PROCESSING
BOUNDS CHECKING AND FLOW CONTROL
We'll pickup with the code we wrote in the last tutorial to define some basic behaviors for our ball.
01
02
03
04
05
06
07
08
09
10
11
12
13
int x;

void setup(){
   size(500,500); 
   smooth();
   x = 50;
}

void draw(){
   background(200,200,200);
   ellipse(x,50,30,30);
   x+=1;
}
Lets first make it bounce off the wall instead of traveling indefinitely.
To start we need to test for a specific condition, in this case whether our ball has gone past our right size. Since our window is 500 pixels wide we have a specific value we can check against: if our x value is greater than our width.

To do this we'll use a conditional statement which is a way to phrase a question or check to see if a specific condition is true or false.
01
02
03
if(x > 500){
    // the above is true, do something
}
One convenience that Processing has is built in variables for our screen width and height, so instead of "hard coding" or explicitly setting our width, we can use the width variable to check against:
01
02
03
if(x > width){
    // the above is true, do something
}    
You'll notice it turns blue when we write width -- thats a good sign that processing knows of that specific keyword.

Using width is also helpful in the case we want to change our window size, we don't need to go throughout our code and updating the values we are checking against.

Finally, just to cover some other options with conditionals:
01
02
03
04
05
06
07
if(x > width){
    // the above is true, do something
}else if(x < 0){
    // our x value is not greater than width but is less than 0!
}else{
    // the two conditions above are false, do something else
}    
So as you can see above conditionals can be chained to control the flow of our program. If we put the above in our draw function with some appropriate actions to deal with the specific conditions, we can being to develop a more dynamic animation.
Now that we've established a basic way to check whether we've lost our ball past the right edge, lets implement it:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
int x;

void setup(){
   size(500,500); 
   smooth();
   x = 50;
}

void draw(){
   background(200,200,200);
   ellipse(x,50,30,30);
   x+=1;

   if(x > width){
      println("our ball is offscreen!");
   }
}
Once the ball goes off screen, the conditional (x > width) evaluates true and we get our println statement.

Now that we are getting the correct behavior - we can look to invert the direction of our ball so that it "bounces" off the wall.
Lets create a couple new variables so that we can invert the speed and deal with a small detail of how the ellipse is drawn:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int x;
int r; // radius
int direction;
int speed;

void setup(){
   size(500,500); 
   smooth();
   x = 50;
   r = 15;
   speed = 1;
   direction = 1;
   ellipseMode(CENTER);
}

void draw(){
   background(200,200,200);
   ellipse(x,50,r*2,r*2);
   x+=(speed * direction);

   // our x position (which is in the center)
   // plus our radius to achieve the right edge
   if(x+r > width){ 
      direction = -1;
   }
}
I first created three new integer (int) variables: a radius (r) and direction and a speed variable which we could use later to turn up or down how fast our ball moves per frame.

In our setup, we can give them some initial values.

I also added ellipseMode(CENTER); for a clearer way to check the boundary of our ball. by default x andy y positions are drawn from the top left (so 0,0 is at the top left of the screen) the same applies to shapes drawn, so the origin of our ellipse is the top left corner. By setting ellipseMode to CENTER we can specify processing to define the origin at the center of our ellipse.

If we run our code we should see our ball animate over to the right, hit the right boundary, and head back [indefinitely the other direction :) ]
Lets add in what we learned earlier about chaining conditionals to account for the left edge as well.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int x;
int r; // radius
int direction;
int speed;

void setup(){
    size(500,500); 
    smooth();
    x = 50;
    r = 15;
    speed = 1;
    direction = 1;
    ellipseMode(CENTER);
}

void draw(){
    background(200,200,200);
    ellipse(x,50,r*2,r*2);
    x+=(speed * direction);

    if(x+r > width){ 
        direction = -1;
    }else if(x-r < 0){
        direction = 1;
    }
}
Now that we've established this logic, we can easily add the top and bottom boundary as well by introducing a few more variables:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
int x;
int y;
int r; // radius
int direction_x;
int direction_y;
int speed;

void setup(){
    size(500,500); 
    smooth();
    x = 50;
    y = 50;
    r = 15;
    speed = 1;
    direction_x = 1;
    direction_y = 1;
    ellipseMode(CENTER);
}

void draw(){
    background(200,200,200);
    ellipse(x,y,r*2,r*2);

    x+=(speed * direction_x);
    y+=(speed * direction_y);

    if(x+r > width){ 
        direction_x = -1;
    }else if(x-r < 0){
        direction_x = 1;
    }

    if(y+r > height){
       direction_y = -1;
    }else if(y-r < 0){
       direction_y = 1; 
    }
}
Since our ball's origin point is x=50 y=50 we're going to get the same result every run and it'll be stuck bouncing form corner to corner.

We can introduce randomness to our sketch to get a new and variable result with each run. simply set our x and y to random origin points:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
int x;
int y;
int r; // radius
int direction_x;
int direction_y;
int speed;

void setup(){
    size(500,500); 
    smooth();
    x = int(random(0,width));
    y = int(random(0,height));
    r = 15;
    speed = 1;
    direction_x = 1;
    direction_y = 1;
    ellipseMode(CENTER);
}

void draw(){
    background(200,200,200);
    ellipse(x,y,r*2,r*2);

    x+=(speed * direction_x);
    y+=(speed * direction_y);

    if(x+r > width){ 
        direction_x = -1;
    }else if(x-r < 0){
        direction_x = 1;
    }

    if(y+r > height){
       direction_y = -1;
    }else if(y-r < 0){
       direction_y = 1; 
    }
}
The random function we added works by returning a number in the range from (minimum,maximum).

Setting it to 0,width for instance will give us a number along our x axis between the left and right edges. We need to wrap it with a int() because the number random returns is a float, and our x and y variables are set to be integers. If we don't type cast (convert from one type of variable to the other) we'll run into errors when we run our code.

A final note -- if we want to nitpick -- we should really be asking for a range between the left wall + our radius and the right wall - our radius:
01
02
03
04
05
    
// ... in the setup function
x = int(random(r,(width-r)));
y = int(random(r,(height-r)));
// ... rest of our code
To finish up lets tweak the style slightly. We can use random to set the fill color of our circle once in the setup (if we did it in our draw we'd get a strobing effect) and set our background color to something a bit darker. Also, lets speed it up a bit:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
int x;
int y;
int r; // radius
int direction_x;
int direction_y;
int speed;

void setup(){
    size(500,500); 
    smooth();
    x = int(random(r,(width-r)));
    y = int(random(r,(height-r)));
    r = 15;
    speed = 5;
    direction_x = 1;
    direction_y = 1;
    ellipseMode(CENTER);

    fill(random(0,255),random(0,255),random(0,255));
}

void draw(){
    background(100,100,100);
    ellipse(x,y,r*2,r*2);

    x+=(speed * direction_x);
    y+=(speed * direction_y);

    if(x+r > width){ 
        direction_x = -1;
    }else if(x-r < 0){
        direction_x = 1;
    }

    if(y+r > height){
       direction_y = -1;
    }else if(y-r < 0){
       direction_y = 1; 
    }
}
In the next tutorial we'll take a break from animating objects to look at interactivity.