Category Archives: Basic

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.

The Logic Error

One of the hardest types of error to debug is the logic error. Your code compiles, your code runs but it doesn’t do what it is supposed to do. There is no error message pinning down a syntax error or helpful exception message showing where the program stopped and why, you just have to examine your code for your mistake.

In this post I want to present such a situation. The program (Processing sketch) is straightforward – there is a ball bouncing inside a box at constant speed. To make sure it is constant the sketch uses the elapsed time between frames to calculate the distance the ball should move. If the ball hits the left or right sides then the horizontal velocity is reversed by multiplying by -1. The same logic is applied if the ball hits the top or bottom sides when we multiply the vertical velocity by -1.

float ballSize = 20;
float ballX, ballY, ballVX, ballVY;
float speed = 500;
float left, right, top, bottom;

int currTime, prevTime;  // milliseconds
float elapsedTime;       // seconds

void setup() {
  size(600, 400);
  left = 40; 
  right = width-40; 
  top = 40; 
  bottom = height-40;
  rectMode(CORNERS);
  ballX = random(left + 2 * ballSize, right - 2 * ballSize);
  ballY = random(top + 2 * ballSize, bottom - 2 * ballSize);
  float angle = random(TWO_PI);
  ballVX = speed * cos(angle);
  ballVY = speed * sin(angle);
  // This should be last line in setup
  currTime = prevTime = millis();
}

void draw() {
  // Using elapsed time between frames to guarantee the ball moves at constant speed.
  currTime = millis();
  elapsedTime = (currTime - prevTime) / 1000.0;
  prevTime = currTime;  // set it up for the next frame
  updateBallPosition(elapsedTime);
  rebound();
  // Draw the frame
  background(255);
  stroke(0);
  strokeWeight(2);
  fill(250);
  rect(left, top, right, bottom);

  fill(0, 140, 0);
  ellipse(ballX, ballY, 2 * ballSize, 2 *ballSize);
}

void updateBallPosition(float et) {
  ballX += ballVX * et;
  ballY += ballVY * et;
}

void rebound() {
  if (ballX - ballSize < left || ballX + ballSize > right)
    ballVX *= -1;
  if (ballY - ballSize < top || ballY + ballSize > bottom)
    ballVY *= -1;
}

The program logic makes sense but it doesn’t work properly. If you copy and paste the code into Processing and run the sketch long enough you will eventually see the ball do something peculiar (it might take several minutes so be patient). If nothing happens on your computer then this video shows the results of running the sketch on mine.

Before you read the explanation give the problem some thought  and see if you can work out why this is happening.
If you haven’t worked it out yet don’t worry it took me a while too when it first happened to me.

Explanation
The ball moves at constant speed but the elapsed time between frames is not. This means that the distance traveled by the ball between frames can vary. Now consider the ball approaching the right wall, eventually the ball hits the wall and the X velocity is multiplied by -1. On the next frame the ball moves left but what happens if the condition

ballX + ballSize > right

is still true. The velocity is reversed again so on the next frame the ball moves right. The X velocity will be reversed each frame so the ball jiggles horizontally until it gets back inside the box. You can see what I mean here –

The Solutions
If we can explain the problem then we can develop appropriate solutions. Obviously the algorithm used in the rebound function has a logic error. I will present 3 alternative algorithms which solve this problem.

Solution 1
This the simplest algorithm to implement and only involves changing the velocity. If the ball hits the left wall then make the X velocity positive and if hits the right wall make the X velocity negative, then do a similar thing for the top and bottom walls. We can see this algorithm in action here –


It also means that if the ball starts outside the box, no matter how far outside, it will end up bouncing inside the box.

Solution 2
This algorithm is a simple variation of the original one. After multiplying by -1 reversing the velocity we update the ball position again using the same elapsed time. This has the effect of bringing the ball back inside the box.


Solution 3
Like solution 1 we test each wall separately but we still multiply the velocity by -1. The difference is that we  move the ball inside the box so that it is just touching the wall. On the next frame, the ball will move further into the box.

In this solution there will one frame where the ball is in contact with the wall on every rebound. This can give a slightly better ‘visual bounce’ than the other algorithms.

Conclusion
Notice that in all three solutions the ball trajectory after rebounding is different and none of them represent a real world rebound, they are all an approximation. There are solutions that provide more ‘accurate’ rebounds but they are computationally more intensive so you have to balance accuracy against efficiency.
Logic errors can be hard to find but it is important to understand what is happening in your code if you want reliable solutions.

frameRate, frameCount and millis

By default Processing will execute the draw() function 60 times a second. Each time it is executed it creates a new frame which is then displayed. So the display is updated 60 fps (frames per second). I should point out that this is not the case for JavaScript since each frame is drawn on demand, although it is possible to trigger those demands 60 times a second.

The frameRate(float fps) method can be used to set the desired frame rate and the variable frameRate holds the instantaneous frame rate (as calculated by Processing). There is another useful variable called frameCount, which is the number of frames rendered since the sketch started. Finally we have millis() which returns the number of milliseconds since the sketch started running.

Both the movies below show the output of sketches where the desired frame rate has been set with the statement frameRate(60).

In this sketch the graph plots the value of frameRate for every frame. We can see that the frame rate starts off low and quickly rises towards the desired value but then there is significant variation between frames. Once it has settled down the sketch uses the frame rate reported by Processing to calculate the average frame rate, which is plotted as a red line. Notice that this average does not match the desired frame rate of 60fps.

So although we could use frameRate to perform time dependent processing the difference from reality would be undesirable.

It is possible to calculate the true average frame rate and this is shown by the green line.

For a real time application we need to measure the elapsed time between frames. Processing provides a handy method called millis() which returns the time since the sketch started in milliseconds, using this it is simple to calculate the elapsed time between frames.

In this sketch the frame rate has been set to 60fps and the graph shows the elapsed time between frames. At 60fps the elapsed time should be 16.667ms but the millis method returns an integer so it is generally 16 or 17ms but there are some values either side of this range.

So what if we want a circle to traverse the screen at exactly 60 pixels per second? This sketch demonstrates how to do it. If you run this code in Processing you will see the green circle traverse the window at exactly 60 pixels per second. Since the sketch is 600 pixels wide it will take 10 seconds to traverse the display. You can change the frame rate in line 9 but it still travels at 60 pixels per second, although the movement will be more jerky at low frame rates.

int currTime, prevTime;  // milliseconds
float elapsedTime;       // seconds
float speed = 60;        // speed in pixels per second
float x0, x1;

void setup(){
  size(600, 200);
  frameRate(200);
  noStroke();
  // This should be last line in setup
  currTime = prevTime = millis();
}
 
void draw(){
  // Using elapsed time between frames for accuracy
  currTime = millis();
  elapsedTime = (currTime - prevTime) / 1000.0;
  prevTime = currTime;  // set it up for the next frame
  // Start frame rendering
  background(0, 0, 128);
  // update the position of the circle and draw it
  x0 += speed * elapsedTime; 
  x0 %= width;
  // wrap round screen width fill(0,255,0);
  ellipse(x0, 64, 20, 20);
} 

We could use frameRate instead by changing line 21 to

x0 += speed / frameRate;

but because the average frame rate measured using frameRate is greater than the actual frame rate the ball travels slower than 60 pixels per second. Although the difference is not great there is no reason why we should accept it.