我正在研究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 = ?
gnovice.. 37
我发现这个问题非常有趣,因为我最近做了一些关于使用阻力建模弹丸运动的工作.
第1点:您实际上是使用显式/前向欧拉迭代更新位置和速度,其中状态的每个新值应该是旧值的函数.在这种情况下,你应该更新所述位置第一,然后更新速度.
要点2:有更真实的物理模型来解决阻力摩擦的影响.一个模型(由Adam Liss建议)涉及与速度成比例的阻力(称为斯托克斯阻力,通常适用于低速情况).我之前提出的那个涉及一个与速度的平方成比例的阻力(称为二次阻力,通常适用于高速情况).关于如何推导出有效达到最大速度所需的最大速度和时间的公式,我将解决每一个问题.我会放弃完整的推导,因为他们相互参与.
斯托克斯的拖累:
更新速度的等式将是:
velocity += acceleration - friction*velocity
它代表以下微分方程:
dv/dt = a - f*v
使用此积分表中的第一个条目,我们可以找到解决方案(假设t = 0时v = 0):
v = (a/f) - (a/f)*exp(-f*t)
当t >> 0时出现最大(即终端)速度,因此等式中的第二项非常接近零并且:
v_max = a/f
关于达到最大速度所需的时间,请注意方程式永远不会真正达到它,而是渐近方向.然而,当指数的参数等于-5时,速度大约是最大速度的98%,可能足够接近以认为它是相等的.然后,您可以将时间近似为最大速度:
t_max = 5/f
然后,您可以使用这两个公式来求解˚F和一个给定期望的VMAX和最高温度.
二次拖动:
更新速度的等式将是:
velocity += acceleration - friction*velocity*velocity
它代表以下微分方程:
dv/dt = a - f*v^2
使用此积分表中的第一个条目,我们可以找到解决方案(假设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和最高温度,对于第二个方程最高温度会告诉你什么˚F应该是,然后你就可以插在公式为VMAX获得了价值一.
这看起来有点矫枉过正,但这些实际上是一些模拟拖拽的最简单方法!任何真正想要查看集成步骤的人都可以给我发电子邮件,我会将它们发送给您.在这里输入它们有点过于牵扯.
另一点:我没有立即意识到这一点,但如果您改为使用我为v(t)推导出的公式,则不再需要更新速度.如果您只是简单地从静止建模加速,并且您正在跟踪自加速开始以来的时间,则代码将类似于:
position += velocity_function(timeSinceStart)
其中"velocity_function"是v(t)的两个公式之一,你不再需要速度变量.一般来说,这里有一个权衡:计算v(t)可能比简单地用迭代方案更新速度(由于指数项)更加计算成本,但是它保证保持稳定和有界.在某些条件下(比如试图获得非常短的tmax),迭代会变得不稳定和爆炸,这是前向欧拉方法的常见问题.但是,保持对变量的限制(如0 < f <1)应该可以防止这些不稳定性.
另外,如果你感觉有点自虐,你可以将v(t)的公式整合到p(t)的闭合形式解,因此完全需要牛顿迭代.我会把这个留给别人去尝试.=)
我发现这个问题非常有趣,因为我最近做了一些关于使用阻力建模弹丸运动的工作.
第1点:您实际上是使用显式/前向欧拉迭代更新位置和速度,其中状态的每个新值应该是旧值的函数.在这种情况下,你应该更新所述位置第一,然后更新速度.
要点2:有更真实的物理模型来解决阻力摩擦的影响.一个模型(由Adam Liss建议)涉及与速度成比例的阻力(称为斯托克斯阻力,通常适用于低速情况).我之前提出的那个涉及一个与速度的平方成比例的阻力(称为二次阻力,通常适用于高速情况).关于如何推导出有效达到最大速度所需的最大速度和时间的公式,我将解决每一个问题.我会放弃完整的推导,因为他们相互参与.
斯托克斯的拖累:
更新速度的等式将是:
velocity += acceleration - friction*velocity
它代表以下微分方程:
dv/dt = a - f*v
使用此积分表中的第一个条目,我们可以找到解决方案(假设t = 0时v = 0):
v = (a/f) - (a/f)*exp(-f*t)
当t >> 0时出现最大(即终端)速度,因此等式中的第二项非常接近零并且:
v_max = a/f
关于达到最大速度所需的时间,请注意方程式永远不会真正达到它,而是渐近方向.然而,当指数的参数等于-5时,速度大约是最大速度的98%,可能足够接近以认为它是相等的.然后,您可以将时间近似为最大速度:
t_max = 5/f
然后,您可以使用这两个公式来求解˚F和一个给定期望的VMAX和最高温度.
二次拖动:
更新速度的等式将是:
velocity += acceleration - friction*velocity*velocity
它代表以下微分方程:
dv/dt = a - f*v^2
使用此积分表中的第一个条目,我们可以找到解决方案(假设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和最高温度,对于第二个方程最高温度会告诉你什么˚F应该是,然后你就可以插在公式为VMAX获得了价值一.
这看起来有点矫枉过正,但这些实际上是一些模拟拖拽的最简单方法!任何真正想要查看集成步骤的人都可以给我发电子邮件,我会将它们发送给您.在这里输入它们有点过于牵扯.
另一点:我没有立即意识到这一点,但如果您改为使用我为v(t)推导出的公式,则不再需要更新速度.如果您只是简单地从静止建模加速,并且您正在跟踪自加速开始以来的时间,则代码将类似于:
position += velocity_function(timeSinceStart)
其中"velocity_function"是v(t)的两个公式之一,你不再需要速度变量.一般来说,这里有一个权衡:计算v(t)可能比简单地用迭代方案更新速度(由于指数项)更加计算成本,但是它保证保持稳定和有界.在某些条件下(比如试图获得非常短的tmax),迭代会变得不稳定和爆炸,这是前向欧拉方法的常见问题.但是,保持对变量的限制(如0 < f <1)应该可以防止这些不稳定性.
另外,如果你感觉有点自虐,你可以将v(t)的公式整合到p(t)的闭合形式解,因此完全需要牛顿迭代.我会把这个留给别人去尝试.=)