翻译文章,原文看这里
该文章中的一些信息将会帮助你模拟一些跳跃和移动。
这个文档的目的是理解自然中的物理现象并将他们应用到你的游戏当中。这不会给你的程序有什么最优化的方案,因为这是你的事情!但是你可以理解这到底是怎么回事。
基本概念
为了保证我所讲的东西的一致性,有一些关键的术语我需要定义一下:
距离:运动的总的长度。
位移:起始点和终点的差值。
速率:移动的距离除以移动时间。
速度:运动的方向和运动的速率。
加速度:移动的速度除以移动的时间。
注意:位移,速度,和加速度是都是向量。(具有方向和大小的量)。
缩写:
a:加速度
M:质量
s:位移
s0:初始点。
t:时间
v:速度
v0:初始速度
单位:
m:米(长度单位)
m/s:米每秒(速度单位)
m/s^2:米每秒的平方(加速度单位)
N:牛顿(重力单位)
s:秒(时间单位)
概念:
想象一下一个太空船以1000m/s的速度穿越太空。它深陷一个没有任何东西的星际空间中。有什么力作用于它呢?回答是:什么都没有!
它会永远以1000m/s的速度飞行下去。
对象改变速度的唯一原因是有力作用于它。你会问那是什么力呢?是一个外部的推力或者拉力。力也是一个向量。它具有大小和方向。现在就有一个重力作用于你:它拉动你到地球的中心。
同样的,一个对象改变了位置就是因为它具有一些速度。
假设上帝之手开始推动那个飞船,有一个力施加到了飞船上,任何力的施加都会引发加速度。速度开始增长。如果上帝没有停止推动,不久飞船将会飞行的越来越快。
瞧!我只是想让我的人物跳跃
假设现在我们有一个跳跃人物Joe,Joe的初始位置是在一个地面或者一个平台上。用户按键后,Joe应该跳到空中。对于Joe,你需要明白三件事情:他的位置,速度和加速度。
开始,他的位置在地面上,一旦按键被触发,我们给Joe一个向上的很快的速度。然后每一帧/秒/通过一个相反的数值更新他向上的速度。
decrease是一个方向向下的加速度。它的水平的方向是没有影响的。所以当Joe在空中的时候,你可以改变它的前后移动。
注意:在实际生活中,当我们跳跃的时候是有可能前后移动的。但是我发现允许前后移动的游戏在跳跃的时候却不能前后移动了,只能竖直的跳跃,这样的游戏是不尊重实际的。
什么情况下我们才能够加入加速度呢?在地球上,Joe的垂直方向的加速度是9.81m/s^2。不幸的是米/秒的单位对于电脑来说是没有意义的。加速度是由你的游戏的帧更新来决定的。最好的方法就是来推测它。
以下为实现的伪代码:
Joe.pos.y = 0; (Or wherever floor is) Joe.vel.y = 0; Joe.accel = 10; Joe.jumping = NO; Loop If (jump key is pressed) { Joe.vel.y = 100; Joe.jumping = YES; } if (Joe.jumping == YES) /* Move Joe if we are jumping */ { Joe.vel.y = Joe.vel.y - Joe.accel Joe.pos.y = Joe.pos.y + Joe.vel.y } if (Joe.pos.y <= 0) /* Check to see if Joe has hit floor */ { Joe.vel.y = 0; Joe.jumping = NO; } End Loop |
第一次按跳跃键,Joe将会突然的跳离地面。
随着逐渐的升高,Joe开始因为速度的逐渐的损耗而慢下来。Joe最终会停止上升,开始下降。它会下降的越来越快直到到达地面。
Joe在Y方向上的速度和位置在每次循环的结尾出现,如下面的数据:
Loop0 : Joe.vel.y = 0 Joe.pos.y = 0 Loop1 : Joe.vel.y = 100 Joe.pos.y = 100 Loop2 : Joe.vel.y = 90 Joe.pos.y = 190 Loop3 : Joe.vel.y = 80 Joe.pos.y = 270 Loop4 : Joe.vel.y = 70 Joe.pos.y = 340 Loop5 : Joe.vel.y = 60 Joe.pos.y = 400 Loop6 : Joe.vel.y = 50 Joe.pos.y = 450 Loop7 : Joe.vel.y = 40 Joe.pos.y = 490 Loop8 : Joe.vel.y = 30 Joe.pos.y = 520 Loop9 : Joe.vel.y = 20 Joe.pos.y = 540 Loop10: Joe.vel.y = 10 Joe.pos.y = 550 Loop11: Joe.vel.y = 0 Joe.pos.y = 550 Loop12: Joe.vel.y = -10 Joe.pos.y = 540 Loop13: Joe.vel.y = -20 Joe.pos.y = 520 Loop14: Joe.vel.y = -30 Joe.pos.y = 490 Loop15: Joe.vel.y = -40 Joe.pos.y = 450 Loop16: Joe.vel.y = -50 Joe.pos.y = 400 Loop17: Joe.vel.y = -60 Joe.pos.y = 340 Loop18: Joe.vel.y = -70 Joe.pos.y = 270 Loop19: Joe.vel.y = -80 Joe.pos.y = 190 Loop20: Joe.vel.y = -90 Joe.pos.y = 100 Loop21: Joe.vel.y =-100 Joe.pos.y = 0 |
注意,Joe碰到地面的速度是很快的,如果Joe没有碰到地面,或者是地面消失了(例如:他跳离了平台),Joe将会下降的非常快。
我们需要给他一个限制速度。这就是Joe所能够下落的最快速度。在实际中,这可能是空气的阻力来影响:
Joe.pos.y = 0; (Or wherever floor is) Joe.vel.y = 0; Joe.accel = 10; Joe.jumping = NO; Loop if (jump key is pressed) { Joe.vel.y = 100; Joe.jumping = YES; } if (Joe.jumping == YES) /* Move Joe if we are jumping */ { if (Joe.vel.y > -100) /* Limit Joe's velocity to -100 */ { Joe.vel.y = Joe.vel.y - Joe.accel Joe.pos.y = Joe.pos.y + Joe.vel.y } } if (Joe.pos.y <= 0) /* Check to see if Joe has hit floor */ { Joe.vel.y = 0; Joe.jumping = NO; } End Loop |
添加到循环当中不会降低Joe的速度。它始终以<-100的速度下降。
其他的方向
对于上面的例子已经很好了,但是对于一个好的人物来讲不只是会上下跳跃。还能够在跳跃的时候来回的走。因为x和y的值在加速度产生的时候是不受约束的,所以当你解决了Joe的y方向上的速度,你也可以移动他的x方向。
现在看来Joe是沿着一个他在真实世界中的路径行走。对于3D空间来讲,他的处理方式同y方向上都是一致的。
装备太空人
运动学应用的另一个例子是星际类型的游戏。你在一个原点的环境中飞行,但是能够向任何的方向冲刺。
在这里,重力没有体现出来,那我们用什么来代替呢?我们使用飞船的冲刺作为加速度。我们可以把加速度的向量分解到x和y方向上,然后再利用上面的方法来制作。
以下是伪代码:
pos.x = 0; pos.y = 0; vel.x = 0; vel.y = 0; acc.x = 0; acc.y = 0; Loop if (thrust key pressed) { resolve_direction_vector; acc.x = scale_x * 10; acc.y = scale_y * 10; } vel.x = vel.x + acc.x; vel.y = vel.y + acc.y; pos.x = pos.x + vel.x; pos.y = pos.y + vel.y; End Loop |
接下来让我们看一下如何来分解向量:resolv_direction_vector。我们这样做的原因是飞船可以向任何的方向飞行。这一步将会得到合适的方向向量。分解为x向量和y向量。一旦分解后,resolve_direction_vector 将会重新设置scale_x 和 scale_y。
![](../../../upload/attachment/26486/367f9542-40c0-38ff-8a3c-4423de8ba384.gif)
给方向设置一个角度,我们能够确定scale_x和scale_y变量。有很多的方法可以实现。我们可以这样:
scale_x = cos(angle);
scale_y = sin(angle);
trig函数将会照顾到负值,如果飞船冲西(angle=180),scale_x和scale_y的值应该是scale_x=-1,scale_y=0。我们的飞船的加速度将是在负的x方向上的。
如果飞船是冲东北的方向(angle=45)那将是
scale_x = .707
scale_y = .707
他的意思是飞船的y方向上的加速度是7.07,x方向上的加速度是7.01。你看到的将是飞船以45度角的方向以10的加速度飞行。
你需要限制飞船的最大速度,否则它会飞的越来越快。
实际因素
在这一部分中介绍一下实际的因素。如果你希望做一些更为复杂的运动,这部分将会给你解决这些因素的所有的东西。如果没有你所需要的,你可以从物理书中找到答案。
对于一个对象我定义了三个关键的变量:位移,速度和加速度。
重力在以下的等式中是同加速度有关系的:(附加说明:这就是牛顿第二定律)。
F=M*a
重力等于质量乘以加速度。在我们的飞船的例子中,上帝的手能够对于一个质量小而加速度更快的飞船受到的阻力比一个更大的质量的要小。
在位置,速度和加速度之间的关系是:
s = s0 + v0*t + 0.5*a*t^2
当前的位置等于初始的位置加上速度乘以时间加上1/2的加速度乘以时间的平方。
v = v0 + a*t
当前的速度等于初始的速度加上加速度乘以时间.
v^2 - v0^2 = 2*a*s
当前的速度的平方减去初始速度的平方等于2倍的加速度乘以位移。
以上的这四个基本公式,可以解决几乎所有的物理运动的问题。
这些公式都是基于加速度恒定的情况下的。
如何使用这些公式
让我们来看一下一个垂直的抛起的球,这是一个一维情形,因为球体只能是向上或者向下。我们把S0作为我们释放球体到空中的位置。虽让我们有了一个初始的位置,我们必须还要用位置了计算一下当前的位移。而position将会以S0为参考进行计算。
了解了这些,让我们把球抛向空中,我们立即释放该球,已知的条件是:
s0 = 0;
v0 = 10 m/s (方向向上,大约22公里/小时)
a = ?
他的加速度是什么呢?一个在地球上的对象,他的重力归结于质量:
Fg=M*g
M是质量,而g是重力加速度,地球上是g=9.81m/s^2。
将以上的公式进行串联:
Fg = M*a -> M*g = M*a -> g = a
质量被削掉了,非常有趣吧。对于任何的下落的对象,加速度是不受质量影响的。这就意味着一个河马和一个乒乓球的下落时一样快的。
球的加速度是g,或者写成9.81m/s^2。但是向下的加速度我们需要写成a=-g。
使用等式3,我们得到了:
v = v0 + a*t = 10 m/s + (-9.81 m/s^2) * 0 s = 10 m/s.
如果使用等式2,我们也能得到s=0。不错吧!
让我们来看一下0.5秒后的速度:
v = 10 + (-9.81) * 0.5 s = 5.1 m/s
正如我所预料到了,球体慢了下来。最终他会停止,知道了这些,我们设速度为0,解出t。
v = 0 = 10 + (-9.81) * t
我们知道了t=1.019秒,因此我们知道了在我们扔出了球1.019秒后,他会停止在半空中。
我们知道了他会停止,但是他在那里会停止呢?我们利用公式2可以计算出:
s = 0 + 10 * 1.019 + 0.5 * (-9.81) * 1.019^2 = 5.1 meters
这就是距离我们抛出它5.1米的位置。
上去了它还得下来,那它的速度是多少呢?我们接到他的时候的速度是多少呢?什么时候我们会接到球呢?我们知道了s=0。我们可以使用公式4,计算之后,我们知道了 v=sqrt(v0^2)。那就是v=v0。实际上这个等式有两个答案:+v0和-v0。什么意思呢?他的意思是球在s=0的位置,它既可能以v0的速度上升,也可能以v0的速度下降。当我们抛出它的时候我们知道了它会上升,它肯定会以相同的速度下降。
最后我们可以计算出他什么时候会下来:
v = -v0 = v0 + (-9.81) * t
结果:t=2.038秒,如果我们以10m/s的速度抛出球,在2.038后,球又会回到我们的手中。
在这部分当中我向大家说明了如何来应用这些公式。在一个实际的程序中,你不能简单的利用这些公式来设置每个对象,每次一个球抛起,都需要有一个单独的时间来控制他们。