6. 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 terminology of the if-statement.
  • The meaning of the basic relational operators.
  • The meaning of the basic boolean operators.

6.1. Introduction

So far, the animated objects we’ve created disappear from view once they hit an edge of the screen. In these notes we’ll see how to get an object to recognize the edge of the screen. To do these we will introduce if-statements and comparison operators.

6.2. Detecting the Bottom Edge

Lets start with a program we’ve already seen. When this program runs a ball moves slowly down the screen, and then disappears:

color orange = color(255, 165, 0);
color white = color(255, 255, 255);

// y is the vertical position of the ball
float y;

void setup() {
  size(500, 500);
  smooth();  // draw things with smooth edges

  // the ball starts near the top of the screen
  y = 1;
}

void draw() {
  // re-draw the background
  background(white);

  // draw the ball
  noStroke();
  fill(orange);
  ellipse(250, y, 50, 50);

  // add 1 to y to make the ball move downwards
  y += 1;
}

How can we get the ball to do something — say, stop — when it hits the bottom of the screen?

This boils down to the following question: when does the point (x, y), the center of the ball, hit the bottom edge?

Since the y-values screen increase downwards, (x, y) is on the bottom edge when y = 499. If y > 499, then it is past the bottom edge and off the screen. It’s unlikely that an animated object will precisely hit an edge, and so we usually combine these two cases and say that (x, y) has hit the bottom edge as soon as y >= 499.

The ball needs to check if it is off the screen every time it moves. When it does hit an edge, then we do something, e.g. stop it, change its direction, make it explode, or whatever we want.

We use an if-statement to check the value of y each time it changes:

void draw() {
  // re-draw the background
  background(white);

  // draw the ball
  noStroke();
  fill(orange);
  ellipse(250, y, 50, 50);

  // add 1 to y to make the ball move downwards
  y += 1;

  if (y >= 499) {
     // uh oh: the ball has gone off the edge of the screen!
     //        Do something!
  }
}

In English, the if-statement reads like this: “If y is greater than, or equal to, 499, then do the following ...”. Note the open { on the line with the if and the matching } under it. These two braces mark the beginning and end of the block of code that will be run if y >= 499 is true.

6.3. Stopping the Ball

Suppose that we want the ball to stop dead when it hits the bottom of the screen. That means that we want its y-value to be fixed at, say, 499. So we put this code inside the if-statement in the previous program:

if (y >= 499) {
   y = 499;
}

This works, but there is a small annoyance: it stops the ball after it travels half-way through the bottom edge:

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

This happens because y is the y-value of the center of the ball.

Instead, suppose we want the ball to stop as soon as its lowest point hits the bottom of the screen. To do this we need to figure out the coordinates of the lowest point on the circle. Since the center point is (250, y), then, because the circle has diameter 50 in our program, it must be (250, y + 25):

A circle with two points.

So we modify the if-statement to check for the lowest point on the circle:

if (y + 25 >= 499) {
   y = 499;
}

If you make this change and run the program, you will see that it doesn’t work! The ball falls as usual, but when it gets to the bottom it suddenly lurches down and stops half-way through the bottom edge as before.

The problem is that we are setting y to be the wrong value inside the if-statement. Currently, we set y = 499, and that sets the y-value of the center of the circle to be 499. We don’t want that: we want the lowest point on the circle to have y-value 499. If this point has y-value 499, then the center must have y-value 499 - 25 (because it is 25 pixels away). So we need to make one more change to our if-statement:

if (y + 25 >= 499) {
   y = 499 - 25;
}

This works!

Note

We wrote 499 - 25 in the assignment to y to make it clear how we got its value. Processing automatically does the arithmetic for us. However, we could also have written it like this:

if (y + 25 >= 499) {
   y = 474;
}

Or even this:

if (y >= 474) {   // harder to read: where does 474 come from?
   y = 474;
}

The main problem with these two way of writing the if-statement is that it is not at all clear where the number 474 came from.

Another nice effect is to have the ball wrap-around to the top of the screen after it hits the bottom edge. This turns out to be a very simple modification: inside the if-statement we set y to be 1 (or some other value close to the top of the screen):

if (y + 25 >= 499) {
   y = 1;  // wrap-around to the top of the screen
}

6.4. If-statement Terminology

The if-statement in our program has this form:

// ... previous statements ...

if (cond) {           // first line is the header
  body statements     // code between { and } is the "body"
}

// ... following statements ...
If-statement flow-chart.

It begins with the token if, and is immediately followed by (cond), where cond is a boolean expression, i.e. an expression that evaluates to either true or false (like y >= 499).

The line with the condition is sometimes referred to as the if-statement’s header line. After the header line comes the body of the if-statement. The code in the body is only executed when cond is true; if cond is false, then the body is not executed.

Also notice that the body statements are indented a few spaces. While this is strictly optional, it is very useful: indentation visually groups related statements, which does wonders for your program’s readability. As our programs get bigger we will see that indentation is a useful technique for making readable code.

When we first wrote our if-statement body, we didn’t put any code into it. Instead, we wrote a source code comment, i.e. a note to us, the programmers, about should happen. We then replaced the comment later when we decided what we wanted the ball to do when it hit the edge.

Note

When the body of an if-statement consists of exactly one statement, it is not necessary to write the { and }. For instance, we could write the if-statement from above like this:

if (y >= 499)
   y = 0;

Or even more succinctly like this:

if (y >= 499) y = 0;

However, if you are not careful this can lead to confusion about what statements are part of the body. In this course we will occasionally write if-statements without the { and }; when we do, we will almost always but the body statement on the same line as the condition.

6.5. Some Relational Operators

Since boolean expressions turn out to be quite important, let’s discuss them in a little more detail.

We’ve just seen >=, which compares numbers and means “greater than or equal to”, e.g. x >= y is true just when x is greater than, or equal to, y, and false otherwise.

Similarly, the expression x <= y evaluates to true if x is less than, or equal to, y, and false otherwise.

Here’s a list a few common boolean expressions. We assume both x and y are numbers:

x >= y   // x greater than, or equal to, y ?
x <= y   // x less than, or equal to, y ?

x > y    // x greater than y ?
x < y    // x less than y ?

x == y   // x equal to y ?
x != y   // x not equal to y ?

>=, <=, <, >, ==, and != are sometimes referred to as relational operators, or comparison operators.

Warning

The expressions x = y and x == y are not the same in Processing. The expression x == y tests if x and y have the same value, while x = y assigns the value of y to x. This is very different than what = usually means in mathematics: the mathematical = means the same as ==.

Warning

You cannot chain relational operators together as in mathematics, i.e. this does not work in Processing:

1 < 2 < 3    // bad!

This is an error. To evaluate such an expression you must write this (where && means “and”):

1 < 2 && 2 < 3  // okay!

Most mainstream programming languages have the same restriction, i.e. expressions like 1 < 2 < 3 either cause an error, or don’t work the way you would expect.

We can also use logical operators to combine boolean expressions. For instance, suppose both a and b are boolean expressions. Then the following are also boolean expressions:

!a       // not a; negation of a

a && b   // a and b; conjunction of a and b

a || b   // a or b; disjunction of a and b

These three logical operators have precise meanings:

  • !a evaluates to true when a is false, and false when a is true.
  • a && b evaluates to true just when both a and b evaluate to true. It evaluates to false if either a, or b, or both a and b, are false.
  • a || b evaluates to true when a is true, or b is true, or both a and b are true. The only time it is false is when both a and b are false.

We can summarize these logical operators using truth-tables. For example, here is the truth table for &&:

a b a && b
false false false
false true false
true false false
true true true

And for ||:

a b a || b
false false false
false true true
true false true
true true true

And !:

a !a
false true
true false

Boolean operators are used all the time in programming, and so you should memorize exactly how they work.

6.6. Some Examples of How to Use Logical Operators

Here’s a simple example of how you might use ||, i.e. “or”. Instead of writing y >= 499 in an if-statement, we could write it like this:

if (y == 499 || y > 499) {
   y = 499;
}

The expression y == 499 || y > 499 is logically equivalent to y >= 499. You could write either one in the program, but y >= 499 is less typing and quite clear, so most programmers prefer it.

As another example, suppose you want to test if y is between, say, 100 and 200. Then you could write this:

if (y > 100 && y < 200) {
   // y is between 100 and 200 ... do what you want to do
}

The expression y > 100 && y < 200 is true just when y is greater 100 and less then 200.

The ! operator means not. So, for example, to test if y is not equal to 499 we could write this:

if (!(y == 499)) {
   // y is not equal to 499 ... do what you want to do
}

Equivalently, we could write this using the != (not equal) operator:

if (y != 499) {
   // y is not equal to 499 ... do what you want to do
}

This second if-statement is better because it is shorter and clearer than the one with ! in the front.

6.7. A Velocity Variable

To implement other behaviours — such as bouncing — we need to make another change to our program. Instead of adding 1 each time to y, we are going to add dy, which is a float variable that we create. It represents the velocity of the ball along the y-axis:

color orange = color(255, 165, 0);
color white = color(255, 255, 255);

// y is the vertical position of the ball
float y;
float dy;

void setup() {
  size(500, 500);
  smooth();
  // the ball starts near the top of the screen
  y = 1;
  dy = 1;
}

void draw() {
  // re-draw the background
  background(white);

  // draw the ball
  noStroke();
  fill(orange);
  ellipse(250, y, 50, 50);

  // add 1 to y to make the ball move downwards
  y += dy;

  if (y >= 499) {
    y = 1;
  }
}

This program behaves exactly the same as the previous one. The difference here is y gets increased by the value of dy each time draw() is called.

Now we can change the ball’s velocity by setting dy. For example, to make the ball stop dead when it hits the bottom of the screen, we do this:

if (y >= 499) {
  dy = 0;
}

When dy is 0, the position of the ball never changes.

To make the ball bounce is almost as easy:

if (y >= 499) {
  dy = -dy;
}

The statement dy = -dy; just changes the sign of dy, i.e. if dy is 1, then after dy = -dy; it will be -1. This causes the ball to move up the screen.

6.8. Questions

  1. Write out the general form of an if-statement. Indicate its header and body.

  2. Why is the body of an if-statement indented?

  3. When testing if the ball has hit the bottom of the screen, we used this code:

    if (y >= 499) {
       // ...
    }
    

    Why does this use the condition y >= 499 instead of y == 499?

  4. For each of the following expressions, say whether it is true or false:

    • 1 == 2
    • 1 != 2
    • 1 + 3 < 13
    • 5 > 5
    • (1 + 2) == (4 - 1)
  5. Suppose x and y are both variables of type float. They’ve been assigned different values, but we don’t know exactly what they are. For each of the following expressions, say whether it is true or false:

    • x == y
    • x != y
    • x == x
    • y >= y
    • (x + y) == (y + x)
  6. Briefly describe the meaning of !, &&, and ||.

  7. What are all the possible values of a and b that make the expression a || b false?

  8. The expression (x < y) || (x == y) can be written as the shorter and logically equivalent expression x <= y. Re-write each of the following expression as a shorter equivalent expression:

    • (x > y) || (x == y)
    • !(x == y)
    • (x <= y) && (x != y)
    • !(x == y) && (x >= y)
    • x != x
  9. Write an if-statement that tests if x, a float variable that has been given some value (you don’t know what it is) is equal to -2, 7, or 15. Only execute the body of the if-statement if x is one of those three values. The if-statements body can just be a source-code comment.

  10. Re-do the previous question, except this time only execute the body of the if-statement if x is not one of -2, 7, or 15. Give two different answers:

    1. One answer that uses !=;
    2. A different answer that uses ! and either || or &&. Don’t uses != in this answer.
  11. Explain the purpose of the variable dy in the final sample program of the notes.

  12. Write an if-statement that could be put into draw() to test if the ball has hit the top of the screen. Don’t worry about what goes inside the body of the if-statement.

6.9. Programming Questions

  1. Write a program that makes a ball rise upwards and when it hits the top of the screen it gets replaced by a fish (or some other image). Make sure no part of the ball is no longer visible after it hits the top of the screen.
  2. Write a program that makes a rectangle move from left to right across the middle of the screen. When it hits the right edge of the screen make the rectangle wrap-around to the left side.
  3. Modify the version of the program that introduces dy so that the speed of the ball depends on the value of mouseY. Using the map function, map the value of mouseY into the range 0 to 10. This will make the ball go fast when the pointer is near the bottom of the screen, and slow when it is near the top (the ball stops moving completely when the pointer is at the very top of the screen).
  4. Modify the version of the program that introduces dy so that when the ball hits the bottom of the screen it bounces up, and when it hits the top of the screen it bounces down.
  5. Modify the version of the program that introduces dy so that when the ball hits the bottom of the screen it turns into a frog and stays sitting at the bottom. You will, of course, need to find (or make) an image of a frog to answer this question.