Week 16: Objects and arrays

Class notes: week 16

Functions

We've already been defining a few special functions in our Processing programs. Those were just special cases of a general way to allow reuse of a group of statements. The following updated version of an example from last week uses a function to wrap up some of the calculations:

// Animation basics, using functions.

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

// Define circle diameter as a function of
// time (in seconds).
float diam(float time) {
  float maxDiam = 100;
  // Using sin wave with period 1.
  return maxDiam/2 * (1 + sin(time * PI * 2));
}

// This function is called once per frame.
void draw() {
    // Clear to a new green background.
    background(0, 255, 0);
    // Calculate a new diameter.
    // Compute diameter for current time.
    // millis() gives number of milliseconds since
    // program start.
    float seconds = millis() / 1000.0;
    float d  = diam(seconds);
    ellipse(width/2, height/2, d, d);
}

// Another special function called by
// processing whenever the mouse is clicked.
void mouseClicked() {
  println("Click!");
}

Exercises:

  • Modify the program so that whenever you click the mouse, the circle moves to the click location.
// Animation basics, using functions.

class Click {
  float x;
  float y;
  Click(float x0, float y0) {
    move(x0, y0);
  }
  void move(float x0, float y0) {
    x = x0;
    y = y0;
  }
}

// This function is called once at program start.
void setup() {
    size(300, 300);
    smooth();
    // Set drawing style for all future frames.
    fill(0, 0, 255);
    noStroke();
    click = new Click(width/2, height/2);
}

// Define circle diameter as a function of
// time (in seconds).
float diam(float time) {
  float maxDiam = 200;
  // Using sin wave with period 1.
  return maxDiam/2 * (1 + sin(time * PI * 2));
}

// Center of circle.
Click click;

// This function is called once per frame.
void draw() {
    // Clear to a new green background.
    background(0, 255, 0);
    // Calculate a new diameter.
    // Compute diameter for current time.
    // millis() gives number of milliseconds since
    // program start.
    float seconds = millis() / 1000.0;
    float d  = diam(seconds);
    ellipse(x, y, d, d);
}

// Another special function called by
// processing whenever the mouse is clicked.
void mouseClicked() {
  x = mouseX;
  y = mouseY;
}

Objects

Up to now we've worked with variables that represent individual numbers or single boolean values. With more complex programs that manage more data, we'll need a way to refer to a large collection of numbers or other data types all at once.

// Bouncing ball.

class Ball {
  // Position
  float x, y;
  // Velocity
  float vx, vy;

  // Ball diameter
  float diam = 30;

  // Constructor defines how object is initialized.
  Ball(float x0, float y0, float vx0, float vy0) {
    x = x0;
    y = y0;
    vx = vx0;
    vy = vy0;
  }

  // Our program will call the update() method
  // each frame to update object state.
  void update() {
    // Update ball position.
    x = x + vx;
    y = y + vy;
    // Bouncing means velocity is reversed.
    // Check to see if it hits left or right side.
    if (x + diam/2 > width)
      vx = -abs(vx);
    if (x - diam/2 < 0)
      vx = abs(vx);

    // Check to see if it hits top or bottom.
    if (y + diam/2 > height)
      vy = -abs(vy);
    if (y - diam/2 < 0)
      vy = abs(vy);
  }

  // Our program will call the draw() method
  // each frame to draw the ball.
  void draw() {
    // Draw ball.
    ellipse(x, y, diam, diam);
  }
}

Ball ball;

// This function is called once at program start.
void setup() {
  size(300, 300);
  smooth();
  // Set drawing style for all future frames.
  fill(0, 0, 255);
  noStroke();
  // Initialize ball
  ball = new Ball(width/2, height/2,
    random(10), random(10));
}

// This function is called once per frame.
void draw() {
  // Clear to a new green background.
  background(0, 255, 0);
  ball.update();
  ball.draw();
}

Exercises:

  • Modify the program so that there is more than 1 ball.
// Bouncing ball.

class Ball {
  // Position
  float x, y;
  // Velocity
  float vx, vy;

  // Ball diameter
  float diam = 30;

  // Constructor defines how object is initialized.
  Ball(float x0, float y0, float vx0, float vy0) {
    x = x0;
    y = y0;
    vx = vx0;
    vy = vy0;
  }

  // Our program will call the update() method
  // each frame to update object state.
  void update() {
    // Update ball position.
    x = x + vx;
    y = y + vy;
    // Bouncing means velocity is reversed.
    // Check to see if it hits left or right side.
    if (x + diam/2 > width)
      vx = -abs(vx);
    if (x - diam/2 < 0)
      vx = abs(vx);

    // Check to see if it hits top or bottom.
    if (y + diam/2 > height)
      vy = -abs(vy);
    if (y - diam/2 < 0)
      vy = abs(vy);
  }

  // Our program will call the draw() method
  // each frame to draw the ball.
  void draw() {
    // Draw ball.
    ellipse(x, y, diam, diam);
  }
}

Ball ball;
Ball ball2;

// This function is called once at program start.
void setup() {
  size(300, 300);
  smooth();
  // Set drawing style for all future frames.
  fill(0, 0, 255);
  noStroke();
  // Initialize balls
  ball = new Ball(width/2, height/2,
    random(10), random(10));
  ball2 = new Ball(width/2, height/2,
    random(10), random(10));
}

// This function is called once per frame.
void draw() {
  // Clear to a new green background.
  background(0, 255, 0);
  ball.update();
  ball.draw();
  ball2.update();
  ball2.draw();
}

Arrays

The final piece we need in order to build large programs is to be able to manage large collections of data. To do that, we just define an array, which is just a list whose entries are all the same type.

// Array basics

// First way to define an array:
// Rectangle sizes.
float[] sizes = {
  10, 20, 30, 40, 50, 60, 70, 80, 90, 100
};

// Declare, but don't define:
// Rectangle positions.
float[] x;
float[] y;

void setup() {
  size(300, 300);
  smooth();

  // Second way to define an array:
  // Initialize position arrays, creating
  // new arrays of same size as sizes.
  x = new float[sizes.length];
  y = new float[sizes.length];
  // Set each element of arrays to random values.
  for (int i = 0; i < x.length; i = i + 1) {
    x[i] = random(width);
  }
  for (int i = 0; i < y.length; i = i + 1) {
    y[i] = random(height);
  }
}

void draw() {
  // Draw all rectangles.
  for (int i = 0; i < x.length; i = i + 1) {
    rect(x[i], y[i], sizes[i], sizes[i]);
  }
}

Exercises:

  • Reorganize the example so that it uses a single array (of a data type you define).

    // Array basics
    
    class Square {
      // Side length.
      float size;
      // Coords for top left corner.
      float x;
      float y;
      // Fill color.
      color col;
    
      Square() {
        x = random(width);
        y = random(height);
        size = random(200);
        col = color(random(255), random(255),
          random(255));
      }
    
      void draw() {
        fill(col);
        rect(x, y, size, size);
      }
    }
    
    Square[] squares;
    
    void setup() {
      size(300, 300);
      smooth();
    
      squares = new Square[100];
      for (int i = 0; i < squares.length; i = i + 1) {
        squares[i] = new Square();
      }
    }
    
    void draw() {
      // Draw all squares:
      for (Square s : squares) {
        s.draw();
      }
    }
    
  • Modify the ball example so that there are 1000 balls bouncing around.

  • Modify the ball example again so that the 1000 balls can be of different sizes.

Readings

Read chapter 8-10 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.