Scripted Animation for the Butterfly
Assignment (Conditionals)

Revised and corrected 9-25-03, 3:00 PM

Here are the scripts, demonstrated in class on September 25, that perform Lingo-based animation for the butterfly in Part 3 of "How to Lingo" (Conditionals). The basic idea here is to use scripted control of sprite position (locH and locV) in place of keyframe animation. Once you introduce a random variable, the butterfly's movement becomes unpredictable, taking us from classic animation, where sequence is predetermined, to simulation, where sequence is random or emergent.

The script actually comes in two parts. The smaller part is a startup script that sets initial values for some variables. This is written as the main movie script:

on startMovie
    global beat, xDir, yDir
    beat = 0
    xDir = "right"
    yDir = "up"
end startMovie

We're using three variables at this point; we'll add a few more later. The variable called beat is used to count beats of the butterfly's wings--you'll see how this works below. The variables xDir and yDir indicate the direction of motion in the X (horizontal) and Y (vertical) axes. We start them out arbitrarily as "right" and "left," though you could give them the opposite values. (It might even occur to you to choose their initial values at random.) I use strings for these variables. You could use numbers (1,0) or the logical values true and false, but I think it's easier to remember what's going on when you use meaningful strings.

Finally note that all three of our variables are named in a global statement. This allows us to use these variables in scripts attached to another object, in our case one of the butterfly cast members. This is called adjusting the scope of the variables. We need to scope our variables in this way because cast members don't accept startMovie handlers, and because the variables must be given values before the animation script is run.

The second part of the project is the animation script itself, which is written as a cast member script for one of the butterfly graphics. You'll note that we've assumed the cast member is to be inserted in Channel 2 of the score--that is, this image sits above the other butterfly image in the stacking order of the Director screen. Here's the script:

on enterFrame
    -- declare global variables
    global beat, xDir, yDir
	
    -- bump up the beat count by one
	beat = beat+1

    -- if the beat is 2, hide this sprite, reset beat to 0	
    if beat=2 then
        sprite(2).visible = false
        beat = 0
    else
        -- if the beat is 1, make the sprite visible
        sprite(2).visible = true
    end if
	
    -- the following statements control horizontal movement
    if xDir = "right" then
        sprite(2).locH = sprite(2).locH+4
    else
        sprite(2).locH = sprite(2).locH-4
    end if
	
    -- the following statements control vertical movement
    if yDir = "down" then
        sprite(2).locV = sprite(2).locV+4
    else
        sprite(2).locV = sprite(2).locV-4
    end if
	
    -- if we've gone too far left or right, reverse direction
    if sprite(2).locH > 390 then
        xDir = "left"
    end if
    if sprite(2).locH < 10 then
        xDir = "right"
    end if
	
    -- if we've gone too far up or down, reverse direction
    if sprite(2).locV > 230 then
        yDir = "up"
    end if
    if sprite(2).locV < 10 then
        yDir = "down"
    end if
end

Let's go through the script section by section.

First we use the counter variable beat to keep track of a two-beat rhythm. The variable is set up with a value of 0. We add one to this value each time, so on the first pass beat is 1 and on the second pass it is 2. If beat evaluates to 2, we turn the sprite invisible and reset beat to 0, so that when we increment its value on the next pass it will be 1 and the cycle will start again.

If you think about this code, you'll see that it substitutes nicely for the mod 2 statement in the keyframe version of the assignment. We can't use that technique here because our movie only has a single frame!

The next two sections of the script control horizontal and vertical movement. In each case we ask for the current value of the relevant control variable, either xDir or yDir. We add to the current location property of the sprite if moving down or right and subtract if moving up or left.

If we left the script at this point, our butterfly would quickly fly off the edge of the screen. So we add four conditional statements that kick in when our sprite exceeds certain limits. When a limit is exceeded in any direction, the relevant direction variable is reset to its opposite value, sending the sprite back toward the middle of things. Note that these limits are set 10 pixels back from the absolute edges of the screen (and you may also notice that we're using different screen dimensions than in the class assignment). This is an aesthetic detail, so that the butterfly doesn't disappear completely from view at any point.

There are only two more details needed to make all this work.

So far we've only scripted one sprite, but there are two in the works. We handle the other butterfly image in the simplest way possible, attaching this script to its cast member:

on enterFrame
    sprite(1).locH = sprite(2).locH
    sprite(1).locV = sprite(2).locV
end enterFrame

Now the underlying sprite automatically matches the horizontal and vertical position of the sprite above it.

We also have to do something about repetition. As a behavior script for the first frame, we add an exitFrame handler with a go to the frame instruction. Now our movie endlessly repeats its one and only frame, and the butterfly flutters eternally from one edge of the screen to another. This is either deep existential truth, or a poor excuse for a screensaver.

Suppose we want our project to be a legitimate screensaver. Such programs protect displays from burn-in by lighting up their pixels in a random or unpredictable sequence. In other words, we need our butterfly to behave less like a program and more like, well, a bug.

We can achieve this goal by taking out the hard-wired amount of change in each direction (originally 4 pixels) and substituting some random variables. So we rewrite the motion-control section of the main script thus:

    -- the following statements control 
    -- horizontal movement
    if xDir = "right" then
        sprite(2).locH = sprite(2).locH + hChange
    else
        sprite(2).locH = sprite(2).locH - hChange
    end if

We do the same with the vertical section, using the variable vChange.

These variables need to be given initial values, so we add them to the global statement in the main movie script. Then we add two more lines to this script:

    hChange = 4 + random(8)
    vChange = 4 + random(8)

The statement random(8) evaluates to a random whole number between 1 and 8. (You can pass other maximum values to this function for a larger range.) Since we don't want movement of the sprite to be less than 4 pixels at any point (an arbitrary decision), we add this random increment to 4. Thus the amount of motion is somewhere between 5 and 12 pixels.

What we've written so far will cause the motion of the butterfly to vary each time the movie is started up. But that's not our final objective. We want the butterfly to alter its behavior while the movie is running. We could do this with a timer, but since our code already recognizes collision with the screen boundaries, we can use those collisions as an occasion for change.

In the if conditions where we change xDir and yDir, we insert the two lines we added to the setup script:

    hChange = 4 + random(8)
    vChange = 4 + random(8)

This isn't the most elegant way to handle things; it would be better to break these instructions out into a function. But since we haven't discussed functions yet, we'll stick with the less elegant method.

You can see this code in action at the top of the page. The source file, scriptedButterfly.dir, is available in the directory mult201 on the FTP server crow.ubalt.edu.


University of Baltimore Logo

Copyright © 2003 School of Information Arts and Technologies