我试图根据Reynolds经典Boids论文创建一个具有到达行为的自主代理,更具体地说是Dan Shiffman在natureofcode.com上的实现。这两种方法都易于理解(和工作),但它们都采用固定的标称更新步骤,而不是查询自上一次帧更新以来的经过时间,并在Euler积分步骤中应用此时间增量。即他们建议简单:
//pseudocode
acceleration.add(force);
velocity.add(acceleration);
location.add(velocity);
然而,如果我想要包含时间增量,那么各种物理学论文建议我应该将其重写为:
//pseudocode
delta = timeElpasedSinceLastFrameUpdate();
acceleration.add(force);
deltaAcceleration = acceleration.mult(delta);
velocity.add(deltaAcceleration );
deltaVelocity = velocity.mult(delta);
location.add(deltaVelocity);
这一直有效,直到我尝试实现转向行为,特别是到达行为。有关该方法的参考,请参见此处链接中的示例6.2:
Nature of Code Steering Behaviours
有问题的步骤(伪代码)是steeringForce = desired - velocity;
没有时间增量应用' - 速度'转向力正确地抵消了当前保持的速度矢量,并使目标在到达目的地处减速停止。
应用时间增量但是当我将加速度乘以增量时,转向力由分数时间增量有效地调节,因此不会对累积速度施加足够的减速以使物体及时停止得到振荡行为。
我可以修复'这不是通过时间增量乘以累积的力(即加速度),但这看起来并不正确。
所以,我的问题:
如何生成抵达行为的steeringForce以考虑变量delta时间?
感谢任何帮助!
答案 0 :(得分:1)
steeringForce
,而只是修改速度。
我们想要一个这样的矢量
desired_velocity = velocity + correction
这与您之前写的相同(但对于'steeringForce'):
correction = desired_velocity - velocity
通过velocity + correction
,您将立即达到所需的速度,这通常不是您想要的速度,因为它会导致非常不稳定的运动。相反,您可以将校正钳位到某个值,这将导致更平滑的运动:
len = length(correction)
corr_length = len > max_correction ? max_correction : len
correction = correction/len*corr_length
现在你可以做到
velocity += correction
这应该导致一些动态的运动,没有振荡。
明确的时间步长积分(例如你的前向欧拉)通常写为
new_acceleration = old_acceleration + (delta_t/mass)*force
^^ note
同样地,
new_velocity = old_velocity + delta_t*acceleration
new_position = old_position + delta_t*velocity
所以要回答你的问题,你需要在积累之前乘以时间步骤:
acceleration.add(force.mult(delta_t/mass));
velocity.add(acceleration.mult(delta_t));
location.add(velocity.mult(delta_t));