重叠空间区域的有效数据结构

发布于 2024-09-07 13:07:07 字数 299 浏览 3 评论 0原文

我正在编写一个游戏,其中大量对象将在平铺的 2D 地图区域上产生“区域效果”。

所需功能:

  • 其中几个区域效果可能会重叠并影响同一个图块
  • 必须能够非常有效地访问任何给定图块的效果列表
  • 区域效果可以具有任意形状,但通常采用“最多 X 个图块”的形式距引起效果的对象的距离”,其中 X 是一个小整数,通常为 1-10
  • 区域效果会频繁变化,例如,当对象移动到地图上的不同位置时
  • 地图可能会很大(例如 1000*1000 块

)数据结构最适合这个?

I'm writing a game where a large number of objects will have "area effects" over a region of a tiled 2D map.

Required features:

  • Several of these area effects may overlap and affect the same tile
  • It must be possible to very efficiently access the list of effects for any given tile
  • The area effects can have arbitrary shapes but will usually be of the form "up to X tiles distance from the object causing the effect" where X is a small integer, typically 1-10
  • The area effects will change frequently, e.g. as objects are moved to different locations on the map
  • Maps could be potentially large (e.g. 1000*1000 tiles)

What data structure would work best for this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

忘你却要生生世世 2024-09-14 13:07:07

如果你确实有很多区域效果同时发生,并且它们将具有任​​意形状,我会这样做:

  • 当创建新效果时,它是
    存储在全局效果列表中
    (不一定是全局变量,
    只是适用于
    整个游戏或当前游戏地图)
  • 它计算哪些图块
    它会影响并存储这些图块的列表,以对抗
  • 每个图块的 效果
    通知新的影响,并且
    将对其的引用存储在
    每个图块列表(在 C++ 中我会使用
    std::vector 为此,与
    连续存储,而不是链接存储
    列表)
  • 结束效果是通过迭代来处理的
    感兴趣的图块并删除对其的引用,然后在销毁它、
  • 移动它或更改其形状之前,通过删除来处理
    如上所述的参考文献,执行变化计算,
    然后在现在受影响的图块中重新附加引用,
  • 您还应该进行仅调试的不变检查,以迭代
    整个地图并验证效果中的图块列表
    与地图中引用它的图块完全匹配。

Providing you really do have a lot of area effects happening simultaneously, and that they will have arbitrary shapes, I'd do it this way:

  • when a new effect is created, it is
    stored in a global list of effects
    (not necessarily a global variable,
    just something that applies to the
    whole game or the current game-map)
  • it calculates which tiles
    it affects, and stores a list of those tiles against the effect
  • each of those tiles is
    notified of the new effect, and
    stores a reference back to it in a
    per-tile list (in C++ I'd use a
    std::vector for this, something with
    contiguous storage, not a linked
    list)
  • ending an effect is handled by iterating through
    the interested tiles and removing references to it, before destroying it
  • moving it, or changing its shape, is handled by removing
    the references as above, performing the change calculations,
    then re-attaching references in the tiles now affected
  • you should also have a debug-only invariant check that iterates through
    your entire map and verifies that the list of tiles in the effect
    exactly matches the tiles in the map that reference it.
鹤舞 2024-09-14 13:07:07

通常这取决于地图的密度。

如果您知道每个图块(或图块的主要部分)至少包含一种效果,您应该使用常规网格 - 简单的二维图块数组。

如果您的地图填充得很弱并且有很多空图块,那么使用一些空间索引 如四叉树、R 树或 BSP 树。

Usually it depends on density of your map.

If you know that every tile (or major part of tiles) contains at least one effect you should use regular grid – simple 2D array of tiles.

If your map is feebly filled and there are a lot of empty tiles it make sense to use some spatial indexes like quad-tree or R-tree or BSP-trees.

神也荒唐 2024-09-14 13:07:07

通常 BSP 树(或 四叉树八叉树) 。

Usually BSP-Trees (or quadtrees or octrees).

橘味果▽酱 2024-09-14 13:07:07

一些不依赖于复杂计算机科学的强力解决方案:

1000 x 1000 并不算太大 - 只是一兆。计算机有演出。你可以有一个二维数组。字节中的每一位都可以是一种“区域类型”。更大的“受影响区域”可能会更大一些。如果您有合理数量的不同类型的区域,您仍然可以使用多字节位掩码。如果这变得荒谬,您可以将数组元素指针指向重叠区域类型对象的列表。但这样你就会失去效率。

您还可以实现稀疏数组 - 使用散列表键(例如,key = 1000*x+y) - 但这要慢很多倍。

当然,如果您不介意用奇特的计算机科学方法进行编码,它们通常会工作得更好!

Some brute force solutions that don't rely on fancy computer science:

1000 x 1000 isn't too large - just a meg. Computers have Gigs. You could have an 2d array. Each bit in the bytes could be a 'type of area'. The 'effected area' that's bigger could be another bit. If you have a reasonable amount of different types of areas you can still use a multi-byte bit mask. If that gets ridiculous you can make the array elements pointers to lists of overlapping area type objects. But then you lose efficiency.

You could also implement a sparse array - using a hashtable key'd off of the coords (e.g., key = 1000*x+y) - but this is many times slower.

If course if you don't mind coding the fancy computer science ways, they usually work much better!

等数载,海棠开 2024-09-14 13:07:07

如果您知道每个区域效果的最大范围,则可以使用您选择的数据结构并存储实际源,仅针对正常的 2D 碰撞测试进行了优化。

然后,在检查图块上的效果时,只需检查(碰撞检测样式,针对您的数据结构进行优化)最大范围内的所有效果源,然后应用定义的测试函数(例如,如果该区域是圆形,则检查如果距离小于常数;如果是正方形,则检查 x 和 y 距离是否均在常数内)。

如果您有少量(<10)效果“场”形状,您甚至可以在其预先计算的最大范围内为每种效果场类型执行独特的碰撞检测。

If you have a known maximum range of each area effect, you could use a data structure of your choosing and store the actual sources, only, that's optimized for normal 2D Collision Testing.

Then, when checking for effects on a tile, simply check (collision detection style, optimized for your data structure) for all effect sources within the maximum range and then applying a defined test function (for example, if the area is a circle, check if the distance is less than a constant; if it's a square, check if the x and y distances are each within a constant).

If you have a small (<10) amount of effect "field" shapes, you can even do a unique collision detection for each effect field type, within their pre-computed maximum range.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文