简单的基于物理的运动

发布于 2024-07-15 13:56:19 字数 847 浏览 6 评论 0原文

我正在开发一个 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;
}

这是一种非常简化的方法,不依赖于质量或实际摩擦力(代码中的摩擦力只是作用于运动的通用力)。 它的效果很好,就像“速度*=摩擦力;” 部分阻止速度超过某个点。 然而,正是这个最高速度及其与加速度和摩擦力的关系让我有点迷失。

我想做的是设置最高速度以及达到它所需的时间,然后用它们来导出加速度和摩擦值。

IE,


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     = ?

I'm working on a 2D game where I'm trying to accelerate an object to a top speed using some basic physics code.

Here's the pseudocode for it:


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;
}

This is a very simplified approach that doesn't rely on mass or actual friction (the in-code friction is just a generic force acting against movement). It works well as the "velocity *= friction;" part keeps the velocity from going past a certain point. However, it's this top speed and its relationship to the acceleration and friction where I'm a bit lost.

What I'd like to do is set a top speed, and the amount of time it takes to reach it, then use them to derive the acceleration and friction values.

i.e.,


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     = ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

小耗子 2024-07-22 13:56:19

我发现这个问题非常有趣,因为我最近做了一些关于阻力运动建模的工作。

第 1 点:您实际上是使用 explicit/forward 更新位置和速度欧拉迭代,其中状态的每个新值应该是旧值的函数。 在这种情况下,您应该首先更新位置,然后更新速度。

第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

然后,您可以使用这两个方程来求解 fa,给定所需的 vmaxtmax


二次阻力:

更新速度的方程将是:

velocity += acceleration - friction*velocity*velocity

表示以下微分方程:

dv/dt = a - f*v^2

使用此积分表<中的第一个条目< /a>,我们可以找到解(假设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)

对于所需的 vmaxtmaxtmax 的第二个方程会告诉您 f 应该是什么,然后您可以将其代入 vmax 等式中以获得 a 的值。


这看起来有点矫枉过正,但这些实际上是一些最简单的阻力建模方法! 任何真正想要查看集成步骤的人都可以给我发一封电子邮件,我会将其发送给您。 他们有点太投入了,无法在这里打字。

另一点:我没有立即意识到这一点,但如果您使用我为v(t)导出的公式,则不再需要更新速度。 如果您只是简单地对静止加速进行建模,并且跟踪自加速开始以来的时间,则代码将类似于:

position += velocity_function(timeSinceStart)

其中“velocity_function”是 v(t) 并且您将不再需要速度变量。 一般来说,这里有一个权衡:计算 v(t) 可能比简单地用迭代方案更新速度(由于指数项)计算成本更高,但保证保持不变稳定且有界。 在某些条件下(例如试图获得非常短的tmax),迭代可能会变得不稳定和爆炸,这是前向欧拉方法的常见问题。 然而,保持对变量的限制(如 0 <f <1)应该可以防止这些不稳定性。

此外,如果您感觉有些受虐狂,您也许可以对 v(t) 公式进行积分,以获得 p(t) 的封闭形式解,因此完全不需要牛顿迭代。 我将把这个留给其他人尝试。 =)

I found this question very interesting since I had recently done some work on modeling projectile motion with drag.

Point 1: You are essentially updating the position and velocity using an explicit/forward Euler iteration where each new value for the states should be a function of the old values. In such a case, you should be updating the position first, then updating the velocity.

Point 2: There are more realistic physics models for the effect of drag friction. One model (suggested by Adam Liss) involves a drag force that is proportional to the velocity (known as Stokes' drag, which generally applies to low velocity situations). The one I previously suggested involves a drag force that is proportional to the square of the velocity (known as quadratic drag, which generally applies to high velocity situations). I'll address each one with regard to how you would deduce formulas for the maximum velocity and the time required to effectively reach the maximum velocity. I'll forego the complete derivations since they are rather involved.


Stokes' drag:

The equation for updating the velocity would be:

velocity += acceleration - friction*velocity

which represents the following differential equation:

dv/dt = a - f*v

Using the first entry in this integral table, we can find the solution (assuming v = 0 at t = 0):

v = (a/f) - (a/f)*exp(-f*t)

The maximum (i.e. terminal) velocity occurs when t >> 0, so that the second term in the equation is very close to zero and:

v_max = a/f

Regarding the time needed to reach the maximum velocity, note that the equation never truly reaches it, but instead asymptotes towards it. However, when the argument of the exponential equals -5, the velocity is around 98% of the maximum velocity, probably close enough to consider it equal. You can then approximate the time to maximum velocity as:

t_max = 5/f

You can then use these two equations to solve for f and a given a desired vmax and tmax.


Quadratic drag:

The equation for updating the velocity would be:

velocity += acceleration - friction*velocity*velocity

which represents the following differential equation:

dv/dt = a - f*v^2

Using the first entry in this integral table, we can find the solution (assuming v = 0 at t = 0):

v = sqrt(a/f)*(exp(2*sqrt(a*f)*t) - 1)/(exp(2*sqrt(a*f)*t) + 1)

The maximum (i.e. terminal) velocity occurs when t >> 0, so that the exponential terms are much greater than 1 and the equation approaches:

v_max = sqrt(a/f)

Regarding the time needed to reach the maximum velocity, note that the equation never truly reaches it, but instead asymptotes towards it. However, when the argument of the exponential equals 5, the velocity is around 99% of the maximum velocity, probably close enough to consider it equal. You can then approximate the time to maximum velocity as:

t_max = 2.5/sqrt(a*f)

which is also equivalent to:

t_max = 2.5/(f*v_max)

For a desired vmax and tmax, the second equation for tmax will tell you what f should be, and then you can plug that in to the equation for vmax to get the value for a.


This seems like a bit of overkill, but these are actually some of the simplest ways to model drag! Anyone who really wants to see the integration steps can shoot me an email and I'll send them to you. They are a bit too involved to type here.

Another Point: I didn't immediately realize this, but the updating of the velocity is not necessary anymore if you instead use the formulas I derived for v(t). If you are simply modeling acceleration from rest, and you are keeping track of the time since the acceleration began, the code would look something like:

position += velocity_function(timeSinceStart)

where "velocity_function" is one of the two formulas for v(t) and you would no longer need a velocity variable. In general, there is a trade-off here: calculating v(t) may be more computationally expensive than simply updating velocity with an iterative scheme (due to the exponential terms), but it is guaranteed to remain stable and bounded. Under certain conditions (like trying to get a very short tmax), the iteration can become unstable and blow-up, a common problem with the forward Euler method. However, maintaining limits on the variables (like 0 < f < 1), should prevent these instabilities.

In addition, if you're feeling somewhat masochistic, you may be able to integrate the formula for v(t) to get a closed form solution for p(t), thus foregoing the need for a Newton iteration altogether. I'll leave this for others to attempt. =)

扬花落满肩 2024-07-22 13:56:19

警告:部分解决方案

如果我们遵循所述物理原理,则不存在最大速度。 从纯粹的物理角度来看,您已将加速度固定为恒定值,这意味着速度始终在增加。

作为替代方案,请考虑作用在物体上的两种力:

  • 恒定的外力 F,它倾向于加速物体,以及
  • 阻力 d,它是与速度成正比,并且往往会减慢速度。

因此迭代 n 时的速度变为:vn = v0 + n F - dvn-1

您要求选择最大速度,v< /em>nmax,发生在迭代 nmax 时。

请注意,该问题受到约束; 也就是说,Fd是相关的,因此您可以任意选择其中一个值,然后计算另一个值。

现在球已经滚动了,有人愿意学习数学吗?

警告:它很丑陋并且涉及幂级数


编辑:为什么第一个方程中的序列 n**F** 会按字面意思出现,除非 n 后面有空格?

Warning: Partial Solution

If we follow the physics as stated, there is no maximum velocity. From a purely physical viewpoint, you've fixed the acceleration at a constant value, which means the velocity is always increasing.

As an alternative, consider the two forces acting on your object:

  • The constant external force, F, that tends to accelerate it, and
  • The force of drag, d, which is proportional to the velocity and tends to slow it down.

So the velocity at iteration n becomes: vn = v0 + n F - dvn-1

You've asked to choose the maximum velocity, vnmax, that occurs at iteration nmax.

Note that the problem is under-constrained; that is, F and d are related, so you can arbitrarily choose a value for one of them, then calculate the other.

Now that the ball's rolling, is anyone willing to pick up the math?

Warning: it's ugly and involves power series!


Edit: Why doe the sequence n**F** in the first equation appear literally unless there's a space after the n?

岁吢 2024-07-22 13:56:19
velocity *= friction;

这并不能阻止速度接近某一点……

随着速度的增加,摩擦力呈指数级增加(不要引用我的话),并且在静止时摩擦力将为 0。 最终,你会达到摩擦力=加速度的点。

所以你想要这样的东西:

velocity += (acceleration - friction);
position += velocity;
friction = a*exp(b*velocity);

你为 a 和 b 选择值。 b 将控制达到最高速度所需的时间,a 将控制摩擦力增加的突然程度。 (再次强调,不要对此进行自己的研究——我是根据 12 年级物理的记忆进行研究的。)

velocity *= friction;

This doesn't prevent the velocity from going about a certain point...

Friction increases exponentially (don't quote me on that) as the velocity increases, and will be 0 at rest. Eventually, you will reach a point where friction = acceleration.

So you want something like this:

velocity += (acceleration - friction);
position += velocity;
friction = a*exp(b*velocity);

Where you pick values for a and b. b will control how long it takes to reach top speed, and a will control how abruptly the friction increases. (Again, don't do your own research on this- I'm going from what I remember from grade 12 physics.)

避讳 2024-07-22 13:56:19

这并没有回答你的问题,但是在模拟中你不应该做的一件事是依赖于固定的帧速率。 计算自上次更新以来的时间,并在方程中使用 delta-T。 比如:

static double lastUpdate=0;
if (lastUpdate!=0) {
  deltaT = time() - lastUpdate;
  velocity += acceleration * deltaT;
  position += velocity * deltaT;
}
lastUpdate = time();

检查一下你是否失去焦点并停止更新也是很好的,当你获得焦点时将lastUpdate设置为0。这样当你回来时你就不会得到一个巨大的deltaT来处理。

This isn't answering your question, but one thing you shouldn't do in simulations like this is depend on a fixed frame rate. Calculate the time since the last update, and use the delta-T in your equations. Something like:

static double lastUpdate=0;
if (lastUpdate!=0) {
  deltaT = time() - lastUpdate;
  velocity += acceleration * deltaT;
  position += velocity * deltaT;
}
lastUpdate = time();

It's also good to check if you lose focus and stop updating, and when you gain focus set lastUpdate to 0. That way you don't get a huge deltaT to process when you get back.

蓝戈者 2024-07-22 13:56:19

如果您想了解使用非常简单的数学可以通过非常简单的物理模型做什么,请查看http://scratch.mit.edu/ - 您可能会得到一些有用的想法和信息 你一定会玩得很开心的。

If you want to see what can be done with very simple physics models using very simple maths, take a look at some of the Scratch projects at http://scratch.mit.edu/ - you may get some useful ideas & you'll certainly have fun.

没有心的人 2024-07-22 13:56:19

这可能不是您想要的,但根据您正在使用的引擎,最好使用其他人构建的引擎,例如 farseer(对于 C#)。
注意 Codeplex 已关闭以进行维护。

This is probably not what you are looking for but depending on what engine you are working on, it might be better to use a engine built by some one else, like farseer(for C#).
Note Codeplex is down for maintenance.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文