对可以互相看到的单位进行分组的最快方法?


12

在我正在使用的2D游戏中,游戏引擎可以为我提供每个单位在其视图范围内的其他单位的列表。

我想知道是否存在一种将单元划分为组的既定算法,其中每个组将由彼此“连接”(甚至通过其他单元)的所有那些单元定义。

一个例子可能有助于更好地理解这个问题(E =敌人,O =自己的单位)。首先,我将从游戏引擎获取的数据:

E1 can see E2, E3, O5
E2 can see E1
E3 can see E1
E4 can see O5
E5 can see O2
E6 can see E7, O9, O1
E7 can see E6
O1 can see E6
O2 can see O5, E5
O5 can see E1, E4, O2
O9 can see E6

然后,我应该按以下方式计算组:

G1 = E1, E2, E3, E4, E5, O2, O5
G2 = O1, O9, E6, E7

可以安全地假定该视场具有可交换属性:[如果A看到B,则B看到A]。

需要澄清的是:我已经编写了一个简单的实现,该实现在游戏引擎信息的每一行上循环,但是从它的外观来看,似乎已经足够深入地研究它并拥有各种已建立的算法(也许可以通过通过一些树状结构?)。我的问题是我找不到描述返回有用的Google匹配的问题的方法。

预先感谢您的帮助!


1
我认为这个问题很笼统,可以在stackoverflow甚至是数学(集合论?)中得到更好的答案。我的观点不是特定于游戏开发的。
Tor Valamo 2011年

1
@Tor-可能是正确的,但是我们知道它是针对游戏的,这一事实可能使人们可以针对问题更具体地制定答案。
罗伯特·弗雷泽

我认为您可以通过旋转空间哈希和可见性地图来做一些聪明的事情-我只需要考虑一下。
乔纳森·迪金森

Answers:


7

如果您的“可以看到”关系是对称的,那么“ A可以看到B”表示“ B可以看到A”,则您要计算的组是“可以看到”关系定义的图的连接组件。正如其他人指出的那样,有一些简单的算法可以计算这些算法,例如:

while ungrouped units remain:
    let u = arbitrary ungrouped unit
    let g = new group
    let s = temporary stack
    assign u to g
    push u onto s
    while s is not empty:
        let v = topmost unit in s
        remove v from s
        for each unit w that v can see:
            if w is ungrouped:
                assign w to g
                push w onto s
            end if
        end for
    end while
 end while

(可以有效地实现“添加新元素”和“删除并返回某些元素”操作的队列或任何其他集合来代替s上面的堆栈。)

如果你的“能看到”关系是不是对称的,你需要决定是否要您的组是连接的部件。对于弱连接的组件,上述算法将按原样运行,只是该行for each unit w that v can see应替换为for each unit w that can see v, or that v can see。对于紧密连接的组件,您可以使用链接的Wikipedia页面上提到的一种算法(KosarajuTarjanGabow)。

对于非对称关系,您可能还需要计算该关系或其紧密连接的组件的传递闭合。为此,您可以使用Floyd-Warshall算法有关更多信息,请参见SO上的答案


附言 正如我链接到上述注释的Wikipedia文章一样,随着可见性关系的变化而动态更新组可能更为有效。我不熟悉Wikipedia上提到的advanced(?)算法,但不难将它们拼凑起来,至少每次都要从头开始重新计算组。

其中一半很容易:如果不同组中的两个单位在它们之间获得了视线,则将这些组合并。处理彼此视而不见的单位会比较棘手。一个简单但可能不是最佳的解决方案是,只要发生这种情况,就对受影响的组中的单元重新运行分组算法。如果可见性更改一次发生一对,您可以对此进行一些优化:

  • 如果一个单位只能看到另一个单位而看不见它,只需将其从其先前的组中删除,然后将其分配给新的组即可。
  • 否则,您可以从一个受影响的单位开始,然后在可见性图上对另一个单位进行A *搜索(例如,使用直线距离作为试探法)。如果找到它,该小组就没有破裂。如果您不这样做,则搜索访问的单位组将形成新的组。
  • 如果确实分裂,您可以尝试猜测两个单元中的哪个单元更可能属于组的较小部分,然后从该单元开始搜索。一种可能性是始终从可以直接看到较少其他单位的单位开始。

4

您拥有的是连接图。通常,将连接的节点(即字符)分组在一起的最佳方法是使用图搜索算法。深度优先,宽度优先,以较早者为准。您要做的只是建立一个列表,列出所有其他节点可访问的节点。只要您的图形是无向的(如果A对B可见,那么B对A可见),就可以正常工作。

在某些情况下,可能会有一些算法可以对此进行改进。例如,如果有时角色不动(并且地形也不动,所以不动的角色仍然可见),则可以选择不再次测试它们以更新其连通性图。

但总的来说,您将不得不重新测试每帧的可见性。奇怪的是,这将比遍历图来查找可见性组的速度慢。


3
只需添加一个技术术语:您要查找的是图的连接组件,而标准算法是:(1)将所有节点放入列表中,(2)选择一个节点,(3)查找使用BFS / DFS的所有已连接节点,(4)从列表中删除所有找到的节点,(5)重复操作,直到没有剩余的节点为止。
内森·里德

3

似乎是一个标准的图形连接问题。可能有某种算法可以解决这个问题,它可能如下所示:

remaining units = all units
for each unit in remaining units:
    current group = create a new group
    add this unit to current group
    for each unit visible to this unit:
        if unit is in a group already:
            merge current group into that existing group
            set current group as that existing group
        else:
            remove that unit from remaining units
            add that unit to current group

我希望可以通过树来实现这一点,例如分层聚类,但是我怀疑这样做是否会更快-树通常是O(log N),而我上面给出的大多数检查都可以实现为O(1) 。


出于兴趣,分层聚类方法有点像这样:为每个单元创建一个组。然后,对于可以互相看见的每一对单元,如果它们位于不同的组中,则将这些组合并为一个,然后丢弃另一个。
Kylotan

这就是我在OP中所说的天真的实现。很高兴知道它可能没有我当时想象的那么糟糕!:)
mac

像树一样将其与路径压缩一起使用联合集。这不是很幼稚,实际上是最佳的。
彼得·泰勒

2

我同意在此方面存在图连通性问题的所有其他人的观点,但是让我指出,您需要的是从所有相关单位生成的Delaunay三角剖分图。这样做是为了确保在生成的图形中仅连接彼此最接近的单元。您将发现以任何其他方式执行此操作都非常具有挑战性,因为图形交叉(非平面性)将导致彼此之间相距太远的单元无法正确地连接到图形中。

仅当您使用连续空间(如大多数自由移动式FPS)时,以上内容才适用;但是,如果您已有单位在其上移动的基础网格(平面图),则可以使用该网格来评估连通性。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.