更快的2D碰撞检测


13

最近,我一直在研究快节奏的2D射击游戏,但遇到了一个大问题。碰撞检测。当然可以,但是速度很慢。我的目标是:屏幕上有很多敌人,并且让他们彼此不接触。所有的敌人都在追逐玩家实体。他们中大多数人或多或少都拥有相同的速度,所以迟早他们都在追逐玩家时占据了相同的空间。这确实降低了娱乐性,因为对于玩家而言,似乎您只被一个敌人追赶。为了防止它们占据相同的空间,我添加了一个碰撞检测(一种非常基本的2D检测,这是我所知道的唯一方法)。

Enemy class update method
    Loop through all enemies (continue; if the loop points at this object)
        If enemy object intersects with this object
            Push enemy object away from this enemy object

这很好。只要我只有<200个敌方实体。当我靠近300-350个敌方实体时,我的帧频开始大幅下降。首先,我认为渲染效果很差,因此我取消了他们的平局。这一点都没有帮助,所以我当然意识到这是更新方法。它们更新方法中唯一重要的部分是每个敌人循环通过每个敌人的部分。当我接近300个敌人时,游戏会执行90000(300x300)步发信号。我的我的〜

我确信必须有另一种方法来解决这种冲突检测。虽然我不知道如何。我发现的页面涉及如何实际执行两个对象之间的碰撞或如何检查对象与图块之间的碰撞。我已经知道这两件事。

tl; dr?如何在实体的LOTS之间进行冲突检测?

快速编辑:如果有任何帮助,我正在使用C#XNA。


我想知道您是如何首先达到90K的。我的扼流圈为20K(尽管我正在做完整的SAT MTV检测)。但我绕过所有敌人似乎是唯一可能的事情。但是,您需要做的就是检查它们是否已经被检查过,因为如果您按照您的意愿去做,那么每个人都会接受两次测试。
妄想逻辑


@MarkusvonBroady已链接的问题中有一个很好的答案。
Cypher'Nov

Answers:


11

您已经直接解决了问题,正在让每个实体都与其他每个实体进行检查。您需要的是某种类型的“详细程度”系统(它是非常简单的场景图,您只是将其用于渲染以外的其他用途:)),在这里最好选择可能的碰撞候选对象。

我通常为这样的系统做三个集合。在谈论目标实体的数量时,您甚至可能需要使用完整的场景图,因为跟踪数据(每个实体3个列表,每个其他实体都有一个条目)可以快速获取控制。

基本上,尽管您有三个列表。第一个应该是一个很小的实体列表,您将在每个框架中检查交互情况。您之所以确定是因为它们在所讨论实体的X范围内。如前所述,该列表的要点是包含可以与该框架中的另一个合理碰撞的每个实体。

下一个列表将位于缓冲区范围内,可以毫不费力地移入实体范围。我们仅出于争论目的将其称为X * 1.5。这是一个按时间划分的列表,在该列表中,您每帧只会更新少数几个,但要确保它们以足够快的速度通过它们,以保持工作顺利进行。

第三个列表是“其他所有”列表,它是一种值得避免的方法(扫描整个实体列表,然后在进行下一步操作之前检查其是否在其他列表之一中?),具体取决于列表大小可能会起作用,或者可能使情况变得更糟。)此列表中的对象得到最少的检查,因为肯定要花更多的帧才能放入其他两个列表之一。

要保持这种状态,您还需要做的是在进行碰撞测试时,确保更新实体所在的列表。移出范围的实体应降级,移近范围的实体应升级为实体。更积极地检查清单。

假设您将事情保持足够简单,这将满足您的需求。如果您可以获取现有渲染场景图的额外信息(假设您有一个),则可以查询它以获取合理范围内的实体列表,该范围甚至会更好,因为这是场景图的重点无论如何(根据职位快速访问相关数据列表)。这将可能需要做更多的工作,并且您应该始终考虑需要做的事与实际应该做的事。

希望这可以帮助。


1
这是一个模糊的答案。我们可以接受错过一些碰撞吗?更简单的是,使用一种将为您进行表面分区的数据结构,例如我在这里谈论的四叉树。甚至四叉树也需要进行一些微调,以避免开销,因此我无法想象您谈论的“解决方案”的复杂性。基本编程规则:仅使用正确的数据结构。
GameAlchemist 2012年

@VincentPiel场景图不比四叉树更复杂。
Cypher 2012年

@James:显然更复杂。如果您不介意掌握QuadTree的全部速度,则可以在网上获得QuadTree库,并使其在几个小时内完美运行。没问题,例如:我要在第一个列表中放置什么,第二个,第三个列表中,我如何决定将一个实体放置在另一个列表中...而不会发生碰撞。有车的时候为什么要骑自行车?
GameAlchemist 2012年

@VincentPiel我想你的意思是@对Cypher而不是我的评论。任何四叉树只是场景图的一种,您必须记住您以每秒X帧的速度运行。如果您注意到错过的碰撞,则需要调整范围阈值以更好地平衡情况。我的解决方案只是一种非常简单的方法,即确保只检查每帧有可能发生冲突的事物,然后对其余的事物进行背景/有限更新,以查看它们是否符合更高的优先级。
詹姆斯

6

您必须使用排序的数据结构来处理冲突,因此您可以拥有n * log(n)次而不是可怕的n ^ 2。如您所知,n * log(n)几乎是线性的。一个(经典)示例是四叉树,这里有一个非常简单且编写得很好的教程,其中包含图形和代码(Java):

http://gamedev.tutsplus.com/tutorials/implementation/quick-tip-use-quadtrees-to-detect-likely-collisions-in-2d-space/

Rq:很容易找到任何语言的QuadTree的实现。尽管如此,您仍必须考虑树的正确“粒度”,并且树的大小越大,我们拥有的实体就越不适合节点内。
Rq 2:由于空间划分仅用于冲突检测,因此您可以自由地随意划分空间。例如,我不会将其划分为四个部分,而是将当前关卡实体的重心用作新划分的中心。1)算法仍然是n * log(n),2)您失去了从树中“重建”场景的可能性-但您不在乎-3)您的树更加平衡,开销更少。
Rq3:一旦有了树,屏幕和实体之间的“碰撞”就会给您...可见的实体!在更像log(n)的时代,那么如果n大,为什么不呢?(最坏的情况显然是这种方法的时间为n。)


是的,四叉树实际上只是一种场景图。我只是一直假设这里的人想自己写东西,而不使用别人的库,在这种情况下为什么要停在四叉树上,而只是找到一个完整的碰撞库。
詹姆斯

0

二进制空间分区树,四叉树,八叉树(用于3D)是可能的树,您可以在每个更新调用中为要应用碰撞的每个对象生成(或维护,如果您有野心)。


3
这更适合作为评论。考虑增加更多答案。

0

当谈论四叉树或八叉树时,我很天真。但是我认为这种方法应该可以做到:

您将需要修改播放器的结构/类。添加指向其他播放器结构的指针数组/向量。

每秒钟检查两个玩家之间的距离。如果它太低以至于可能在1秒钟内到达,则将该玩家的指针添加到当前玩家的碰撞数组中。

现在,仅检查彼此列表中玩家之间的碰撞。

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.