5

情况:模拟环境中有几个实体,它们有一个人为的时间概念,称为“滴答声”,与实时没有联系。每个实体轮流移动,但有些比其他实体更快。这以延迟表示,以滴答为单位。所以实体 A 可能有 10 的延迟,而 B 可能有 25 的延迟。在这种情况下,轮流顺序将变为:

AABAA

我想知道使用什么数据结构。起初我自动想到“优先队列”,但延迟与“当前时间”相关,这使事情变得复杂。此外,会有更大延迟的实体,并且程序将运行数百万个滴答并不是不可预见的。当延迟本身保持相对较小且不增加时,内部计数器越来越高似乎很愚蠢。

那么你将如何解决这个问题?

4

5 回答 5

4

您将实体存储在堆中,并按剩余等待时间对它们进行分组。接下来要移动的实体组将位于堆的顶部。您只需更新这些实体。当它们的剩余等待时间降至 0 时,您将它们从堆中删除。将下一组实体排在堆的顶部,同时将它们的等待时间减少上一次移动之前刚刚过去的时间。

例如:

您的堆有 3 个节点(A、B 和 C),顶部是节点 A,其中两个实体都剩余 5 个刻度。childern 分别剩余 10 和 12 个刻度。

  • 在时间 t=5 时,您移动节点 A 中存储的所有实体
  • 从堆中删除 A
  • B 移动到堆的顶部,剩余 10-5 = 5 个刻度,然后
  • 重复。
于 2010-03-13T04:41:10.547 回答
1

根据您的描述,在我看来,“下一步是什么?”的概念。比“距离下一个行动还有多长时间?”更重要。在这种情况下,按“下一个”或剩余的最低滴答数到最高对您的队列进行排序。当然,插入以适当的顺序输入,更改的条目(“加速”咒语)从队列中删除,更改,然后适当地重新输入。

然后,您只需将下一个作业从队列中弹出。无论剩余多少滴答声都必须是“经过的时间”。通过队列,将每个条目的剩余滴答数字段减去您刚刚发现的滴答数。

这样做的好处是可以跟踪剩余时间的概念,但也不必触发事件或执行任何其他代码,以便在没有采取任何操作时经过。您可以负担得起,因为与实时无关。只有“下一步是什么?”和“到达那里需要多长时间?”。

于 2010-03-13T04:21:13.550 回答
0

选项#1:轮询

我可能会构建一个控制器,它可以发现所有不同实体的延迟并为每个实体维护一个剩余滴答声。控制器将循环通过滴答声,并且在每个滴答声中,它会减少游戏中所有实体的剩余滴答声。

一旦实体的剩余刻度值达到零,您就知道该轮到它们了,要么由处理刻度的心跳方法控制,要么由您调用的方法控制。

选项 #2 事件

像 UI 范例一样思考,界面不会不断轮询按钮以查看它何时被单击。而是让按钮在通过事件单击时通知 UI。让您的实体(或 EntityBattleContext)在准备好时触发一个事件。您将不得不以某种方式处理您的游戏时间,因为它根本不是基于现实世界的时间,您可能需要让所有实体侦听 GameTick 事件,并且当它们接收到该事件时更新它们的内部 TicksRemaining 变量。

在遵循事件驱动路线之前,请确保轮询路线不起作用。记住基本规则总是稍后优化,因为更多时候不是你不需要优化。

于 2010-03-13T04:15:01.647 回答
0

如果我们假设您的实体正在观察或观察模拟时间,那么它们每个都可以实现一个接口,使它们能够跟踪ticks left并提供一种方法来获取特定实体还剩下多少滴答声。在每个滴答声中,实体将其减ticks left1。

然后,您可以保留这些实体的排序集合队列(设置,因为每个实体将只在队列中一次),基于 排序get ticks left,因此第 0 个实体是下一个移动的实体,第 N 个实体是“最慢的” .

当实体的get ticks left方法为0时,从排序集中移除,ticks left定时器复位,重新插入排序集中。

于 2010-03-13T04:17:48.650 回答
0

看看Java的DelayQueue是如何实现的。

于 2010-03-13T07:07:18.537 回答