Week 15: Animation in Processing

Class notes: week 15

This week, we'll cover how animation works in Processing. The basic idea is that you define a function that is called every time a frame is drawn. Processing automatically manages the loop that repeatedly draws frames, and at the same time processes any events that result from user interaction (like mouse movements or clicks, or key presses).

We'll discuss how to define your own functions in detail later, but for now we'll start with two special functions used by processing:

// Animation basics.

// This function is called once at program start.
void setup() {
    size(300, 300);
    // Set drawing style for all future frames.
    fill(0, 0, 255);
    noStroke();
}

// This function is called once per frame.
void draw() {
    // Clear to a new green background.
    background(0, 255, 0);
    // Calculate a new diameter.
    // The frameCount variable counts the number
    // of frames that have been drawn.
    float diam = 100 * (1 + sin(frameCount / 60.0));
    ellipse(width/2, height/2, diam, diam);
}

Exercises:

  • Make the center of the circle also move around.

    // Animation basics.
    
    // This function is called once at program start.
    void setup() {
        size(300, 300);
        // Set drawing style for all future frames.
        fill(0, 0, 255);
        noStroke();
    }
    
    // This function is called once per frame.
    void draw() {
        // Clear to a new green background.
        background(0, 255, 0);
        // Calculate a new diameter.
        // The frameCount variable counts the number
        // of frames that have been drawn.
        float diam = 100 * (1 + sin(frameCount / 60.0));
        // "%" is modulus operator: result is remainder
        // after dividing by width.
        float x = frameCount % width;
        float y = height/2;
        ellipse(x, y, diam, diam);
    }
    
  • What happens if you remove the background call?

    // Animation basics.
    
    // This function is called once at program start.
    void setup() {
        size(300, 300);
        // Set drawing style for all future frames.
        fill(0, 0, 255);
        stroke(255, 0, 0);
        strokeWeight(3);
        //noStroke();
    }
    
    // This function is called once per frame.
    void draw() {
        // Clear to a new green background.
        //background(0, 255, 0);
        // Calculate a new diameter.
        // The frameCount variable counts the number
        // of frames that have been drawn.
        float diam = 100 * (1 + sin(frameCount / 60.0));
        ellipse(width/2, height/2, diam, diam);
    }
    

Interaction

Processing provides several special variables and functions for detecting interactions. See the Input section of the Processing reference for all the details.

Here's a simple drawing program that makes use of the mouse:

// Simple drawing program.

// This function is called once at program start.
void setup() {
    size(300, 300);
    fill(0);
}

// This function is called once per frame.
void draw() {
    // Note that we don't clear the frame.
    if (mousePressed) {
        ellipse(mouseX, mouseY, 5, 5);
    }
}

Exercises:

  • Have the drawing be connected lines rather than dots.

    // Simple drawing program.
    
    // This function is called once at program start.
    void setup() {
      size(300, 300);
      fill(0);
    }
    
    // This function is called once per frame.
    void draw() {
      // Note that we don't clear the frame.
      // Use if statement to draw circle only
      // if mousePressed is true.
      if (mousePressed) {
        line(pmouseX, pmouseY, mouseX, mouseY);
      }
    }
    
  • Use key presses to change colors.

    // Simple drawing program.
    
    // This function is called once at program start.
    void setup() {
      size(300, 300);
      fill(0);
    }
    
    // This function is called once per frame.
    void draw() {
      if (key == 'r') {
        stroke(255, 0, 0);
      } else if (key == 'g') {
        stroke(0, 255, 0);
      } else if (key == 'b') {
        stroke(0, 0, 255);
      } else {
        stroke(0);
      }
    
      // Note that we don't clear the frame.
      // Use if statement to draw circle only
      // if mousePressed is true.
      if (mousePressed) {
        line(pmouseX, pmouseY, mouseX, mouseY);
      }
    }
    
    // Simple drawing program.
    
    // This function is called once at program start.
    void setup() {
      size(300, 300);
      fill(0);
      strokeWeight(5);
    }
    
    // This function is called once per frame.
    void draw() {
      // Change color based on mouse movement.
      // Compute distance traveled since last
      // frame.
      float d = dist(pmouseX, pmouseY,
        mouseX, mouseY);
      // Set color based scaled distance.
      stroke(d * 5);
    
      // Note that we don't clear the frame.
      // Use if statement to draw circle only
      // if mousePressed is true.
      if (mousePressed) {
        line(pmouseX, pmouseY, mouseX, mouseY);
      }
    }
    

Motion

To represent moving objects, we'll use variables to keep track of location, and possibly also velocity.

// Bouncing ball.

// Ball position.
float pX, pY;
// Ball velocity (in units of pixels/frame).
float vX, vY;

float diam = 30;

// This function is called once at program start.
void setup() {
    size(300, 300);
    // Set drawing style for all future frames.
    fill(0, 0, 255);
    noStroke();
    // Initialize position.
    pX = width/2;
    pY = width/2;
    // Initialize velocity to random value.
    vX = random(10);
    vY = random(10);

}

// This function is called once per frame.
void draw() {
    // Clear to a new green background.
    background(0, 255, 0);
    // Update ball position.
    pX = pX + vX;
    pY = pY + vY;
    // Bouncing means velocity is reversed.
    // Check to see if it hits left or right side.
    if (pX + diam/2 > width || pX - diam/2 < 0)
        vX = -vX;
    // Check to see if it hits top or bottom.
    if (pY + diam/2 > height || pY - diam/2 < 0)
        vY = -vY;
    // Draw ball.
    ellipse(pX, pY, diam, diam);
}

Exercises:

  • Add gravity!

    // Bouncing ball.
    
    // Ball position.
    float pX, pY;
    // Ball velocity (in units of pixels/frame).
    float vX, vY;
    
    // Acceleration due to gravity.
    // (Change in vY in pixels/frame per frame).
    float g = 0.5;
    float diam = 30;
    
    // This function is called once at program start.
    void setup() {
      size(300, 300);
      // Set drawing style for all future frames.
      fill(0, 0, 255);
      noStroke();
      // Initialize position.
      pX = width/2;
      pY = width/2;
      // Initialize velocity to random value.
      vX = random(10);
      vY = 0;
    }
    
    // This function is called once per frame.
    void draw() {
      // Clear to a new green background.
      background(0, 255, 0);
      // Update ball position.
      pX = pX + vX;
      pY = pY + vY;
      // Bouncing means velocity is reversed.
      // Check to see if it hits left or right side.
      if (pX + diam/2 > width || pX - diam/2 < 0) {
        vX = -vX;
      }
      // Check to see if it hits top or bottom.
      if (pY + diam/2 > height || pY - diam/2 < 0) {
        vY = -vY;
      } else {
        // Acceleration due to gravity.
        vY = vY + g;
      }
      // Draw ball.
      ellipse(pX, pY, diam, diam);
    }
    
  • Add a user-controlled paddle (think Pong, or perhaps Circus Atari).

    // Bouncing ball.
    
    // Ball position.
    float pX, pY;
    // Ball velocity (in units of pixels/frame).
    float vX, vY;
    
    float diam = 30;
    
    // This function is called once at program start.
    void setup() {
      size(300, 300);
      // Set drawing style for all future frames.
      fill(0, 0, 255);
      noStroke();
      // Initialize position.
      pX = width/2;
      pY = width/2;
      // Initialize velocity to random value.
      vX = random(5);
      vY = random(5);
    }
    
    float paddleX = 280;
    float paddleHeight = 40;
    // This function is called once per frame.
    void draw() {
      // Clear to a new green background.
      background(0, 255, 0);
      // Update ball position.
      pX = pX + vX;
      pY = pY + vY;
      // Bouncing means velocity is reversed.
      // Check to see if it hits left or right side.
      if (pX + diam/2 > width || pX - diam/2 < 0)
        vX = -vX;
      // Check to see if it hits top or bottom.
      if (pY + diam/2 > height || pY - diam/2 < 0)
        vY = -vY;
    
      if (pX + diam/2 > paddleX
        && (pY >= mouseY && pY <= mouseY + paddleHeight)) {
        vX = -vX;
      }
      // Draw ball.
      ellipse(pX, pY, diam, diam);
    
      // Draw paddle
      rect(paddleX, mouseY, 10, paddleHeight);
    }
    

Readings

Read chapter 7 in Getting Started with Processing. Run the examples as you go through. The examples can be loaded directly from the Processing environment by looking in the File/Examples menu.