If you want to advance from regular drawings to drawings that actually move, this is the right section for you. In this section, you will create an small movie of a sailboat sailing into the sunset.
Special thanks goes to Paolo Ruiz, who created this wonderful program. The entire program is also available in our Logo Library.
Apart from animation, this section als shows how to work with bitmaps instead of turtles as moving objects.
But first, let us dive into animation in general.
Let the Turtle Move
The trick behind animation is to move your turtle independently from a running program. The easiest way to move a turtle is to let it advance, then wait for a little while, and repeat everything over and over again:
TO MOVE.IT FOREVER [ FD 1 WAIT 50 ] END
If you run this code, the turtle starts moving, and stops only when you click the Stop button. Easy enough, but what if you need to move more than one turtle at a time? Then things become really complicated really quickly.
Thankfully, Logo offers a way to let a turtle move independently. The SETVELOCITY command does just that. It expects a single input, which is the number of pixels (dots) the turtle should move per second. A value of 100, for example, lets the turtle move with a speed of 100 dots per second:
Setting it back to 0 stops the turtle.
Right-click your turtle and open the Properties dialog; then play with the Velocity and Heading settings to get a feeling for the velocity.
Using SETVELOCITY, you can move multiple turtles around without having to loop and wait and loop and wait…
You propbably already know that you can drop a shape onto the turtle to change its shape to, say, a bird or a car. Moving a bird around looks so much more fun than just having the turtle move!
Problems arise when you want the turtle to move in a direction different from straight up. Your shape rotates just nicely as well. This may be fine if you, for example, want to steer a racing car, but rotating an elephant, for example, does not look right. An elephant would not want to walk on its tusk.
Logo also has a solution to this problem. The LOCKSHAPE command locks the shape in whatever heading it points so regardless of the underlying turtle’s heading, and the UNLOCKSHAPE command makes the shape rotate with the turtle’s heading again.
Try this for yourself. Drop an elephant on the turtle, make it become an elephant. Then, enter the LOCKSHAPE command. Now you can move and turn the elephant without having it rotate.
The Turtle Size
Let us assume that your turtle’s shape is now an elephant. Elephants are big animals, and the elephant shape is also big. What if you want the elephant to be much smaller?
Again, Logo comes to your rescue. The SETTURTLESIZE (or
SETTS) command changes the
size of your shape. A size of 1 is the original size. Make it smaller by using a smaller value, like 0.5 for half the size,
for example, or double its size my using
SETTS 2. The TURTLESIZE command reports the
current size of the shape.
You could even change the actual size of the shape by setting the turtle’s
SIZE property. This property takes a two-element
list containing the shape’s width and height in pixels.
The elephant shape, for example, reports a width of 249 and a height of 200 pixels:
GPROP 0 "SIZE Result: [249 200]
You think that the elephant is too skinny? Well, make it wider:
PPROP 0 "SIZE [400 200]
Try for yourself!
Did you know that many Logo commands just manipulate a trutle’s properties? The
for example, alters the turtle’s
SCALE property, and the
SETVELOCITY command changes the turtle’s
That’s why you can change most of these values when your right-click a turtle to display the property editor.
Sailing Into the Sunset
Now let us get to our beautiful sunset movie.
For this movie, you will not actually use the turtle other than to draw the actual objects that move. In the animation world, they call objects that move “sprites”, and this is what we will be calling them.
How do we create sprites?
First, let us look art the SNAP command. This command expects two or three inputs. The first two inputs are the width and height of the area to snap. The third input instructs the command to either snap both the drawing and the background (which is the default), the drawing only, or the background only. The command returns the name of the snapped bitmap. The turtle’s position is used as the lower left corner of the area to snap.
SETXY [10 20] (SNAP 50 100 "DRAWING)
Here, the lower left corner is at 10 horizontal and 20 vertical. The area to snap is 50x100 pixels, which puts the upper right corner at 60 horizontal and 120 vertical. In our case, we do not want any of the white background to be snapped, so we use the optional value “DRAWING as the third input.
The return value is the name of the snapped bitmap, which could e.g. be
BITMAP.1. In the procedures below,
we store that name into a more descriptive variable, like for example:
MAKE "CLOUD1 (SNAP 60 30 "DRAWING)
This lets us use the variable to activate the bitmap later. The TELL command instructs Logo to forward all turtle and movement commands to the name or list of widgets given as input.
TELL 0 ; activate turtle #0 TELL [0 1 2 3 4 5] ; turtles 0-5 will listen to commands TELL :CLOUD1 ; the bitmap whose name is in :CLOUD1 will listen
First, we need the sailboat. There is no sailboat in the Toolbox to speak of, so we need to draw our own. Here is the Logo procedure:
TO MAKE.SHIP ; Draws the original ship size setw 3 SETPC "INDIGO SETH 90 FD 200*.7 RT 100 REPEAT 3 [FD 200*.1 RT 6] LT 80 FD 200*.2 BK 200*.2 RT 80 SETH 270 FD 200*.55 LT 30 FD 200*.2 BK 200*.2 RT 30 RT 70 REPEAT 5 [FD 200*.06 RT 4] SETH 90 FD 200*.3 LT 90 FD 200*1.4 RT 150 REPEAT 7 [FD 200*.2 RT 4] SETH 265 FD 200*.43 SETH 10 REPEAT 6 [FD 200*.21 LT 4] SETH 200 REPEAT 5 [FD 200*.24 LT 4] SETH 95 FD 200*.23 ; move the turtle to the lower left corner of the drawing PU SETXY [-28 -80] SETH 0 ; then snap the drawing into a bitmap and save the name MAKE "SHIP (SNAP 200 370 "DRAWING) ; set the ship to WINDOW because we do not want the sailboat to wrap PPROP :SHIP "WRAPMODE "WINDOW ; remove the drawing and send the turtle home CS END
It is a good idea to clean the screen after the drawing so the next drawing can happen.
A word about this command:
PPROP :SHIP "WRAPMODE "WINDOW
Usually, turtles and sprites wrap to the other side of the Graphics panel when they hit any boundary.
The sailboat should start off-screen and sail into the horizon at about the center of the picture. If the sailboat
would wrap, we would not be able to really place it outside of the drawing area. Therefore, we set
WRAPMODE property to
WINDOW, which lets the sprite sail outside of the drawing area.
For more wrap modes, see e.g. the WINDOW command.
We want the clouds to move slowly acress the screen; therefore, clouds need to be sprites as well. Here is how:
TO MAKE.CLOUD1 HOME PD SETPC "DARKGRAY SETH 25 REPEAT 19 [FD 1 RT 3] SETH 25 REPEAT 29 [FD 1 RT 4] SETH 90 REPEAT 17 [FD 1 RT 5] SETH 110 REPEAT 9 [FD 1 RT 4] SETH 270 FD 58 PU SETH 0 BK 5 MAKE "CLOUD1 (SNAP 60 30 "DRAWING) CS END TO MAKE.CLOUD2 HOME PD SETPC "DARKGRAY SETH 25 REPEAT 19 [FD 1 RT 2] SETH 25 REPEAT 36 [FD 1 RT 3] SETH 90 REPEAT 17 [FD 1 RT 4] SETH 85 REPEAT 14 [FD 2 RT 5] SETH 270 FD 80 PU SETH 0 BK 5 MAKE "CLOUD2 (SNAP 80 40 "DRAWING) CS END
Then, we create the procedures that make the clouds, and initialize them:
TO CLOUD1 TELL :CLOUD1 ST LOCKSHAPE SETXY [120 190] SETH 90 SETVELOCITY 20 TELL 0 END TO CLOUD2 TELL :CLOUD2 ST LOCKSHAPE SETXY [-200 200] SETH 90 SETVELOCITY 20 TELL 0 END
These procedures position the clouds; they use the
LOCKSHAPE command, because
we want the clouds to move from left to right, which needs a heading of 90 degrees
without the could turning as well. Finally, we use
SETVELOCITY to have them start
moving on their own.
Note how we use the
TELL command to activate each sprite and have it listen to Logo
The ship also need some initialization:
TO SHIP TELL :SHIP ST LOCKSHAPE SETXY [50 -525] TELL 0 END
The ship needs to adjust the size while moving, which is a bit more complex
SETVELOCITY. We’ll talk about this in more detail below.
Finally, we can put it all together and create the scenery. A small procedure for a few waves, and another procedure for the horizon and the sun is needed.
TO WAVES :X SETPC "LIGHTSEAGREEN SETH 120 REPEAT :X [REPEAT 7 [FD 2 LT 10] RT 70] END TO HORIZON ; the curved horizon PU SETY 45 RT 90 PD SETW 3 SETPC "MEDIUMAQUAMARINE REPEAT 5 [FD 80 RT 0.5] ;curved horizon REPEAT 10 [LT 0.5 BK 80] REPEAT 5 [FD 80 RT 0.5] ; the sun setpc "gold SETH 0 REPEAT 19 [FD 10 RT 10] END TO SCENERY CLOUD1 CLOUD2 SHIP HORIZON PU SETXY [-120 -60] PD WAVES 3 PU SETXY [-250 -150] PD WAVES 5 PU SETXY [200 -120] PD WAVES 4 END
Note that we first need to make the clouds and the ship; after that, we are free to draw the rest.
Moving the Sailboat
We are almost there. The tricky part is to move the sailboat. It needs to move forward and at the same time become smaller, and all in a smooth fashion.
Now it is time to talk about the core of animation. You would not want to use the SETVELOCITY command, because you need to shrink and move the boat at the same time, both in certain time intervals.
Usually, this would require some sophisticated programming with wait loops or the like.
You do not want to do this. Instead, Logo uses a concept called “Animation Frames”. You may remember that movies in a cinema are actually a sequence of pictures, often with 24 pictures per second. The human eye is too slow to distinguish between these pictures, creating the illusion of continous movement in the brain. If you, for example, were from Mars with a much sharper eyesight, you could not watch a movie without getting a Martian headache, because the flickering would drive you crazy.
Logo uses the same concept to animate turtles, shapes and the like. It acts like a movie with 30 pictures, or frames, per second. And Logo offers to call a list of your Logo commands 30 times a second.
How convenient! Now, we just need to create a procedure that Logo needs to call 30 times a second, and both advance and shrink the sailboat during each of these procedure calls. Here it is:
MAKE "START.POS 203 MAKE "SHIP.POS :START.POS ; Called on every animation frame TO MOVE.SHIP IF :SHIP.POS <= 1 THEN (WHEN [ANIMATION FRAME]) STOP TELL :SHIP ; Move ship slower the farther it gets FD 1 + :SHIP.POS / 55 MAKE "SHIP.POS :SHIP.POS - 1 SETTS :SHIP.POS / :START.POS END
The first line stops the animation frames for the ship and exits the procedure when the ship has reached the horizon.
You can now use the WHEN command. This is a very powerful command that lets you attach Logo commands to a lot of events, like when you press a mouse button, or the mouse moves, and much more. The Logo manual has an entire chapter dedicated to the WHEN command. Click here for more information.
For now, we just use the WHEN command to make Logo call our movement procedure:
WHEN [ANIMATION FRAME] [MOVE.SHIP]
As you saw before, to stop Logo from calling
MOVE.SHIP repeatedly, use the WHEN
command without a runlist:
(WHEN [ANIMATION FRAME])
The Main Program
That’s it. Well, almost.
We need the main program that puts everything together:
TO ANIMATE DRAW HT MAKE.SHIP MAKE.CLOUD1 MAKE.CLOUD2 SCENERY ; start the animation frame monitor WHEN [ANIMATION FRAME] [MOVE.SHIP] ; sit and wait to keep everything moving WAIT -1 END
The last command
WAIT -1 needs an explanation. All Logo commands that Logo should execute on certain
events like an animation frame stop when a program ends. If you do not wait forever, the WHEN
command simply ceases working before the first animation frame is executed. So the only solution is
to wait forever so Logo can call the animation frame commands repeatedly.
But how to end the program then, apart from clicking the Stop button?
If you look at the
MOVE.SHIP procedure, the first line reads
IF :SHIP.POS <= 1 THEN (WHEN [ANIMATION FRAME]) STOP
If you want the whole movie to stop, including the clouds, use the TOPLEVEL command instead. This command causes Logo to return to toplevel, ending the program, and stopping all independent movement.
IF :SHIP.POS <= 1 THEN TOPLEVEL
Right now, we stop the program by clicking the Stop button so we can admire the clouds.
Are we done?
If you run the
ANIMATE procedure, everything runs just fine, but you see an annoying flicker
when you draw the sailboat and the clouds. It would be great if the turtle could draw the sprites
without disrupting the movie.
Again, Logo is there to help you. The FREEZEPIC command freezes the output of the Graphics panel. You can still draw, but the drawing will not display anymore. This is exactly what the doctor ordered. The UNFREEZEPIC revives the Graphics panel, and all drawings that have been made while the picture was frozen will appear.
What is needed is the following:
- Call FREEZEPIC
- Do all the drawing and creation of the sprites
- Erase the drawing and call UNFREEZEPIC
Let us alter the
ANIMATE procedure to include
TO ANIMATE DRAW HT FREEZEPIC MAKE.SHIP MAKE.CLOUD1 MAKE.CLOUD2 UNFREEZEPIC SCENERY ; start the animation frame monitor WHEN [ANIMATION FRAME] [MOVE.SHIP] ; wait for a TOPLEVEL WAIT -1 END
Now, we are really done! Enjoy!