Turtle Graphics¶
In these notes you will learn:
- How to draw shapes using turtle graphics.
- How to implement a
Turtle
class for drawing turtle graphics.
Introduction¶
Turtle graphics is a simple yet useful approach to drawing pictures. The idea is to imagine a little robotic turtle with a colored pen that can move around the screen and do three things:
- move forward some number of steps
- rotate left/right some number of degrees
- lift the pen up or put it down
As it moves, the turtle draws a line showing it’s path. So, for example, these commands would make the turtle draw a square:
- Pen down.
- Forward 10.
- Turn right 90 degrees.
- Forward 10.
- Turn right 90 degrees.
- Forward 10.
- Turn right 90 degrees.
- Forward 10.
- Turn right 90 degrees.
Turtle graphics is easy enough for young children to understand. It only has a few simple commands, and with a bit of experimentation you can draw some very interesting pictures.
Designing a Turtle Class¶
Processing doesn’t come with turtle graphics built-in, so lets add it
ourselves. In an object- oriented language like Processing, the natural
approach is to create a class called Turtle
that represents an on-screen
turtle. When it’s done, it should work like this:
Turtle t = new Turtle();
t.setColor(color(255, 0, 0));
t.forward(10);
t.right(90);
t.forward(10);
t.right(90);
t.forward(10);
t.right(90);
t.forward(10);
Lets list what a Turtle
objects needs to know about. It needs to know:
- its current (x, y) position
- the direction it is facing, i.e. it’s angle (in degrees)
- whether or not the pen is up, or down; if the pen is up, then no line is drawn when the turtle moves
- the color of the pen
In addition, it needs to perform the following actions:
t.forward(25)
means move forward 25 pixels from its current positiont.right(45)
means rotate, around it’s current position, 45 degrees clockwiset.left(45)
means rotate, around it’s current position, 45 degrees counter-clockwiset.penUp()
makes the turtle draw no line when it movest.penDown()
makes the turtle draw a line when it movest.setColor(color(r, g, b))
sets the color of the turtle’s pen
This forms a simple blueprint for our Turtle
class, and the next step is
to implement it.
Implementing the Turtle Class¶
To implement the Turtle
class, lets first write down the variables we know
each Turtle
object will contain:
class Turtle {
float x; // turtle is at (x, y)
float y;
float angle;
boolean penUp;
color penColor;
Turtle() {
x = width / 2; // turtle starts in center of screen
y = height / 2;
angle = 0.0; // facing East
penUp = false; // pen is down, so lines will be drawn
penColor = color(0); // pen is black
}
// ...
} // class Turtle
Notice that the constructor for the Turtle
class assigns reasonable
starting values to the variables.
Next, lets add functions for moving the pen up and down:
class Turtle {
// ...
void penDown() {
penUp = false;
}
void penUp() {
penUp = true;
}
// ...
}
And functions for rotating left and right:
class Turtle {
// ...
void left(float degrees) {
right(-degrees);
}
void right(float degrees) {
angle += degrees;
}
// ...
}
Notice that left
is implemented using right
, e.g. t.left(26)
is
the same as t.right(-26)
.
The final function we need is forward
, and it’s the trickiest part of the
Turtle
class:
class Turtle {
// ...
void forward(float dist) {
float dx = dist * cos(radians(angle));
float dy = dist * sin(radians(angle));
if (!penUp) {
stroke(penColor);
line(x, y, x + dx, y + dy);
}
x += dx;
y += dy;
}
// ...
}
When the turtle is asked to move forward, it moves in the direction it is
currently pointing. The first two lines of forward
use basic trigonometry
to calculate how far along the x-axis and y-axis it should move to get to the
desired point.
Once dx
and dy
are known, then, if the pen is down, a line of the
appropriate color is drawn from (x
, y
), to (x + dx
, y + dy
).
Finally, the last two lines of the function update current position to be the
new position. It’s important that this update happens after drawing the
line, otherwise x
and y
would no longer contain the current position
of the turtle.
Sample Program¶
Now lets use our Turtle
class to write a sample program. Lets draw a
series of squares to make a flower-like pattern:
Turtle t;
void setup() {
size(500, 500);
t = new Turtle();
t.setColor(color(0, 255, 0));
noLoop(); // only call draw() once
}
void draw() {
background(255);
int i = 0;
while (i < 36) {
square();
t.right(10);
++i;
}
}
void square() {
t.forward(100);
t.right(90);
t.forward(100);
t.right(90);
t.forward(100);
t.right(90);
t.forward(100);
}
Note that the noLoop()
function is called in setup()
. This causes
draw()
to be called only one time. If you delete noLoop()
, then the
image will jiggle because the turtle is perfectly re-tracing its path.
It’s fun and easy to get different patterns. For example, try replacing the
square
function in the program above with this function:
void star() {
t.forward(190);
t.right(200);
t.forward(190);
t.right(200);
t.forward(190);
t.right(200);
t.forward(190);
t.right(200);
t.forward(190);
t.right(200);
t.forward(190);
t.right(200);
t.forward(190);
t.right(200);
t.forward(190);
t.right(200);
t.forward(190);
}
Regular Polygons¶
An equilateral triangle is a regular 3-sided polygon, while a square is a regular 4-sided polygon. In general, you can draw a regular n-sided polygon using this function:
void polygon(int sides, int step) {
int i = 0;
while (i < sides) {
t.forward(step);
t.right(360.0 / sides);
i += 1;
}
}
For example, polygon(3, 100)
draws an equilateral triangle with sides of
length 100, while polygon(4, 80)
draws a square with sides of length 80,
and polygon(10, 150)
draws a decagon with sides of length of 150.
A small but very import detail in this function is that every time through the
the turtle turns 360.0 / sides
degrees, we must write 360.0
and
not 360
. If you replace that 360.0
with 360
, Processing will
do integer division, which doesn’t always give the right answer. For example,
for polygon(100, 5)
, 360 / sides
is 360 / 100
, which evaluates to
3
(integer division in Processing always chops off digits to the right of
the decimal point). So each turn of the turtle will be 3 degrees, so the
turtle will only go around 3 * 100 = 300 degrees — leaving out 60 degrees of
the circle! So 360.0 / sides
, with the .0
, is needed to guarantee
floating point division is done.
A polygon with lots of sides looks like a circle. For example, polygon(100,
5)
draws what looks like a circle, but it’s really a polygon with 100 sides.
Questions¶
What is turtle graphics? Explain using English that a child in grade 4 or 5 could understand.
On paper, write a turtle graphics program that draws an equilateral triangle (i.e. a triangle whose sides are all the same length).
On paper, write a turtle graphics program that draws a circle.
Can turtle graphics be use to draw any image whatsoever? Justify your answer.
In the
Turtle
forward
function, why is it necessary to use theradians
function in these two lines?float dx = dist * cos(radians(angle)); float dy = dist * sin(radians(angle));
Programming Questions¶
Add a function called
penSize(n)
that sets the width of the line drawn by the turtle.Add a function called
jumpTo(x, y)
that makes the turtle immediately go to location (x, y) on the screen. If the pen is down, then a line will be drawn; otherwise, no line will be drawn. The angle of the turtle should not change.Continuing with the previous question, re-implement the
forward
function usingjumpTo
. Try to makeforward
as short and as simple as possible.Sometimes it’s convenient to specify a color by its English name instead of its RGB triple. Add a function called
setColor(name)
that sets the color of the pen to be the name of the passed-in color. It should work for, at least, “white”, “black”, “red”, “green”, “blue”, and “yellow”. For example:Turtle t = new Turtle(); t.setColor("yellow"); // ...
Add an image that shows the current location of the turtle. One way to do this is to draw the turtle as a triangle so that you can see the direction the turtle is facing. Or, you could use an image of a cartoon turtle.
The Turtle Class¶
class Turtle {
float x;
float y;
float angle;
boolean penUp;
color penColor;
Turtle() {
x = width / 2;
y = height / 2;
angle = 0.0;
penUp = false;
penColor = color(0);
}
void penDown() {
penUp = false;
}
void penUp() {
penUp = true;
}
void setColor(color c) {
penColor = c;
}
void left(float degrees) {
right(-degrees);
}
void right(float degrees) {
angle += degrees;
}
void forward(float dist) {
float dx = dist * cos(radians(angle));
float dy = dist * sin(radians(angle));
if (!penUp) {
stroke(penColor);
line(x, y, x + dx, y + dy);
}
x += dx;
y += dy;
}
} // class Turtle