处理破坏游戏实体的正确方法


10

想象一下一个游戏世界,其中始终不断地动态加载实体的负载,我可能将其表示为实体的列表,但是如何删除它们呢?

在添加时,我可能会推迟新实体,但可能需要删除容器中的任何位置。为了避免搜索元素以找到要删除的位置,我有哪些选择?

我坚称我可以将实体ID作为其在容器中的位置存储,从而创建直接删除的路径,但是会不会产生某种相互依赖的“混乱”?

我知道正确的方法是类似List.RemoveAt(whereToRemove);。但是,如果只有实体知道何时应该死去怎么办?

还是我只是缺少一些东西,而列表容器会知道对象何时被破坏并减小其自身大小?

Answers:


10

这是您的条件:

  • 删除后,其他对象仍可能取决于您删除的实体。

  • 您只需要实体指定它自己的删除。

不能两者兼有。为什么?因为代码的级别高于实体本身的级别(请参见下面的示例)决定了何时需要使用该实体。因此,只有相同级别的代码才能确定您的实体是否适合删除。

但是,可能发生的情况是该实体可以通过触发更高级别的代码正在侦听的事件来请求将其自己删除。然后,更高级别的请求将删除请求存储在列表中。


示例1:无事件

您正在检查世界中实体之间的碰撞。通常在您的主游戏循环中将其处理得更高,该循环将检查每个实体是否彼此相对。具体地说,在此示例中,当一个实体与另一个实体发生碰撞时,只有该实体的内部逻辑才能确定其遭受了多大的损害以及是否已“过期”。因此,让我们按照碰撞的逻辑流程进行操作,其中您的世界中有四个实体A,B,C和D。A是我们关注的实体。

我们检查A与B的碰撞。存在碰撞。A受到50%的伤害。

我们检查A与C的碰撞。存在碰撞。A受到50%的伤害。因为损害达到0,所以A确定它已经“死亡”。它将自己从列表中删除。

我们检查A是否与D发生冲突。不会发生冲突,但是您永远不会碰到那么远:您会遇到运行时异常,因为您的实体列表在遍历操作期间已被修改。

示例2:带有事件

与以前相同的设置。

我们检查A与B的碰撞。存在碰撞。A受到50%的伤害。

我们检查A与C的碰撞。存在碰撞。A受到50%的伤害。因为损害达到0,所以A确定它已经“死亡”。它会向实体管理代码触发一个事件,说“尽快删除我”。实体管理代码查看作为事件一部分发送的实体引用,并将该引用存储在要删除的实体列表中。

我们检查A与D的碰撞。没有碰撞,检查工作正常。

现在,在当前游戏循环迭代的最后,遍历要删除的实体列表,然后从您的主要实体列表中删除每个实体。


您可以看到这如何完全避免了该问题。您不必使用事件,可以使用信号或其他方法,但是原理是相同的-在可以安全地删除实体之前,不要删除实体。为了保持事物整洁有序,这种方法的另一面是对要添加的实体进行相同的操作-确保您保留对它们的引用,并且仅在下一个游戏循环迭代开始时添加它们。

最后,每次使用主实体列表执行添加/删除操作时,请不要忘记刷新要删除列表和要添加列表。

PS。不要害怕搜寻您的主要清单来进行个别清除。这是实体管理的重要组成部分,甚至庞大的清单也往往非常快速地遍历-毕竟,这就是它们的目标。



0

我想您可以使用smartpointer想法为您处理释放,在这种情况下,无需在代码中保留所有实体的列表。

在某些情况下,您需要一个列表来迭代游戏中的所有对象。此列表可能只是一个链接列表,在其中插入和删除对象将花费O(1)的时间。

甚至可以更快地提高速度,也可以使用一些静态数组(可能是向量)。在这种情况下,您需要跟踪同一向量内的2个链接列表,其中一个将遍历有效对象,而另一个将遍历空闲对象。只要smartpointer标记了某个要删除的位置,您只需删除该指针并将其空间添加到可用空间列表中即可。每当添加一些实体时,只需删除第一个可用空间,然后用实体指针填充它,然后将其添加到有效对象列表中即可。

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.