Detecting the Edges of the Screen

In these notes you will learn:

  • How to test if a point has hit an edge of the screen.
  • Some basic uses of if-statements.
  • The structure and terminology of basic if-statements.
  • How to use variables to control the velocity of a ball.

Introduction

In this note we’ll see how to get an object to recognize the edges of the screen by using if-statements.

Detecting the Bottom Edge

Lets start with a program that makes a ball move slowly down the screen. When the ball hits the bottom, it disappears:

float x;  // (x, y) is the center
float y;  // of the ball

void setup() {
  size(500, 500);

  x = 250; // start near the top middle
  y = 50;  // of the screen
}

void draw() {
  background(255);  // draw the background

  // draw the ball
  noStroke();
  fill(255, 0, 0);
  ellipse(x, y, 50, 50);

  x += 0;  // add 0 to x
  y += 1;  // add 1 to y
}

Now lets modify this so that the ball wraps-around to the top of the screen. The means after it hits the bottom, it jumps back to the top.

To do this, we need to know when the ball has hit the bottom. We can do that by adding an if-statement after x and y are incremented:

void draw() {
  // ...

  x += 0;  // add 0 to x
  y += 1;  // add 1 to y

  if (y > 499) {  // if y is greater than 499, then
    y = 0;        // set y to be 0
  }

}

Every time draw() runs, it now checks to see if y is bigger than 499, i.e. if the ball has hit, or passed, the bottom of the screen.

If it has hit the bottom, then y is set to 0 so that on the next call to draw() the ball starts at the top. This gives the appearance of wrapping- around the screen.

Adding Velocity

Now lets make a useful improvement to our program. In addition to a position, all animated objects also have a velocity, which is the speed and direction the object is travelling in.

We will often want to change the velocity of an object, e.g. make it stop or slow down or speed up. To make that possible, the velocity must be represented as variables so that we can, when needed, vary the velocity.

The standard names for the velocity variables are dx and dy, where the d stands for “difference”. For example, dx is the difference in the x values in two consecutive calls to draw().

Now lets re-write the above program using dx and dy:

float x;  // (x, y) is the center
float y;  // of the ball

float dx; // left/right velocity
float dy; // up/down velocity

void setup() {
  size(500, 500);

  x = 250; // start near the top middle
  y = 50;  // of the screen

  dx = 0; // initialize the velocity so
  dy = 1; // its moving downwards only
}

void draw() {
  background(255);  // draw the background

  // draw the ball
  noStroke();
  fill(255, 0, 0);
  ellipse(x, y, 50, 50);

  x += dx;  // add dx to x
  y += dy;  // add dy to y

  if (y > 499) {  // if y is greater than 499, then
    y = 0;        // set y to be 0
  }
}

The behaviour should be the same as before, but now we can more easily control the ball’s velocity.

For example, to make the ball stop when it hits the bottom edge, change the if-statement to this:

if (y > 499) {  // if y is greater than 499, then
  dx = 0;       // set stop the ball
  dy = 0;
}

Setting both dx and dy to 0 immediately stops the ball.

Or, if want to make the ball reverse direction, we would change the if- statement to this:

if (y > 499) {  // if y is greater than 499, then
  dy = -dy;     // reverse the y-direction
}

The statement dy = -dy means “assign to dy the negation of dy”. This flips the sign of dy, which has the effect of changing the ball’s direction.

Note

All the 2-dimensional animated objects we create in this course will have, at least, these four variables: x, y, dx, and dy. Some objects might have (many!) more, but these are the minimum set of variables we need to do interesting animation.

Changing the Color

We can run any code we like when the ball hits the bottom of the screen. Lets make the ball’s color change to a random new color when it hits the bottom.

Since its color now varies, we’ll store its color in a variable called ballFillColor to store its color. Here is the modified program:

float x;  // (x, y) is the center
float y;  // of the ball

float dx; // left/right velocity
float dy; // up/down velocity

color ballFillColor;

void setup() {
  size(500, 500);

  x = 250; // start near the top middle
  y = 50;  // of the screen

  dx = 0; // initialize the velocity so
  dy = 1; // its moving downwards only

  ballFillColor = color(255, 0, 0);
}

void draw() {
  background(255);  // draw the background

  // draw the ball
  noStroke();
  fill(ballFillColor);
  ellipse(x, y, 50, 50);

  x += dx;  // add dx to x
  y += dy;  // add dy to y

  if (y > 499) {  // if y is greater than 499, then
    dy = -dy;     // flip its sign and give it a random color
    ballFillColor = color(random(256), random(256), random(256));
  }

}

Checking for the Top Edge

Currently, our program only checks for the bottom edge of the screen. If we want to check for other edges, then we need to add if-statements that check for each edge:

void draw() {
  // ...

  // check if hit the bottom edge
  if (y > 499) {  // if y is greater than 499, then
    dy = -dy;     // flip its sign and give it a random color
    ballFillColor = color(random(256), random(256), random(256));
  }

  // check if hit the top edge
  if (y < 0) {  // if y is less than 0, then
    dy = -dy;   // flip its sign and give it a random color
    ballFillColor = color(random(256), random(256), random(256));
  }
}

If you run the program now, the ball will bounce up and down forever, changing to a random color after each bounce.

Checking for the Left and Right Edges

We’ve set dx to 0 in our program, which means the ball does not move left or right at all. But if we set it to some non-zero value, then it will eventually hit the left or right edge. So lets check for those two edges:

void draw() {
  // ...

  // check if hit the left edge
  if (x < 0) {  // if x is less than 0, then
    dx = -dx;   // flip its sign
    ballFillColor = color(0, 0, 255);
  }

  // check if hit the top edge
  if (x > 499) {  // if y is greater than 499, then
    dx = -dx;     // flip its sign
    ballFillColor = color(255, 255, 0);
  }

}

Notice that we check the value of x here (instead of y), and that we flip the sign of dx (instead of dy).

When you test this program, make sure to set both dx and dy to non- zero values.

Bouncing Off Edges of the Ball

For simplicity, we’ve been making the ball bounce when its center point hits an edge. The problem with this is that the ball goes half-way off the screen on each edge, e.g:

A ball half-way through the bottom edge of the screen.

Instead, suppose we want the ball to stop when its outside edge hits the a screen edge. Since the screen has four edges, we need to keep track of four different points on the ball:

  • the top-most point, (x, y - 25)
  • the bottom-most point, (x, y + 25)
  • the left-most point, (x - 25, y)
  • the right-most point, (x + 25, y)
Four points in the edge of a circle.

We need to modify the four if-statements to check for these points instead of (x, y):

void draw() {
  // ...

  // check if hit the bottom edge
  if (y + 25 > 499) {
     // ...
  }

  // check if hit the top edge
  if (y - 25 < 0) {
     // ...
  }

  // check if hit the left edge
  if (x - 25 < 0) {
     // ...
  }

  // check if hit the top edge
  if (x + 25 > 499) {
     // ...
  }

}

Be careful to get all the arithmetic exactly right!

Adjust the Ball’s Position on a Bounce

It is useful to add one more small feature to this program. When a fast-moving ball hits an edge, it’s possible that it goes a few pixels past the edge. In other words, the ball can be slightly embedded in the edge. When we reverse the direction of a ball embedded in an edge, it’s possible that the ball could get stuck forever.

We will try to prevent that problem by adjusting the position of the ball after it hits an edge. When we reverse the ball, we will also move it a little so that it is precisely on the edge. That way it will hopefully never get caught in an edge.

To implement this, we will need to modify the if-statements. For example:

// check if hit the bottom edge
if (y + 25 > 499) {  // if y is greater than 499, then
    dy = -dy;        // flip its sign
    y = 499 - 50;
    ballFillColor = color(255, 0, 0);
}

The statement y = 499 - 50 was added. It makes sure that the ball is exactly on the edge when it reverses direction.

For the top edge, the if-statement becomes this:

// check if hit the top edge
if (y - 25 < 0) {  // if y is less than 0, then
    dy = -dy;      // flip its sign
    y = 25;
    ballFillColor = color(0, 255, 0);
}

The statement y = 25 has been added.

The if-statements for the left and right edges are modified in a similar way, except the variable x is used instead of y.

Questions

  1. In brief, clear English, describe the purpose of an if-statement. Show how it works using a simple example.
  2. Why is the body of an if-statement indented?
  3. What do the variables dx and dy mean in these programs?
  4. In the program developed in the notes, we checked for edges in this order: bottom, top, left, and right. Would the program still work if we changed the order the edges were checked?

Programming Questions

  1. Modify the final program below so that when the ball hits an edge it wraps- around (i.e. immediately jumps) to the opposite edge. Make sure no part of the ball is ever drawn off the screen.

  2. Modify the final program below so that an image bounces around the screen instead of a ball. Make sure that no part of the image ever goes off the screen, i.e. it should bounce off its edges just like the ball.

  3. Modify the final program below so that ball changes to a random color every time it hits an edge. Use this expression create a random color:

    color(random(256), random(256), random(256))
    

Final Program

float x;  // (x, y) is the center
float y;  // of the ball

float dx; // left/right velocity
float dy; // up/down velocity

color ballFillColor;

void setup() {
  size(500, 500);

  x = 250; // start near the top middle
  y = 50;  // of the screen

  dx = -2; // initialize the velocity so
  dy = 1;  // its moving downwards only

  ballFillColor = color(255, 0, 0);
}

void draw() {
  background(255);  // draw the background

  // draw the ball
  noStroke();
  fill(ballFillColor);
  ellipse(x, y, 50, 50);

  x += dx;  // add dx to x
  y += dy;  // add dy to y

  // check if hit the bottom edge
  if (y + 25 > 499) {  // if y is greater than 499, then
    dy = -dy;     // flip its sign
    ballFillColor = color(random(256), random(256), random(256));
  }

  // check if hit the top edge
  if (y - 25 < 0) {  // if y is less than 0, then
    dy = -dy;   // flip its sign
    ballFillColor = color(random(256), random(256), random(256));
  }

  // check if hit the left edge
  if (x - 25 < 0) {  // if x is less than 0, then
    dx = -dx;   // flip its sign
    ballFillColor = color(random(256), random(256), random(256));
  }

  // check if hit the top edge
  if (x + 25 > 499) {  // if y is greater than 499, then
    dx = -dx;   // flip its sign
    ballFillColor = color(random(256), random(256), random(256));
  }

}