Dots and Lines¶
Lets write a program that draws a dot wherever the user clicks on the screen. Between each dot a line is drawn so that we can see the path of the clicks.
Note
Drawing connected points and lines turns out to be fairly common, and so Processing provides some built-in functions to do it for you: see the documentation for beginShape if you are curious.
Designing Our Program¶
Lets spend a moment thinking about how we want our program to work. When the user clicks the screen the first time, a red dot appears at the click point. Then, for the every click after that, a red dot is drawn at the click point, along with a straight line from its center to the center of the previous point.
We’ll represent the dots as follows:
class Sprite {
float x;
float y;
float dx;
float dy;
void update() {
x += dx;
y += dy;
}
}
class Dot extends Sprite {
void render() {
fill(255, 0, 0);
noStroke();
ellipse(x, y, 10, 10);
}
} // class Dot
With the Point
class in hand, lets now write a high-level sketch of the
entire program:
ArrayList<Dot> dots; // dots is initially null
void setup() {
size(500, 500);
smooth();
dots = new ArrayList<Dot>(); // make an empty ArrayList of dots
}
void draw() {
background(255);
// draw all the lines
// draw all the points (on top of the lines)
}
void mousePressed() {
// add (mouseX, mouseY) to points
}
By using comments like this, we can see the overall structure of the program without yet needing to worry about the low-level details.
Filling in the Details¶
Now lets replace the comments with working code. We’ll start with
mousePressed
:
void mousePressed() {
Dot d = new Dot(); // create a new dot
d.x = mouseX; // set its center to be
d.y = mouseY; // at (mouseX, mouseY)
dots.add(d); // add it to the dots ArrayList
}
Next, lets write the code for drawing all the points. This is not too hard:
void draw() {
background(255);
// draw the lines
// draw the dots
for (Dot d : dots) { // for each Dot d in dots
d.render(); // draw d
d.update();
}
}
Drawing the Lines with a For-each Loop¶
Next, we need to draw the lines between the dots. To draw a line, we will need two dots, one for each endpoint of the line. One day to do it is like this:
void draw() {
background(255);
// draw the lines
stroke(0);
Dot prev = null;
for (Dot d : dots) {
if (prev != null) {
line(d.x, d.y, prev.x, prev.y);
}
prev = d;
}
// draw the dots
for (Dot d : dots) {
d.render();
}
}
The variable prev
keeps track of the dot that comes just before the dot
d
in the for-loop. When the loop starts, prev
is set to the special
value null
because there is no previous dot. Inside the loop, we need an
if-statement to make sure that prev
is non-null before drawing a line.
Recall that null
is a special value that is used with object variables to
indicate they are not referring to any object (yet). That makes sense here:
there’s is no point before the first one.
Drawing the Lines with a While Loop¶
An alternative way to draw the lines is to use a while-loop like this:
// draw the lines
if (dots.size() > 1) {
int i = 1; // i starts at 1 because dots.get(i - 1) is an error when i == 0
while (i < dots.size()) {
Dot a = dots.get(i - 1);
Dot b = dots.get(i);
stroke(0);
line(a.x, a.y, b.x, b.y);
i += 1;
}
}
The idea here is to make the index variable i
take on the values 1, 2, 3,
..., n - 1 (where n is dots.size()
), and then to draw a line from the
Dot
at location i - 1
to the Dot
at location i
.
Bouncing Points¶
As a fun example, lets modify the above program so that the points fall down and bounce on the bottom of the screen. While not terribly practical, it is a nice-looking effect that might give you ideas for other kinds of animation.
We want this new program to work just like the previous one, except that when you press any key suddenly gravity is turned on and the dots all begin to fall downwards.
We saw in earlier notes how to make a ball fall down
and bounce on the screen. The idea is add two new variables: gravity
, to
control how fast a dot falls downwards, and elasticity
to control how
high it bounces:
class Dot extends Sprite {
float gravity;
float elasticity;
void render() {
fill(255, 0, 0);
noStroke();
ellipse(x, y, 10, 10);
}
void update() {
x += dx;
y += dy;
dy += gravity;
if (y >= height) { // check if ball has hit the bottom edge
dy = -(dy * elasticity);
y = height - 1;
}
}
} // class Dot
When the mouse is clicked, we need to set the dots gravity and elasticity:
void mousePressed() {
Dot d = new Dot();
d.x = mouseX;
d.y = mouseY;
d.gravity = 0.1;
d.elasticity = 0.8;
dots.add(d);
}
Now when you run the program, the dots bounce on the bottom of the screen.
Programming Questions¶
- Modify the bouncing dots program so that the dots don’t start moving until the user presses a key. If the user then presses a key while the dots are moving, they should immediately stop where they are and not move again until the user presses any key.
Final Program (no bouncing)¶
class Sprite {
float x;
float y;
float dx;
float dy;
void update() {
x += dx;
y += dy;
}
}
class Dot extends Sprite {
void render() {
fill(255, 0, 0);
noStroke();
ellipse(x, y, 10, 10);
}
} // class Dot
ArrayList<Dot> dots; // dots is initially null
void setup() {
size(500, 500);
smooth();
dots = new ArrayList<Dot>(); // make an empty ArrayList of dots
}
void draw() {
background(255);
// draw the lines
Dot prev = null;
for (Dot d : dots) {
if (prev != null) {
stroke(0);
line(d.x, d.y, prev.x, prev.y);
}
prev = d;
}
// draw the dots
for (Dot d : dots) {
d.render();
}
}
void mousePressed() {
Dot d = new Dot();
d.x = mouseX;
d.y = mouseY;
dots.add(d);
}
Final Program (bouncing)¶
class Sprite {
float x;
float y;
float dx;
float dy;
void update() {
x += dx;
y += dy;
}
}
class Dot extends Sprite {
float gravity;
float elasticity;
void render() {
fill(255, 0, 0);
noStroke();
ellipse(x, y, 10, 10);
}
void update() {
x += dx;
y += dy;
dy += gravity;
if (y >= height) { // check if ball has hit the bottom edge
dy = -(dy * elasticity);
y = height - 1;
}
}
} // class Dot
ArrayList<Dot> dots; // dots is initially null
void setup() {
size(500, 500);
smooth();
dots = new ArrayList<Dot>(); // make an empty ArrayList of dots
}
void draw() {
background(255);
// draw the lines
Dot prev = null;
for (Dot d : dots) {
if (prev != null) {
stroke(0);
line(d.x, d.y, prev.x, prev.y);
}
prev = d;
}
// draw the dots
for (Dot d : dots) {
d.render();
d.update();
}
}
void mousePressed() {
Dot d = new Dot();
d.x = mouseX;
d.y = mouseY;
d.gravity = 0.1;
d.elasticity = 0.8;
dots.add(d);
}