Learning and Applying Mathematics using Computing

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.

Horizontal Position

Recall that our horizontally velocity stayed constant — the banana moves the same horizontal distance each frame: h

The distance that the projectile will have moved horizontally is therefore very simple:

  • After 0 frames: 0
  • After 1 frame: h
  • After 2 frames: h + h = 2 \times h
  • After 3 frames: \text h + h + h = 3 \times h

It’s not hard to see that in general, the horizontal position after a given number of frames, f, will be:

\text{horizDist} = f \times h

Vertical Position

The vertical position of the projectile is more complex. The distance it moves (initially v) reduces by g each frame:

So, here’s the distance the projectile will have moved after the first few frames:

  • After 0 frames: 0
  • After 1 frame: v
  • After 2 frames: v + (v-g) = 2 \times v - g
  • After 3 frames: v + (v-g) + (v-g-g) = 3 \times v - g \times (1 + 2)
  • After 4 frames: v + (v-g) + (v-g-g) + (v-g-g-g) = 4 \times v - g \times (1 + 2 + 3)

So the overall pattern is that the position will be:

\text{vertDist} = f \times v - g \times \displaystyle\sum_{i=1}^{f-1} i

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 \frac{1}{2} \times n \times (n + 1), which we can use here (n being f - 1):

\text{vertDist} = f \times v - g \times \frac{1}{2} \times (f - 1) \times f

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:

0 = \text{vertDist}
0 = f \times v - g \times \frac{1}{2} \times (f - 1) \times f
0 = f \times v - \frac{g}{2} \times (f^2 - f)
0 = f \times v - (\frac{g}{2} \times f^2 - \frac{g}{2} \times f)
0 = (v + \frac{g}{2}) \times f - \frac{g}{2} \times f^2

What we have here is a quadratic for f, which we can solve with the usual quadratic formula, where:

a = -\frac{g}{2}
b = v + \frac{g}{2}
c = 0

This gives our next step, by filling in the quadratic formula:

f = \displaystyle\frac{-(v + \frac{g}{2}) \pm \sqrt{(v + \frac{g}{2})^2 - 0}}{2 * -\frac{g}{2}}

f = \displaystyle\frac{-(v + \frac{g}{2}) \pm (v + \frac{g}{2})}{-g}

f = \textbf{either~~} 0 \textbf{~~or~~} \displaystyle\frac{-2 \times (v + \frac{g}{2})}{-g}

f = \textbf{either~~} 0 \textbf{~~or~~} \displaystyle\frac{2 \times v + g}{g}

f = \textbf{either~~} 0 \textbf{~~or~~} 2 \times \displaystyle\frac{v}{g} + 1

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 2 \times \frac{v}{g} + 1 frames. In our example above, the banana was launched with v = 5, g = 1, so we can predict correctly that it lands after 2 \times \frac{5}{1} + 1 = 11 frames.

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.


Comments on: "Take Aim" (1)

  1. Nice work, appreciated – helped me out with this tennis game I’m working on.

    Here is a version of the above which works with a height offset for AS3:

    static public function ComputeImpactTime(vz:Number, height:Number):Number
    var dt:Number = Constants.kTimeStep;
    var a:Number = (kGravity * dt) / 2.0;
    var b:Number = (vz * dt) + a;

    return (-b – Math.sqrt((b * b) – (4 * height * a))) / (2 * a);

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s