parent previous next question (Smalltalk Textbook 28)

EngiTurtle

Turtle graphics were invented at MIT by Seymore Papert to help kids explore geometry. Imagine a turtle which is dragging a pen. In order to draw shapes, you order the turtle to do things like 'go forwards' 'turn left' etc. I will make a simple turtle graphics program in this section to illustrate Object Oriented programming. File in the program in Appendix 14 now.

Let's draw a red triangle and a blue square. Program 28-1 creates a turtle and specifies the pen by size ('nib:'), color ('color:') and a drawing surface ('graphicsContext').


Program-28-1: (EngiTurtle, ColorValue; go:, turn:)
---------------------------------------------------------
| window turtle |
window := ScheduledControllers activeController view.
turtle := EngiTurtle new.
turtle nib: 3.
turtle color: ColorValue red.
turtle graphicsContext: window graphicsContext.
window clear.
turtle home.
turtle north.
3
        timesRepeat:
                [turtle go: 100.
                turtle turn: 120].
turtle color: ColorValue blue.
turtle south.
4
        timesRepeat:
                [turtle go: 100.
                turtle turn: 90].
window sensor waitClickButton.
window display
---------------------------------------------------------

The program (1) places the turtle at the center of the drawing surface (home), (2) faces the turtle to the north (upward), (3) tells it to move ('go:') 100 steps, (4) tells it to 'turn:' 120 degrees clockwise. Then it repeats (3), (4) twice to draw a red triangle. After drawing a red triangle, the turtle faces to the south ( downward ) and draws a blue square.

Program 28-2 draws 8 arrows at 45 degree increments.


Program-28-2: (EngiTurtle, ColorValue; go:, turn:, goto:, down, location:,
direction:, arrow)
----------------------------------------------------------
| window turtle arrow |
window := ScheduledControllers activeController view.
turtle := EngiTurtle new.
turtle nib: 3.
turtle color: ColorValue red.
turtle graphicsContext: window graphicsContext.
window clear.
arrow :=
        [:length |
        | location direction tip |
        location := turtle location.
        direction := turtle direction.
        turtle go: length.
        tip := turtle location.
        turtle turn: 150.
        turtle go: 20.
        turtle up.
        turtle goto: tip.
        turtle down.
        turtle turn: -150.
        turtle turn: -150.
        turtle go: 20.
        turtle location: location.
        turtle direction: direction].
turtle home.
turtle north.
8
        timesRepeat:
                [arrow value: 100.
                turtle turn: 45].
window sensor waitClickButton.
window display
----------------------------------------------------------

Notice the arrow block closure saves the location and direction of the turtle before drawing an arrow, then restores the turtle to the saved position and direction. Also notice that (1) the program saves the position of the arrow head ('tip'), (2) draws an arrow, (3) raises 'up' the pen, (4) jumps to ( 'goto:') the arrow head ('tip'), (5) then lowers 'down' the pen, (6) and draws the opposite side.

'EngiTrutle' class has 5 examples. Example 1 draws a pac-man, 2 draws a dragon line, 3 draws a star, 4 draws a mandala, and 5 is an example of parallel processing to draw 5 spirals at once.

6 instance variables are defined for 'EngiTurtle':

-------------------------------------------------------
        location    turtle's coordinates 
        direction   turtle's direction ( degree ) 
        down        the pen touches the board or not 
        nib         size of the pen  
        color       color of the pen  
        gstate      the drawing board 
--------------------------------------------------------

You can calculate new coordinates of the turtle after he moves from his 'location' in some 'direction' like this.

-------------------------------------------
radian := direction dgreesToRadians.
x := location x + (radian cos * length).
y := location y + (radian sin * length).
-------------------------------------------

Therefore, the program draws turtle graphics by sending 'displayLineFrom: location to: x @ y' message with pen size as 'lineWidth:' and pen color as 'paint:' to a graphics context stored in 'gstate' to draw a line from old 'location' to new 'location'. This then is how you simulate the turtle moving a given number of steps in a certain direction when the turtle receives the 'go:' message.

A picture drawn by the turtle can be turned into an image. Program 28-3 uses the 'asImage' message to creates an image of the mandala drawn by the turtle.


Program-28-3: (EngiTurtle, ColorValue; mandala:diameter:, clear, home)
------------------------------------------------------------
| window turtle size image |
window := ScheduledControllers activeController view.
turtle := EngiTurtle new.
turtle nib: 1.
turtle color: ColorValue blue.
size := window bounds width min: window bounds height.
turtle graphicsContext: window graphicsContext.
window clear.
turtle home.
turtle mandala: 24 diameter: size - 20.
image := turtle asImage.
window display.
EngiDisplayModel openOn: image
------------------------------------------------------------

The 'EngiTurtle' is simple but useful. I hope you make a subclass of 'EngiTurtle' to draw a turtle on the screen and move it incrementally instead of just drawing the lines like we did above.


parent previous next question
Copyright (C) 1994-1996 by Atsushi Aoki
Translated by Kaoru Rin Hayashi & Brent N. Reeves