如何实现带有时间增量的到达行为?
How to implement arriving behavior with time delta?
我正在尝试根据 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);
这也有效,直到我尝试实现转向行为,特别是到达行为。有关该方法的参考,请参见此处 link 中的示例 6.2:
Nature of Code Steering Behaviours
有问题的步骤(在伪代码中)是 steeringForce = desired - velocity;
如果不应用时间增量,“-速度”对转向力的贡献会正确抵消当前保持的速度矢量,并使物体在到达目的地减速停止。
然而,在应用时间增量时,当我将加速度乘以增量时,steeringForce 会被分数时间增量有效地缓和,因此不会对累积速度应用足够的减速以使物体及时停止并且我获得振荡行为。
我可以 'fix' 通过不将累积的力(即加速度)乘以时间增量来做到这一点,但这似乎不正确。
那么,我的问题是:
应如何生成到达行为的 steeringForce 以考虑可变增量时间?
感谢任何帮助!
编辑:我错过了你问题的主要部分。有很多方法可以获得您想要的结果,但它们通过不同的方式实现。我能想到的最简单的方法可能是暂时跳过 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));
我正在尝试根据 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);
这也有效,直到我尝试实现转向行为,特别是到达行为。有关该方法的参考,请参见此处 link 中的示例 6.2:
Nature of Code Steering Behaviours
有问题的步骤(在伪代码中)是 steeringForce = desired - velocity;
如果不应用时间增量,“-速度”对转向力的贡献会正确抵消当前保持的速度矢量,并使物体在到达目的地减速停止。
然而,在应用时间增量时,当我将加速度乘以增量时,steeringForce 会被分数时间增量有效地缓和,因此不会对累积速度应用足够的减速以使物体及时停止并且我获得振荡行为。
我可以 'fix' 通过不将累积的力(即加速度)乘以时间增量来做到这一点,但这似乎不正确。
那么,我的问题是:
应如何生成到达行为的 steeringForce 以考虑可变增量时间?
感谢任何帮助!
编辑:我错过了你问题的主要部分。有很多方法可以获得您想要的结果,但它们通过不同的方式实现。我能想到的最简单的方法可能是暂时跳过 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));