11.1 – Intro to Arrays

Before we get into arrays- a few more things about objects.

When your class uses an image, you still need to load that image in your main program’s setup.  You can pass in the image as an argument when you create your object.

MyImage newImageObject;
PImage theImageIWantToDisplay;

void setup() {
  size(400, 400);
  theImageIwantToDsiplay = loadImage("photo.jpg");
  newImageObject = new MyImage(theImageIWantToDisplay);
}

void draw() {
  background(0);
  newImageObject.display();
}
class MyImage {
  PImage theImage;

  MyImage(PImage tempImage) {
    theImage = tempImage;
  } 

  void display() {
    image(theImage, mouseX, mouseY, 100, 100);
  }
}

You’re also going to run into situations when a class needs to know about another object. An example of this is collision testing. If we go back to the example from a few weeks ago, where we test a ball hitting a right paddle, we can think about breaking down our program into two classes- a ball and a paddle.

Since there are two paddles and potentially multiple balls, the collision function should be in the ball class (so that we only have to pass the paddle into the ball, rather than ALL the balls into the paddle).

The rect class is straight forward:

class MyRect {
  int x;
  int y;
  int w;
  int h;

  MyRect() {
    w = 10;
    h = 200;
    x = width - 20;
  }

  void display(){
    y = mouseY; //why does this need to be in display?
    rect(x, y, w, h);
  }
}

The ball class is a straight forward as well, however we’re going to re-write our collision function. We used to pass in the two shape’s w,h,x, and y like this:

boolean collision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2) {
  if (x1 + w1 > x2 && y1 > y2 && y1 < y2 + h2) {
    println("collision");
    return true;
  }
  else {
    return false;
  }
}

Since the ball class already knows the ball’s x, y, w, and h, we not longer need to pass that in. All we need to pass in is a rect object. We then have access to the rect’s w, h, x, and y.

 boolean collision(MyRect theRect) {
    if (ballx + ballw > theRect.x && bally > theRect.y && bally < theRect.y + theRect.h) {
      return true;
    }
    else {
      return false;
    }
  }

Isn’t this so much easier to read than the previous function? We can put the whole ball class together like so:

class MyBall {
  int ballx;
  int bally;
  int ballw;
  int ballh;
  int speed;

  MyBall(int tempSpeed) {
    ballx = 0;
    bally = 100;
    speed = tempSpeed;

    ballw = 50;
    ballh = 50;
  }

  void display() {
    ellipse(ballx, bally, ballw, ballh);
  }

  void move() {
    ballx += speed;
  }

  void bounce(){
   speed = speed * -1; 
  }

  boolean collision(MyRect theRect) {
    if (ballx + ballw > theRect.x && bally > theRect.y && bally < theRect.y + theRect.h) {
      return true;
    }
    else {
      return false;
    }
  }
}

Our main program is pretty straightforward:

MyBall ball;
MyRect paddle;

void setup() {
  size(400, 400);
  paddle = new MyRect();
  ball = new MyBall(10);
}

void draw() {
  background(0);
  paddle.display();
  ball.display();
  ball.move();
  if (ball.collision(paddle)) { //
    ball.bounce();
  }
}

**Note that when we call ball.collision we PASS in the paddle object as its argument**

Also it will work easily for multiple balls. We can have as many balls as we want and know when they’re colliding with the paddle:

//Ball and Rect class stay the same
MyBall ball;
MyBall ball2;
MyRect paddle;

void setup() {
  size(400, 400);
  paddle = new MyRect();
  ball = new MyBall(10);
  ball2 = new MyBall(3);
}

void draw() {
  background(0);
  paddle.display();
  ball.display();
  ball.move();
  ball2.display();
  ball2.move();
  if (ball.collision(paddle)) {
    ball.bounce();
  }
   if (ball2.collision(paddle)) {
    ball2.bounce();
  }
}

This is a great time to move into our discussion about Arrays.

In the above example, if we wanted to make multiple instances of an object, we’d have to write them all out one by one. If we wanted to have hundreds or thousands of balls we can see how this would get real tedious, real fast. The magical solution is a new programming concept known as Arrays.

We already know that a variable is a named pointer to a location in memory where data is stored. Variables allow a program to keep track of information over a period of time. An array is the same idea, except it points to multiple pieces of information.

An array is a list of variables. They must all be of the same type (a list of int’s, a list of floats, NOT a list of floats AND ints). Think of an array like a big filing cabinet  Each drawer holds one object, and it keeps track of that object. It also remembers the order that you stored your objects. This is in an important point – in many programs the order of information is just as important as the information itself.

Every object has an index– the “number” that tells you which drawer it’s stored in. Officially, an index is an integer value that designates its position in the list. The name of the array refers to the list as a whole (the whole filing cabinet). Each element is accessed via its index position.

A very important note – Index’s start counting at 0, not 1! If you have an array that holds 100 objects, the index will go from 0 – 99.

When do you use an array? Any time a program requires multiple instances of similar data. Like 4 players scores, 10 different colors used in a design program, a list of fish objects in an aquarium simulation, the days per month in a scheduling program.

Declaring and Creating an Array

We already know that all variables must have a name and a data type. Arrays are no different, but the declaration statement looks different. We denote the array by placing empty square brackets [] after the type.

int [] arrayOfInts;

(Note- You can name your array anything you want. Here I am using the word ‘array’ to demonstrate a point, but array names are not required to have the word ‘array’ in them).

At this point you’ve said that there’s an array made of integers and it’s called arrayOfInts. You have not yet declared how many int’s are in the array.

A fundamental property of arrays is that they’re of a fixed size. Once we define the size of the array it can never change. The reason goes back to memory management – Processing needs to know how much memory to devote to holding onto your array. But don’t worry about that- think of it like needing to decide how many drawers are going to be in your filing cabinet when you build it. You can’t add another drawer after you’ve built your filing cabinet.

How do we say how large the array should be?

int [] arrayOfInts = new int [42];

This array will hold 42 int’s. You should recognize the word ‘new’ from when we made objects. This is what initializes your array. The size always has to be an int, however you can send it a hard coded value, a variable, or the result of an expression as long as it evaluates to an int. You cannot change the size after you declare it.

So we made our filing cabinet, bow we need to put things inside of the drawers.

We can open up each drawers one by one:

int [] stuff = new int [3];

stuff[0] = 8; // The first element of the array equals 8

stuff[1] = 3; // The second element of the array equals 3

stuff[2] = 1; // The third element of the array equals 1

Or, we can add them all at once using curly brackets and commas-

int[] arrayOfInts = {1, 5, 8, 9, 4, 5};

Note, in this example, we don’t need to tell it the size of the array. Processing will count the number of items you’re adding and automatically create an array big enough to hold them all.

Frankly though, neither of these options are common and you won’t really see them again after this example. The point of an array is to be able to store hundreds, thousands, or hundred of thousands. Like a repetitive task that can be done over and over again. Something should be jumping out at you right now
.. LOOPS!

For loops and arrays are natural partners. You have a list, you need to cycle through that list.

Let’s think of the follow problem– create an array of 1,000 floats, initialize each element of that array with a random number between 0 and 10.

float [] values = new float [1000];

This is what we want to avoid:

vales[0] = random(10);
values[1] = random(10);
values[2] = random(10);

We can rethink this problem- for every index number ‘n’ from 0 to 9999, initialize the nth element as a random value:

int n = 0;
values[n] = random(10);
values[n+1] = random(10);
values[n+2] = random(10);

Using the concept of ‘n’ to describe an array index should open up some doors for us. We’ve seen this kind of repitition before. We can use a while loop to repeat this task over and over again for us:

int n = 0;
    while (n

Or better yet, a for loop:

for (int n = 0; n < 1000; n++) {
      values[n] = random(0,10);
}

As good programmers, we should always be wary of hard coded numbers. What if we wanted to update this array to have 20,000 random numbers? We’d have to remember to change the bumber in the for loop as well. Luckily, Processing already knows how long our array is and we can use that built-in function as the exit condition for our loops. We access the length of an array through the “dot” operator we learned last week when we learned about objects– values.length

 for (int n = 0; n < 1000; n++) {
      values[n] = random(0,10);
}

A very common problem is trying to access an element in the array that doesn’t exist. Remember, we start counting our array index at 0. If we have an array with 100 items, the index goes from 0 to 99. If you try to acces values[100], you will get an error that says: ArrayIndexOutOfBoundsException

Here is an example of arrays in action. We’re going to generate lots and lots of random circles. We’ve been able to do this kind of animation before, however previously we lost the location of the ellipse every time a new one was made. In this instance, at any given frame, I am storing the x and y location of every single circle.

int [] xpos;
int [] ypos;

void setup() {
  size(400, 400);
  xpos = new int[1000]; //would be better to have a variable here
  ypos = new int[1000]; //would be better to have a variable here
 /*
--If we didn't want the random location to update every frame--
 for (int i = 0; i < xpos.length; i++) {
    xpos[i] = int(random(width));
  } 
  for (int i = 0; i < ypos.length; i++) {
    ypos[i] = int(random(height));
  }*/
}

void draw() {
  background(0);

   for (int i = 0; i < xpos.length; i++) {
   xpos[i] = int(random(width));
   } 
   for (int i = 0; i < ypos.length; i++) {
   ypos[i] = int(random(height));
   } 
   for (int i = 0; i < ypos.length; i++) { //what would happen if xpos and ypos were of different lengths?
   fill(255);
   ellipse(xpos[i], ypos[i], 20, 20);
   }

  //could be shortened to
 /* for (int i = 0; i < ypos.length; i++) {
    fill(255);
    xpos[i] = int(random(width));
    ypos[i] = int(random(height));
    ellipse(xpos[i], ypos[i], 20, 20);
  }*/
}

Next class we’re going to finally unlock the true power of OOP by creating arrays of objects.

Leave a Reply

Your email address will not be published. Required fields are marked *