In these notes you will learn:

- How to draw a multi-segment “snake” using an
`ArrayList`of objects. - How to delete an element in an
`ArrayList`. - How to generalize a class designed for a specific task.
- Make an object move randomly on its own.

In these notes, we’re going to look at a version of a program borrowed from the excellent book Learning Processing: A Beginner’s Guide to Programming Images, Animation, and Interaction. It draws a “snake” that follows the mouse pointer:

```
// The snake consist of a series of segments, i.e. circles.
class Segment {
float x, y;
Segment(float init_x, float init_y) {
x = init_x;
y = init_y;
}
} // class Segment
final int NUM_SEGMENTS = 50;
ArrayList<Segment> snake;
void setup() {
size(500, 500);
smooth();
// initialize all the segments
snake = new ArrayList<Segment>();
int i = 0;
while (i < NUM_SEGMENTS) {
Segment s = new Segment(0, 0);
snake.add(s);
++i;
}
}
void draw() {
background(255);
// remove the first segment, and shift all the other segments
// down one index position
snake.remove(0);
// add a new segment centered at the mouse
Segment s = new Segment(mouseX, mouseY);
snake.add(s);
// draw everything
int i = 0;
while (i < snake.size()) {
noStroke();
fill(255 - i * 5);
Segment t = snake.get(i);
ellipse(t.x, t.y, i, i);
++i;
}
}
```

This program draws a single snake that follows the mouse pointer. Now lets
create a `Snake` class so we can make more than one snake object:

```
class Segment {
float x, y;
Segment(float init_x, float init_y) {
x = init_x;
y = init_y;
}
} // class Segment
class Snake {
ArrayList<Segment> segment;
Snake(int numSegments) {
// initialize the snake's segments
segment = new ArrayList<Segment>();
int i = 0;
while (i < numSegments) {
Segment s = new Segment(0, 0);
segment.add(s);
++i;
}
}
void update() {
// remove the first segment, and shift all the other segments
// down one index position
segment.remove(0);
Segment s = new Segment(mouseX, mouseY);
segment.add(s);
}
void render() {
// draw everything
int i = 0;
while (i < segment.size()) {
noStroke();
fill(255 - i * 5);
Segment t = segment.get(i);
ellipse(t.x, t.y, i, i);
++i;
}
}
} // class Snake
Snake snake;
void setup() {
size(500, 500);
smooth();
snake = new Snake(50);
}
void draw() {
background(255);
snake.update();
snake.render();
}
```

Notice how simple the code in `setup` and `draw` is. This is common in
well-designed object-oriented programs: all the implementation details are in
the `Snake` object.

Now that we have the `Snake` class, we can draw multiple snakes on the
screen at the same time. Unfortunately, there is a problem: the `update`
function sets the snake’s head to be the location of the mouse pointer. Every
`Snake` will thus be drawn in the same place, which is not what we want.

So what we’ll we do is make a small modification to the `update()` function
that lets us pass in the position we want the next segment drawn at:

```
class Snake {
// ...
void update(float x, float y) {
// remove the first segment, and shift all the other segments
// down one index position
segment.remove(0);
Segment s = new Segment(x, y);
segment.add(s);
}
// ...
} // class Snake
```

Now when we call `update`, we need to pass in the position we want the
snake’s next segment to be drawn at:

```
Snake snake1, snake2;
void setup() {
size(500, 500);
smooth();
snake1 = new Snake(50);
snake2 = new Snake(50);
}
void draw() {
background(255);
snake1.update(mouseX, mouseY);
snake1.render();
snake2.update(500 - mouseX, 500 - mouseY);
snake2.render();
}
```

A subtle limitation of our code so far is that it only works for snakes with
about 50 segments in them. If you make a snake’s underlying segment
`ArrayList` much longer than 50, the visuals break down pretty severely.

The problem is in the `Snake` `render` function:

```
class Snake {
// ...
void render() {
// draw everything
int i = 0;
while (i < segment.size()) {
noStroke();
fill(255 - i * 5);
ellipse(segment.get(i).x, segment.get(i).y, i, i);
++i;
}
}
} // class Snake
```

Do you see the problems? There are two:

`fill(255 - i * 5)`does not work correctly if`i`is too big. The issue is that the value you give to`fill`must be between 0 and 255. In other words, this must be true for`fill`to work correctly:\begin{equation*} 0 \leq 255 - 5i \leq 255 \end{equation*}This says that the smallest value \(255 - 5i\) can have is 0, while the biggest value it can have is 255.

From the while-loop, we can see that

`i`is between 0 and 49 (`segment.size()`). So if`i`is 0, then \(255 - 5i = 255\) , which is a permissible input to`fill`. Similarly, if`i`is 49 (the highest possible value — one less than`segment.size()`), then \(255 - 5i = 255 - 5 \cdot 49 = 10\) which is, again, a legal value for`fill`.But suppose our snake as 100 segments. Then

`i`ranges from 0 to 99, and when it’s equal to 99 we have \(255 - 5i = 255 - 5 \cdot 99 = -240\) , which is*not*a legal`fill`value.One way to fix this is to use the

`map`function. Recall that`map`converts a value from one particular input range into a proportionally equivalent value in an output range. The value we are interested in here is`255 - i * 5`:float x = 255 - i * 5;

To use

`map`, we need to determine the range of`x`, i.e. we need to know its smallest and largest values. Lets determine the biggest value of`x`first. Note that if`i`is small, then`x`is big, and since the smallest value of`i`is 0 (thanks to the while-loop that controls it), the biggest possible value of`x`is \(255 - 5\cdot 0 = 255\) .To determine the smallest value of

`x`, we note that when`i`is big,`x`is small, and so the largest possible value of`i`is`segment.size() - 1`. Thus the largest possible value of the expression`255 - i * 5`is`255 - (segment.size() - 1) * 5`(`i`has just been replaced with its largest possible value).And so we now know the range of value of

`x`:255 - (segment.size() - 1) * 5 <= x <= 255 // input range

It’s ugly, but accurate!

The output range is 0 to 255 because we want to output of the call to

`map`to be fed into`fill`.Now we can finally rewrite our code so that the snake is colored correctly no matter how many segments it has:

float x = 255 - i * 5; float mx = map(x, 255 - (segment.size() - 1) * 5, 255, // input range 0, 255 // output range ); fill(mx);

Notice how we used indentation and comments to make the code easier to read.

The diameter of the ellipse is

`i`, which doesn’t work when`i`is too big. One way to solve this problem is, as for the fill color, to use`map`:float diam = map(i, 0, segment.size() - 1, // input range (i's range) 0, 50); // output range (diam's range) ellipse(segment.get(i).x, segment.get(i).y, diam, diam);

Lets try to make a snake that moves on its own. The simplest way to make
something move is as we have been doing throughout the course: increment the
`x` and `y` values of the position of the thing we want to move. Since our
snakes move by putting down new segments, to make a snake appear to move on
its own we must automatically decide where to put each new head segment.

The approach we’ll follow here is to make each new head segment be placed a little past the previous head segment. We’ll need to keep track of the previous head segment to do this:

```
Snake snake;
Segment prevHead;
void setup() {
size(500, 500);
smooth();
snake = new Snake(150);
prevHead = new Segment(0, 0);
}
void draw() {
background(255);
snake.update(prevHead.x + random(2.0), prevHead.y + random(2.0));
snake.render();
prevHead = snake.segment.get(snake.segment.size() - 1);
}
```

This makes the snake wiggle diagonally down the screen. It is a nice effect, although it perhaps looks more like a comet then a snake.

The calculation to get `prevHead` is a bit ugly, but that’s partly an
artifact of how `ArrayList`s work: `ArrayList`s don’t provide any
simple way to access their last element.

- Instead of drawing the segments as ellipses, draw them as lines between the points (be careful with the loop index!). This way no matter how fast your move the mouse pointer the snake will always be connected.

```
class Segment {
float x, y;
Segment(float init_x, float init_y) {
x = init_x;
y = init_y;
}
} // class Segment
class Snake {
ArrayList<Segment> segment;
Snake(int numSegments) {
// initialize the snake's segments
segment = new ArrayList<Segment>();
int i = 0;
while (i < numSegments) {
Segment s = new Segment(0, 0);
segment.add(s);
++i;
}
}
void update() {
// remove the first segment, and shift all the other segments
// down one index position
segment.remove(0);
Segment s = new Segment(mouseX, mouseY);
segment.add(s);
}
void render() {
// draw everything
int i = 0;
while (i < segment.size ()) {
noStroke();
float x = 255 - i * 5;
float mx = map(x,
255 - (segment.size() - 1) * 5, 255, // input range
0, 255 // output range
);
fill(mx);
float diam = map(i,
0, segment.size() - 1, // input range (i's range)
0, 50); // output range (diam's range)
ellipse(segment.get(i).x, segment.get(i).y, diam, diam);
++i;
}
}
void update(float x, float y) {
// remove the first segment, and shift all the other segments
// down one index position
segment.remove(0);
Segment s = new Segment(x, y);
segment.add(s);
}
} // class Snake
/////////////////////////////////////////////////////////////////////
Snake snake;
Segment prevHead;
void setup() {
size(500, 500);
smooth();
snake = new Snake(150);
prevHead = new Segment(0, 0);
}
void draw() {
background(255);
snake.update(prevHead.x + random(2.0), prevHead.y + random(2.0));
snake.render();
prevHead = snake.segment.get(snake.segment.size() - 1);
}
```