35.Take Aim
In our last post, we implemented projectile motion as the start of a game involving monkeys throwing bananas. We saw that projectile motion always follows the same parabolic pattern, which will look something like this:
在我们上一篇帖子里,作为一个涉及猴子扔香蕉游戏的开始,我们实现了抛掷运动。我们看到抛掷运动始终遵循抛物线模式,它看起来像这样:
Since the projectile follows a straightforward motion pattern, we can actually predict, mathematically, where the projectile will land. To do this, let’s work out where the projectile will be, a certain number of frames after it has launched, given an initial velocity of h horizontally, and v vertically, with gravity set to some value g.
由于抛掷遵照一个明确的运动模式,我们能够从数学上真实地预判抛掷的着陆点。为了做到这个,让我们算出抛掷将会落在哪儿,即发射之后的一个确定数量的帧数,给定初始的水平速率h和垂直速率v,并将重力加速度设为g。
Horizontal Position
水平位置
Recall that our horizontally velocity stayed constant — the banana moves the same horizontal distance each frame: h
回忆一下我们的水平速率保持不变——香蕉每一帧移动相同的水平距离h:
The distance that the projectile will have moved horizontally is therefore very simple:
抛掷的水平移动距离因而非常简单:
- 在第0帧后:
- 在第1帧后:
- 在第2帧后:
- 在第3帧后:
It’s not hard to see that in general, the horizontal position after a given number of frames, f , will be:
不难看出一般来说,在给定帧数下的水平位置f将会是:
Vertical Position
垂直位置
The vertical position of the projectile is more complex. The distance it moves (initially v) reduces by g each frame:
抛掷的垂直位置更加复杂。它移动的距离(初始为v)每一帧减少g:
So, here’s the distance the projectile will have moved after the first few frames:
于是,这儿是经过开始的一些帧后抛掷将会移动的距离:
- 在第0帧后:
- 在第1帧后:
- 在第2帧后:
- 在第3帧后:
- 在第4帧后:
So the overall pattern is that the position will be:
于是总体模式是位置将会是:
The last part describes the sum of the numbers from 1 up to f-1 — that’s the (1+2+3) part from our pattern above. This need to sum up the numbers is the classic example for summation (wikipedia currently has it as its example for summation), and has the well-known result in mathematics that summing the numbers from 1 to n is equal to, which we can use here (n being f-1):
公式的最后部分描述了从数字1到f-1的和——那是我们公式中的(1+2+3)部分。这种累加数字的需求便是典型的求和示例,同时在数学里关于数字1到n的和有众所周知的结果可供我们在这里使用(n换做f-1),它等于:
Predicting the landing
预测着陆点
So we now have formulae for the horizontal and vertical distance of the projectile (in our case, a banana). The question we want to answer is: where will the banana land? For this, we use the fact that in our game, the banana only lands when the vertical distance reaches zero again (i.e. when the banana returns to ground level), so we can use that to work out how many frames it will be in flight for. Then, once we know the number of frames before it lands, we can then work out how far it will have gone horizontally. So we need to solve for when vertical distance is zero:
于是我们现在拥有了计算抛掷(在我们的例子里指香蕉)的水平和垂直距离的公式。我们希望回答的问题是:香蕉会落在哪儿?为了解答它,我们使用这样的事实,即在我们的游戏中,香蕉只会在其垂直距离重新到达零时着陆(换句话说当香蕉回到地面水平线上),于是我们可以计算出它在飞行时将会经历多少帧。于是,一旦我们知道它着陆前的帧数,我们便可以算出它将会在水平方向移动多远。因此我们需要解析垂直距离什么时候为零:
What we have here is a quadratic for , which we can solve with the usual quadratic formula, where:
我们这儿得到的是一个关于f的二次方程式,可以使用通常的二次公式来求解它,已知:
This gives our next step, by filling in the quadratic formula:
下一步带入二次公式:
Now, the solution where =0 refers to when the banana is launched, so we can ignore that solution. We want the other solution, which says that the banana will land after frames. In our example above, the banana was launched with
, so we can predict correctly that it lands after
frames.
现在看看,解为0对应的是香蕉发射时的情况,于是我们可以顾略该解。我们希望另一个解,它说明香蕉将会在帧之后落地。在我们上面的示例中,香蕉发射时
,于是我们可以准确地预测出它在
帧后落地。
The advantage of doing all this maths is that our code ends up nice and simple for calculating the horizontal impact of the banana:
所作的这些数学计算的优点在于我们的代码最终在计算香蕉的水平分量时显得既良好又简单:
double vx = Player.getVelX(radianAngle, forceFactor); double vy = Player.getVelY(radianAngle, forceFactor); double impactTime = 2.0 * (vy / ProjectileWorld.GRAVITY) - 1; double impactX = player.getX() + impactTime * vx;
I’ve added this to the scenario so that you can have a play. You can see that the cross on the ground moves as you aim, and once you fire, it correctly predicts where the banana will land. Having the visible target makes our scenario a bit too easy for human players, but the calculation will be useful in future posts.
我已经添加了这个剧本因而你可以试玩一下。你可以看到当你瞄准时地面上的叉在移动,而且一旦你开火,它准确地预测香蕉将会在哪儿落地。拥有可见的目标使得我们的剧本对于人类玩家过于简单,但是在今后的帖子里这个计算将会非常有用。