Monthly Archives: August 2016

Cannon Fire

In the post Linear motion we saw how vectors can be used to represent the position and velocity of a moving object. Here we look at how they can be used to simulate the shot fired from a medieval cannon as shown here.

When the cannon is fired the cannon ball will have an initial direction and speed (depending on the barrel elevation and the amount of gunpowder used).

We can see that the cannon ball’s direction (angle) changes throughout it’s flight due to  gravity and air resistance so using speed/angle would be computationally demanding. So we are going to use vectors (Processing’s PVector class) to represent the ball’s position and velocity.

So we need some variables to store this data –

int cannon_angle;           // degrees
PVector cannon_pos;

// Cannon ball data
PVector ball_pos, ball_vel;
float speed = 300;         // cannon-shot speed

So the cannon is fired, the first job is to calculate the initial position and velocity of the cannon ball. We can do that with

ball_pos.set(cannon_pos);
float angle = radians(cannon_angle);
ball_vel.set(speed * cos(-angle), speed * sin(-angle));

The first line initialises the position of the ball to that of the cannon. The angle data is stored in degrees because that is what the human user understands but we must convert it to radians for the trigonometric functions, that is done in the second line. Finally we initialise the velocity vector using the speed and angle. Notice that we negate the angle because the barrel rotation is anti-clockwise.

At each frame we need to update the ball’s velocity to take into account gravity and air resistance, both of which can be represented as vectors. In this sketch we use

gravity = new PVector(0, 100);
air = new PVector(-40, 0);

The gravity will only affect the vertical component of the velocity and the air resistance will only affect the horizontal component.

So we update the velocity with

ball_vel.add(PVector.mult(gravity, elapsedTime));
ball_vel.add(PVector.mult(air, elapsedTime));
ball_vel.x = max(ball_vel.x, 0);

where elapsedTime is the number of seconds since the last frame.

The last line prevents the cannon ball reversing its horizontal velocity due to air resistance. In the physical world this is impossible but in our simplistic model, it is a possibility we should guard against.

We can now use this velocity to update the ball’s position with

ball_pos.add(PVector.mult(ball_vel, elapsedTime));

I hope this demonstrates the usefulness of using vectors to represent positions, velocities and forces (gravity and air resistance) to plot non-linear movement.

You can download the sketch used in the production of the movie above here. It is compatible with both Processing 2 & 3.

Linear motion

What is the difference between speed and velocity?

To move a ball (or anything else) then we need to know how fast to move the ball and the direction to move it. So to answer the question –

  • speed = says how fast the ball is moving.
  • velocity = says how fast the ball is moving and the direction it is moving.

So in our program we need to think in terms of velocity and there are two ways we can represent velocity.

Speed and angle

The ball is moving at 100 pixels per second at 30°.

In mathematics 0° starts along the hrorizontal axis and increases anti-clockwise but on most computer displays it increases clockwise. This is because the positive Y axis is reversed and y increases as we move down the display.

Vectors

Instead of using the angle we can simply specify the amount the ball should travel in both  the X and Y directions and record this in a vector. In Processing we should use the PVector class to do this.

The PVector class has three fields [x, y, z] but since we are moving in 2D we can ignore the z value. As well as velocity the PVector should be used to remember the position of the ball.

Converting between speed/angle and vector representations

There are many situations where you might use both representations so it is important to be able to convert between representations. So using –

a = the movement angle measured in radians 
s = the movement speed 
vx = the amount to move in the x direction 
vy = the amount to move in the y direction 
vel = a PVector object that represents the velocity [vx, vy]
Speed/angle to vector
vx = s * cos(a)
vy = s * sin(a)

and using the PVector object

vel.set(s * cos(a), s * sin(a))
Vector to speed/angle
s = sqrt(vx * vx + vy + vy)
a = atan2(vy, vx)

and using the PVector object

s = vel.mag()
a = atan2(vel.y, vel.x)

Visualising both representations

Updating the balls position

Lets assume that we are using a PVector to store the ball’s current position. We can update the balls position every frame using the elapsed time between frames.

Speed and angle
// pos is a PVector of the ball's current position
// the ball is traveling at 'speed' 
// angle = direction the ball is traveling in radians
// speed = the ball's speed in pixels per second
// elapsedTime = time since the last frame in seconds 
pos.add(speed * cos(angle) * elapsedTime, 
               speed * sin(angle) * elapsedTime); 
Vector
// pos is a PVector of the ball's current position
// vel is the velocity where the fields are
//     x = the horizontal speed in pixels per second
//     y = the vertical speed in pixels per second
// elapsedTime = time since the last frame in seconds
pos.add(vel.x * elapsedTime, vel.y * elapsedTime); 

Which representation to use?

It depends on what you are trying to do, but generally the vector representation is preferred because it reduces the need to use the processor intensive trigonometric functions.

Next: The post Cannon Fire shows how this information can be used to simulate a medieval cannon.