我正在开发2D游戏,试图使用一些基本的物理代码将物体加速到最高速度。
这是它的伪代码:
const float acceleration = 0.02f;
const float friction = 0.8f; // value is always 0.0..1.0
float velocity = 0;
float position = 0;
move()
{
velocity += acceleration;
velocity *= friction;
position += velocity;
}
这是一种非常简化的方法,不依赖于质量摩擦或实际摩擦(代码内摩擦只是一种抵抗运动的通用力)。它与“速度* =摩擦力”一样有效。部分可防止速度超过特定点。但是,正是这个最高速度及其与加速度和摩擦的关系让我有些迷失。
我想做的是设置最高速度,以及达到最高速度所需的时间,然后使用它们来得出加速度和摩擦值。
即
const float max_velocity = 2.0;
const int ticks; = 120; // If my game runs at 60 FPS, I'd like a
// moving object to reach max_velocity in
// exactly 2 seconds.
const float acceleration = ?
const float friction = ?
最佳答案
我发现这个问题非常有趣,因为我最近做了一些有关拖动阻力的弹丸运动建模的工作。
要点1:实际上,您正在使用explicit/forward Euler iteration更新位置和速度,其中状态的每个新值都应该是旧值的函数。在这种情况下,您应该先更新位置,然后再更新速度。
第2点: the effect of drag friction有更多逼真的物理模型。一种模型(由Adam Liss建议)涉及与速度成比例的阻力(称为斯托克斯阻力,通常适用于低速情况)。我先前建议的牵伸力与速度的平方成正比(称为二次阻力,通常适用于高速情况)。关于如何推导最大速度的公式以及有效达到最大速度所需的时间,我将逐一介绍。我将放弃全部推导,因为它们涉及很多。
Stokes' drag:
更新速度的公式为:
velocity += acceleration - friction*velocity
它表示以下微分方程:
dv/dt = a - f*v
使用this integral table中的第一个条目,我们可以找到解决方案(假设在t = 0时v = 0):
v = (a/f) - (a/f)*exp(-f*t)
最大速度(即终端速度)在t >> 0时发生,因此方程式中的第二项非常接近零,并且:
v_max = a/f
关于达到最大速度所需的时间,请注意,方程式从未真正达到它,而是逐渐向它渐近。但是,当指数的自变量等于-5时,速度约为最大速度的98%,可能足够接近以使其相等。然后,您可以将时间估计为最大速度,如下所示:
t_max = 5/f
然后,可以根据给定的所需 vmax 和 tmax 来使用这两个方程式来求解和。
Quadratic drag:
更新速度的公式为:
velocity += acceleration - friction*velocity*velocity
它表示以下微分方程:
dv/dt = a - f*v^2
使用this integral table中的第一个条目,我们可以找到解决方案(假设在t = 0时v = 0):
v = sqrt(a/f)*(exp(2*sqrt(a*f)*t) - 1)/(exp(2*sqrt(a*f)*t) + 1)
最大(即终端)速度在t >> 0时出现,因此指数项远大于1并且方程式接近:
v_max = sqrt(a/f)
关于达到最大速度所需的时间,请注意,方程式从未真正达到它,而是逐渐向它渐近。但是,当指数的自变量等于5时,速度约为最大速度的99%,可能足够接近以使其相等。然后,您可以将时间估计为最大速度,如下所示:
t_max = 2.5/sqrt(a*f)
这也等效于:
t_max = 2.5/(f*v_max)
对于所需的 vmax 和 tmax , tmax 的第二个等式将告诉您 f 应该是什么,然后您可以将其插入 vmax 的等式中以获取值。
这似乎有些矫kill过正,但实际上它们是拖动模型的最简单方法!任何真正想要查看集成步骤的人都可以向我发送电子邮件,然后将它们发送给您。他们太累了,无法在此处键入。
另一点:我没有立即意识到这一点,但是如果您改为使用我为 v(t)导出的公式,就不再需要更新速度。如果您只是简单地模拟静止时的加速度,并且要跟踪加速度开始以来的时间,则代码应类似于:
position += velocity_function(timeSinceStart)
其中“velocity_function”是 v(t)的两个公式之一,您将不再需要速度变量。通常,这里需要权衡取舍:计算 v(t)可能比使用迭代方案(由于指数项)简单地更新速度要高得多,但是可以保证保持稳定和有界。在某些条件下(例如,尝试获得非常短的 tmax ),迭代可能变得不稳定和爆炸,这是正向Euler方法的常见问题。但是,保持变量的限制(例如0 < f
此外,如果您感到受虐狂,则可以集成 v(t)的公式,以获得 p(t)的封闭式解决方案,从而完全不需要进行牛顿迭代。我将其留给他人尝试。 =)