Source Code. Projects. Nerd Stuff. Art Stuff.

Lesson 8: Arrays

[gn_pullquote align="left"]An array is a list of variables that share a common name. Arrays are useful because they make it possible to work with more variables without creating a new name for each. This makes the code shorter, easier to read, and more convenient to update.[/gn_pullquote]

Suppose we want to create a shape. We might define the vertices, lines arc, and so on. Suppose we wanted two of the same shape. We might write this:

  float x1 = -2;
  float x2 = 20;

  void setup() {
    size(240, 120);
    smooth();
    noStroke();
  }

  void draw() {
    background(0);
    x1 += 0.5;
    x2 += 0.5;
    arc(x1, 30, 40, 40, 0.52, 5.76);
    arc(x2, 90, 40, 40, 0.52, 5.76);
  }

 

This code seems manageable, but what if we wanted five circles? Or a hundred? Or three thousand? We would have to create a variable for each shape, and update each one separately. This would be too difficult to keep track of. This is where an array comes in handy:

  float[] x = new float[3000];

  void setup() {
    size(240, 120);
    smooth();
    noStroke();
    fill(255, 200);
    for (int i = 0; i < x.length; i++) {
      x[i] = random(-1000, 200);
    }
  }

  void draw() {
    background(0);
    for (int i = 0; i < x.length; i++) {
      x[i] += 0.5;
      float y = i * 0.4;
      arc(x[i], y, 12, 12, 0.52, 5.76);
    }
  }

 

Let’s examine the details of how this works.

Make an array

Each item in an array is called an element, and each element has an index value to mark its position within the array. Just like coordinates on the screen, index values for an array start counting from 0. For instance, the first element in the array has the index value 0, the second element in the array has the index value 1, and so on. If there are 20 values in the array, the index value of the last element is 19.

Using arrays is similar to working with single variables; it follows the same patterns. As we already know, we can make a single integer variable called x with this code:

1
int x;

To make an array, just place brackets after the data type:

1
int[] x;

The beauty of creating an array is the ability to make 2, 10, or 100,000 variable values with only one line of code. For instance, the following line creates an array of 2,000 integer variables:

1
int[] x = new int[2000];

You can make arrays from all Processing data types: boolean, float, String, PShape, and so on, as well as any user-defined classes. For example, the following code creates an array of 32 PImage variables:

1
PImage[] images = new PImage[32];

NOTE: Each array can store only one type of data (boolean, int, float, PImage, etc.). You can’t mix and match different types of data within a single array. If you need to do this, work with objects instead.

Like making an object, there are three steps to working with an array:

  1. Declare the array and define the data type.
  2. Create the array with the keyword new and define the length.
  3. Assign values to each element.

Each step can happen on its own line, or all the steps can be compressed together. Each of the three following examples shows a different technique to create an array called x that stores two integers, 12 and 2. Pay close attention to what happens before setup() and what happens within setup().

Option 1: Declare and Assign an Array

First we’ll declare the array outside of setup() and then create and assign the values within. The syntax x[0] refers to the first element in the array and x[1] is the second:

  int[] x;          // Declare the array

  void setup() {
    size(200, 200);
    x = new int[2];
    x[0] = 12;
    x[1] = 2;
  }

 

Option 2: Compact Array Assignment

Here’s a slightly more compact example, in which the array is both de- clared and created on the same line, then the values are assigned within setup():

  int[] x = new int[2];    // Declare and create the array

  void setup() {
    size(200, 200);
    x[0] = 12;
    x[1] = 2;
  }

 

Option 3: Assigning to an Array in One Go

You can also assign values to the array when it’s created, if it’s all part of a single statement:

int[] x = {12, 2};  // Declare, create and assign
void setup() {
size(200, 200);
}

 

NOTE: Avoid creating arrays within draw(), because creating a new array on every frame will slow down your frame rate.

Repetition and Arrays

The for() loop makes it easier to work with large arrays while keeping the code concise. The idea is to write a loop to move through each element of the array one by one. To do this, you need to know the length of the array. The length field associated with each array stores the number of elements. We use the name of the array with the dot operator (a period) to access this value. For instance:

  int[] x = new int[2];      // Declare and create the array
  println(x.length);         // Prints 2 to the console

  int[] y = new int[1972];      // Declare and create the array
  println(y.length);               // Prints 1972 to the console

 

A for loop can be used to fill an array with values, or to read the values back out. In this example, the array is first filled with random numbers inside setup(), and then these numbers are used to set the stroke value inside draw(). Each time the program is run, a new set of random num- bers is put into the array:

  float[] gray;

  void setup() {
    size(240, 120);
    gray = new float[width];
    for (int i = 0; i < gray.length; i++) {
      gray[i] = random(0, 255);
    }
  }

  void draw() {
    for (int i = 0; i < gray.length; i++) {
      stroke(gray[i]);
      line(i, 0, i, height);
    }
  }

 

Track Mouse Movements

Here, there are two arrays to store the position of the mouse—one for the x-coordinate and one for the y-coordinate. These arrays store the location of the mouse for the previous 60 frames. With each new frame, the oldest x- and y-coordinate values are removed and replaced with the current mouseX and mouseY values, and at each frame, all 60 coordinates are used to draw a series of ellipses to the screen. The new values are added to the first position of the array, but before this happens, each value in the array is moved one position to the right (from back to front) to make room for the new numbers. This example visualizes this action.

  int num = 60;
  int x[] = new int[num];
  int y[] = new int[num];

  void setup() {
    size(240, 120);
    smooth();
    noStroke();
  }

  void draw() {
    background(0);
    // Copy array values from back to front
    for (int i = x.length; i > 0; i--) {
      x[i] = x[i-1];
      y[i] = y[i-1];
    }
    x[0] = mouseX; // Set the first element
    y[0] = mouseY; // Set the first element
    for (int i = 0; i < x/length; i++) {
      fill(i * 4);
      ellipse(x[i], y[i], 40, 40);
    }
  }

 

NOTE: The technique for storing a shifting buffer of numbers in an array shown in this example and Figure 10-2 is less efficient than an alterna- tive technique that uses the % (modulo) operator. This is explained in the Examples -> Basics -> Input -> StoringInput example included with Processing.

Arrays of Objects

The next example brings together every major programming concept we’ve covered so far: variables, iteration, conditionals, functions, objects, and arrays. Making an array of objects is nearly the same as making the arrays we introduced in previous examples, but there’s one additional consideration: because each array element is an object, it must first be created with the keyword new (like any other object) before it is assigned to the array. With a custom-defined class such as JitterBug (see the lesson on Objects), this means using new to set up each element before it’s assigned to the array. Or, for a built-in Processing class such as PImage, it means using the loadImage() function to create the object before it’s assigned.

  JitterBug[] bugs = new JitterBug[33];

  void setup() {
    size(240, 120);
    smooth();
    for (int i = 0; i < bugs.length; i++) {
      float x = random(width);
      float y = random(height);
      int r = i + 2;
      bugs[i] = new JitterBug(x, y, r);
    }
  }

  void draw() {
    for (int i = 0; i < bugs.length; i++) {
      bugs[i].move();
      bugs[i].display();
    }
  }

  // Copy JitterBug class here