模拟虚拟世界:连续或离散的步骤?

时间:2012-08-22 20:43:48

标签: javascript performance node.js simulation

我正在制作类似于Polyworld的东西,这意味着我将模拟虚拟世界,小爬行动物在那里奔跑,吃饭和进化。我用Node.js制作它,我计划使用物理和神经网络,但我不确定更新世界的最佳方法是什么,更具体地说,如果更新函数接收delta时间作为参数,或者每次做同样的事情,独立于他们最后一次被召唤的时间?这两种方式有什么好处?

修改 我反对不断更新的一点是,我想实现某种间隔,例如,食物块产生的每20个模拟秒。如果dt不同于1(或1的一小部分),这将永远不会正常工作。

然后,再次,如果我使用离散更新,更新不关心已经过了多少时间,我将无法“减慢时间”。当我在强大的服务器上工作并在浏览器中渲染时,我认为更新会经常发生,我需要一种减慢时间而不影响模拟的方法,所以我可以看到发生了什么。

6 个答案:

答案 0 :(得分:2)

每次调用更新功能时,您都可以计算自动画启动以来经过的时间。然后你将这段时间传递给更新功能,即使帧在第20秒没有精确更新,你也可以根据实际时间进行所有计算。

示例:汽车在20秒开始运动,速度为3units / s。假设更新功能在以下时间触发:...,19.35s,20.67s,...... 当你在19.35s更新时,你知道它应该没有被移动,所以没有任何反应,但是当时间值20.67s触发更新功能时,你知道汽车已经移动了0.67秒,因此你计算它的位置(时间*速度)0.67 * 3 = 2.01并进行所有其他计算/绘制,就好像它已经移动了2.01个单位一样。这样你就不必担心没有精确的时间测量,滞后,更新功能需要比平时更多的时间等等。

答案 1 :(得分:2)

如果您没有多个代理(每个代理都有自己的线程),必须进行协作,并且您不必处理流程问题的同步/事件,我建议您使用连续模拟。使用固定时间步骤并在每个步骤中更改您的世界状态。 每个世界都使用如下函数改变其状态:

newState = f(oldState,deltaSteps)

关于您提到的速度问题,请勿直接将迭代映射到时间。定义一个中间时间单位(步骤),它们将此单位时间映射到ms,迭代或您喜欢的内容。因此,如果要增加或降低模拟速度,只需更改用于逐步转换的因子。如果你需要改变速度,只需改变你的常数。

查看此page,了解有关模拟技术的一些见解。

答案 2 :(得分:1)

我认为你不会超过某个频率(如50赫兹)。这会浪费CPU时间在不必要的精度上。

如果用户的设备无法提供更新率,则为

  1. 保持相同的物理频率并降低挂钟速度
  2. 用更高的ΔT
  3. 降低物理频率 如果频率仍高于20Hz,我会选择2。如果它变低,你可能应该切换到策略1以保持精确度。

    因此,您可能需要基于deltaT的解决方案,以便调整更新频率。

答案 3 :(得分:1)

您的更新功能应该在每个步骤执行相同的操作。

这两种方法都有缺点,但是在模拟群体中的多对多交互时,传递表示自上次更新以来经过的时间的增量变得难以管理。这是因为预测交互发生的时间点(增量)是很费时的。如果错过了这些时间点,则模拟不准确。

在每个时间步骤更新所有元素的方法的缺点是它将完成不需要的工作。但是,这种不必要的工作成本可能会低于准确预测需要评估哪些时间点所需的工作量,特别是考虑到复杂的交互环境。

答案 4 :(得分:0)

我认为你会希望你的动画是连续的并且基于一些经过的时间或时钟(你可能能够加速或减速)。所以你想要一些基于delta的更新函数。

但这并不意味着您不能使用setInterval来生成食物块。它也并不意味着其他一切都需要或应该基于该三角洲。

例如,您可以在您的位置更新后检查彼此接近的生物或生育所需的任何条件,然后生成后代作为不依赖于当前时钟的离散步骤。你可能想记录发生这种情况的时钟。

答案 5 :(得分:-1)

我会用恒定的时间步长做到这一点。它更容易编码。每个更新功能根据环境执行一步。您不必每步都更新浏览器。您可以计算10或100个步骤,然后将结果发送到浏览器。

这种方式会更准确。许多小的简单步骤比delta时间取决于函数(噩梦)更容易编码。

如果您使用可变时间步骤。当时间步长很大时,您可能会遇到蚂蚁在t0处的A点和t + delta处的B点的情况。你首先更新蚂蚁,它在B点结束。你更新A和B之间的食物重生点,它应该在t0 + 1/3 delta处重生。蚂蚁没有看到食物就过去了。模拟是错误的。

您可能需要的其他事项:

  • 要真正准确,你必须检查段之间的碰撞[先前位置 - 新位置]而不是点。否则蚂蚁可能会在没有碰撞的情况下穿过它们。检查物理引擎。
  • 避免将所有对象发送到您的浏览器。使用八叉树或四叉树快速确定数据的子集与浏览器显示的区域相对应。

在Node.js中做这个的奇怪选择,我会使用Java或真正的oop语言。

你会在游戏开发者论坛上找到很多有用的帮助。