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 position
  • t.right(45) means rotate, around it’s current position, 45 degrees clockwise
  • t.left(45) means rotate, around it’s current position, 45 degrees counter-clockwise
  • t.penUp() makes the turtle draw no line when it moves
  • t.penDown() makes the turtle draw a line when it moves
  • t.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

  1. What is turtle graphics? Explain using English that a child in grade 4 or 5 could understand.

  2. On paper, write a turtle graphics program that draws an equilateral triangle (i.e. a triangle whose sides are all the same length).

  3. On paper, write a turtle graphics program that draws a circle.

  4. Can turtle graphics be use to draw any image whatsoever? Justify your answer.

  5. In the Turtle forward function, why is it necessary to use the radians function in these two lines?

    float dx = dist * cos(radians(angle));
    float dy = dist * sin(radians(angle));
    

Programming Questions

  1. Add a function called penSize(n) that sets the width of the line drawn by the turtle.

  2. 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.

  3. Continuing with the previous question, re-implement the forward function using jumpTo. Try to make forward as short and as simple as possible.

  4. 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");
    // ...
    
  5. 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