Behaviors are one of the best features of Adobe Director. Using one or more behaviors you can quickly bring an idea to life and easily update or modify the way a Director movie functions or operates. A behavior is a Lingo script that is designed to be easily applied to the sprites and frames in a movie. Once a behavior is written, it can be attached to objects in a movie by dragging and dropping the behavior onto a sprite or frame script channel. Director comes with dozens of pre-built behaviors, but in this lesson we'll build a custom behavior from scratch.
Decide what the behavior should do and how it will work.
This step should be obvious, but the first step in creating your own behavior is determining exactly what it should do, and how it needs to work. You will need to take your idea and simplify it as much as possible so you will be able to develop the idea into a workable Lingo behavior. It is useful to write out specificaly what the behavior should do into a short paragraph or statement. Sketching out a digram or illustration is also helpful. Here's a description for the behavior we'll be developing:
This behavior will allow a sprite to automatically move around the perimeter of any sprite rectangle, in a clockwise fashion.
It's a simple description, but it clearly explains what we need the behavior to do. Now we need to analyze the description and break it down into the pieces that will allow it to become a functional behavior. The illustration below helps to visualize the needed elements, and how it will work. The red balls in the illustration represent the movement of a ball sprite over the four sides of a rectangle, drawn in black. The blue arrows indicate the direction of movement of a ball sprite around the rectangle.
You may also click the button below to see the behavior in action, with the behavior attached to three ball sprites.
Determine the sprite properties and variables that the behavior will need.
- Because this behavior dictates that one sprite will move around a rectangle we will assume that the behavior will be attached to the sprite that moves. We will use the me.spriteNum property for the behavior to automatically know which sprite channel the moving sprite is in.
- We will use another sprite to define the rectangle, so the behavior will need to store the sprite channel number containing the rectangle, as well as the rectangle points themselves.
- For the moving sprite we will use the locH and locV sprite properties to control where it is on the screen at any given moment.
- Since the movement of the sprite will be handled by the behavior, we will break up the sprite's movement into four directions. The current direction the sprite should move will be stored in a property variable.
- The four directions of movement are right, down, left, and up.
- We will also use a variable to store the speed at which the sprite should move.
Name the property variables.
Based on our analysis of what the behavior needs to do we can accomplish our goals with just four property variables. They will be defined as:
- pSpeed - How fast the sprite will move.
- pRectSprite - The sprite used to get the rectangle points that define the area of movement of the sprite.
- pRect - The rectangle points that define the area and shape of the rectangle.
- pState - The current animation state of the sprite. That is, right, down, left, and up movement.
Each of the above will be declared as property variables. If you aren't sure what a property variable is, remember that the Lingo handlers within a behavior are only "alive" as long as the behavior is running. When each handler is finished, any variables within that handler are lost. Sprite properties such as the sprite's location are stored in the sprite object, but handlers are something like arrows. Once an arrow is shot it has to be retrieved and drawn before it can be used again. By declaring a variable as a property variable, the value of that variable is retained as long as the sprite has an instance on that frame of the movie. Property variables are the best way to retain information about a sprite that you need it to remember as the movie is running.
Declare the property variables in the behavior.
Declaring property variables is easy. Usually, this is done at the top of a script. This is what our property variable declarations will look like:
Although you may put multiple property variables on a single line, separated by commas, the above format makes it easy to add comments (shown in red), to document what each variable is for. Note that we are going to follow the Lingo style convention of putting a lower case 'p' in front of property variable names to make it clear that they are property variables.
Initialize the property variables used in the behavior.
Initializing a variable means you deliberately assign it a value (even a value of 0), so it holds the value you want before other message handlers or variables use it. For our example behavior, the only variable that needs to be initialized is the pRect variable that stores the rectangle of the sprite used to define the area the other sprite uses to determine its movement limits. The beginSprite handler is a good place to initialize variables like this since it will be called before other sprite or frame handlers, and it is only called once, when the sprite is first encountered by the playhead. This is a very efficient way to initialize the property variable, and will not waste unecessary processing time, even if the playhead is looping.
Establish the definable behavior parameters.
The above handler may look intimidating, but if you look more closely you will see that it is really just providing an interactive way for you, or another developer, to set values for the behavior after the behavior has been dropped onto a sprite.
Essentially, the getPropertyDescriptionList handler contains Lingo that generates a list of definitions and labels for the parameters that appear in a behavior’s Parameters dialog box.
On the first line a property list named list is declared. The addProp command adds the property varible, comment, the data format of the variable, and the default value of each variable to the description list that determines how the behavior's Parameters dialog window will appear.
Rather than typing all of the symbols and parameters each time you need to define a getPropertyDescriptionList handler, you can simply copy and paste one you have already made into your script editor, and change it to suit your behavior. The values that will change from variable to variable include the data type, which tells Director what kind of data shold be stored for a particular variable. For example, #integer means the value for that variable will be an integer. Using #sound means the property is a sound type cast member. There are a number of other data types, and there is a complete listing of them here, for reference.
The image below shows how the above getPropertyDescriptionList handler parameters will appear in the completed behavior.
Write the method hander or handlers that get the job done.
This is either the most fun part of developing a behavior, or the hardest. For our example we will break down the sprite's movement into four directions, and create a handler to manage each direction. We will use the position of the sprite to trigger when the next direction should take over, so the sprite's movement will be self-directing. In essence, we will create a 4-state machine that will keep the sprite moving around the rectangle indefinitely.
Let's start by making a handler that moves a sprite horizontally across the screen from left to right, relative to its current position, as each frame is rendered. Ultimately, we will use an exitFrame message to drive the animation, but by breaking the four types of movement down into individual handlers the behavior will be much easier to read, modify, and debug.
To move a sprite progressively to the right we can use its horizontal location (locH), and add a value to that with the pSpeed variable. The greater the value of pSpeed, the faster the sprite will move. Since the sprite will be following the shape of a rectangle, we can use the geometry of the sprite's rectangle to determine when the next direction of movement should occur.
You may recall that any rectangle can be defined with just four numbers. By subtracting the difference between the left, top, right, and bottom numbers of the rectangle's definition, the length of any side of the rectangle can be easily determined. Director has a rect() data type that makes it easy to work with rectangles. Let's look at a simple example.
If we had a rectangle, rect(100,200,300,400), and assigned it to a variable called pRect, we could access any of the four numbers that define that rectangle like this:
pRect, pRect, pRect, pRect
These correspond to the left, top, right, and bottom numbers of the rectangle, respectively.
If we compare the position of the sprite moving toward the right to the right side of the rectangle, pRect, we could use that number to stop the movement to the right and switch directions.
The handler below does just that. It moves the sprite to the right until it moves past the right side of the rectangle. When that happens the state of the sprite changes, and the direction of movement will be changed when the behavior is complete.
We can use the same technique for the other movement directions. Here's what a handler would look like to move the sprite down the right side of the rectangle:
The moveItDown handler changes the vertical position of the sprite and compares that position to the 4th number of the rectangle, which is the bottom of the rectangle. When the sprite moves up to or past the bottom position of the rectangle, the state is changed to "moveLeft"
Below, are the moveItLeft and moveItUp handlers. They are written using the same scheme as the moveItRight and moveItDown handlers.
Once the movement handlers are defined we have to tie all of them together so the animation happens automatically.
Drive the animation using an exitFrame handler.
As it stands, the behavior we have written has the potential to move a sprite around the perimeter of a rectangle, but it won't work because there is no recurring message event to activate and maintain the sprite animation. To accomplish this we will use an exitFrame handler that waits for specific "state" messages to be sent. When a state message is sent the exitFrame handler will call the appropriate movement handler to keep the sprite moving around the rectangle.
Each of the four movement handlers above sets the pState variable to a specific string. The pState string is assigned a value of moveRight, moveDown, moveLeft, or moveRight from the movement handlers. Each movement handler automatically sets the pState variable when it reaches the targeted edge of the rectangle. All that's left to do is have the exitFrame handler wait for the pState variable to change, and to then call the appropriate movement handler to continue the sprite movement in the next direction. We will do this with a case statement. The case statement is similar to an if / else if, but is easier to read and requires less typing.
The exitFrame handler below continuously checks for the string assigned to the pState variable. As soon as pState changes, due to the sprite reaching the edge of one of the sides of the rectangle, one of the the moveItRight, moveItDown, moveItLeft, and moveItUp handlers will be called. In this way the sprite will continuously move around the rectangle, changing from one state, then calling a different handler, again and again.
Combining all of the above steps should produce a behavior that does what it was specified to do. This method of breaking down the movement of sprites into "states" can be very useful for a wide variety of applications. This behavior could be easily expanded to include more movement options. For example, if you wanted the sprite to toggle between moving and stopping when it was clicked you would only need to add a mouseDown or mouseUp handler that changed the pSpeed value to 0, or 5, each time it was clicked, effectively toggling its movement without breaking any of the other preexisting functionality.
For a challenge, try using the above scheme to control a virtual robot on the screen, or to move a computer opponent in a game.
You may download the above behavior, in completed form here, or a Director movie that uses the behavior. You may also want to take a look at this example to see how the "state machine" method was used to illustrate part of the "Itsy Bitsy Spider" poem.