Goal

In this exercise you will learn the basic structure of a handler and how to construct handlers that respond to specific messages. Additionally, you will learn how to create and work with different kinds of scripts and messages.

Definitions for Key Terms Used in this Exercise

Behavior - A behavior is a collection of Lingo handlers that are "packaged" in such a way that they can be easily engineered for reusability. Behaviors are designed to be an integral part of one or more sprites and have characteristics that allow messages to be sent and received very flexibly. Behaviors are the most common type of script and are always attached to sprites or frames.

Cast Script - A script attached to a cast member, not a sprite. Cast scripts are often used for cast members that serve the same function throughout a movie. Once a cast script is defined for a cast member it retains that script wherever it exists as an instance of a sprite in the movie. For example, a button cast member called "quit" would be a good candidate for a cast script since it would always serve the same purpose no matter where it is placed within the movie. Cast scripts can be a source of confusion because the script is integrated into the cast member itself. However, any behavior(s) attached to the sprite instantiation of that cast member override the cast script. For this reason and others, it is not recommended that you use cast scripts since behaviors are much more versatile and reusable.

Frame Script - A behavior script attached to a particular frame in a Director movie. A frame script is frequently used to control the playhead, but may be used for any number of tasks. Common frame script messages include "enterFrame" and "exitFrame."

Function - Any Lingo keyword or handler that returns a value. A function always includes parenthesis that surround the value, or values that are processed as a value for that function. For example, in the function "sin(3)" the "3" is the value that gets processed by the function (also called an argument). Any handler can be written as a function if it is formatted properly and processes or returns a value.

Message - The word (or string), as part of a handler definition, that activates the handler. For example, the words "mouseUp" and "exitFrame" are common messages used to activate handlers.

Movie Script - A special kind of script containing handlers that can be accessed from anywhere in the movie. A movie script is a good place to put handlers that are needed throughout the movie, not just as an attached behavior to one or more sprites. Movie scripts exist in the cast, but are not specifically attached to anything since the handlers defined within them are accessible to the entire movie.

Parameter - A value, much like a variable, that can be automatically passed or inserted into a handler. A handler with a defined parameter expects a word or number to be inserted next to the handler message so it can process the value of that parameter. Another word for a parameter is an 'argument'.

Parent Script - A parent script is a special type of object-oriented script that defines a child object, though it is not a itself a child object. A child object is a self-contained, independent instance of a parent script. Children of the same parent have identical handlers and properties, so child objects can have similar responses to events and messages.

Script - Any combination of handlers, statements, or expressions used in a Director movie. A script may be attached to a cast member, a sprite, a frame, an object, or the movie.

Sprite Script - A script attached to a sprite in the movie. A sprite script overrides a cast script that may have been defined for the cast member the sprite represents.

Handler Basics:

Scripts are collections of Lingo code that take care of specific tasks while your movie is running. Scripts are the sets of instructions you assign to frames, sprites, or other objects in your movie that take care of any logical processing of data that you may require. Scripts are synonymous with 'code,' a term you may have heard of in the context of other computer programming languages, but code and script are really the same thing. They both provide instructions for the computer to follow when specific events and logical conditions arise, while a movie is running. Lingo code is called a "script" because it tends to be much easier to learn and develop programs with than other comparable languages, and is much more "English-like," much like a script might be written and read by a live human actor. Lingo, like other well-designed computer languages, is capable of handling just about any computing or processing task you can imagine, provided you're willing to invest the time and thought that may be required to get the computer to do your bidding.

A script may have tens of thousands of lines of code, though most scripts are relatively short. Scripts always contain one or more handlers. A handler is a structured block of code that performs any number of tasks, depending on how it is written. In the simplest terms, you can think of a handler as something that "handles" Director movie events and messages for you.

A handler is easy to create and has only minimal structural requirements. First, the handler must begin with the word "on," followed by a message that activates the handler. Second, the handler must have the word "end" on a line all by itself. This is really all that is required for the basic structure of a handler, as far as Lingo is concerned. Here’s an example of what a basic handler might look like:

01-mouseUp-handler

Although the above handler is technically legitimate, it is not very practical because it doesn’t do anything. It needs a "body" of statements to make it perform something useful. Here’s the same handler as shown above, but with a "body."

02-handler-body

The same basic structure is present in the second handler, but it has four lines of code (i.e., statements) defining the body of the handler that make it actually do something. In both examples, whenever the "mouseUp" message is received by the handler it will process whatever code, if any, is contained within its body content.

Below, is a diagram that describes the basic anatomy of a handler:

03-handler-anatomy

The Message Activator is the message that causes the handler to execute the code in the "body" part of its structure. In the above example, the 'mouseUp' message is what triggers the handler to activate. Other common messages a handler might respond to are: mouseWithin, mouseEnter, mouseLeave, and exitFrame. You can also make up any message you like, and as long as the messages is sent to a handler, Lingo will do its best to make sense of it and execute the handler's code.

Regarding Messages: A message must "look" like a single word to Lingo, no matter what the name of the handler might be. That is, the message name can contain no spaces. This is why handler messages often look odd and contain no spaces. "theSuperDuperHandler" is a legitimate handler message name, and is written as such for stylistic reasons.

Lingo is not case sensitive, and doesn't care if any or all of the letters constituting a handler name are capitalized, or not. The capital letters at the beginning of each successive word in the message name make it easier for humans to read (i.e., as compared to "thesuperduperhandler"). You may write a handler name either way, but the convention is to capitalize the first letter of each successive word in a handler name, after the first word. The same naming style rule should be applied to variable names as well. (Variables will be discussed more completely in another exercise.)

A handler may contain thousands of lines of code in its body. Practically speaking, you won't likely need that many lines of code in any handler you write. If a handler becomes too long it is difficult to read, and may be even harder to modify. If you happen to write a lengthy handler, that is, one having hundreds of lines of code, consider breaking it up into a number of smaller handlers to make it easier to work with. There is virtually no hit in playback performance for breaking up a complex, lengthy handler into smaller "bite-sized" chunks, and it will be much easier to manage in the long run.

Comments:

When the computer reads the code you write in a script, it reads the code from left to right, then top to bottom. Each Lingo expression and statement you write is parsed and interpreted by Lingo based on very specific logical rules it has been programmed with. As long as you follow these rules to the letter (or symbol), you will have syntactically correct code. This doesn't mean that your code will always work, but if it is syntactically correct it means the computer thinks it can read what you've written, and that you haven't broken any of the rules that tell it how to do so. You could still have logic or runtime errors that might prevent your code from operating in the way you expect.

You'll find that it's an extremely useful practice to insert comments to yourself in the code you write to help you remember details about why you wrote something a specific way, or to point out sections of code that might otherwise be hard or time-consuming to remember or understand later. Lingo ignores comments. That is, commented code is never processed as instructions. When the Lingo parser encounters comment marks, it skips it and moves on to the next uncommented keyword, or to the next line of executable code. In this way you can also use comments to temporarily disable code that is causing problems, without having to delete it. Below, in red, is an example of commented code.

04-code-comments

You use two hyphens together '--' to tell Lingo that the code that follows on that line is a comment. Lingo will, by default, color comments red in the script editor. You will see comments used later in this exercise, as well as in the other exercises and code examples.

Commenting your code is a great practice to adopt, and it doesn't have to be overly time-consuming! Another commenting strategy is to make handler and variable names more verbose, rather than succinct and cryptic. In this way many of the handlers in your movies can be more self-explanatory, without requiring lots of comments. Creating easy to understand handler names and variables can be challenging, but it's well worth the effort to make your code easier to understand. You may look back at something you wrote recently and wonder, what were you thinking? Well written comments or aptly named handlers and variables virtually eliminate those problems.

Handlers that Accept Parameters:

In some cases it is more convenient to design a handler so that it can accept a value from outside the handler, rather than from a variable containing a value within the handler. For example, if you wanted to write a handler that computes the number of minutes in a given number of days without using parameter you could write it as:

05-days-to-minutes

The above handler will put "7200" in the message window. This works fine, but it isn't very flexible since the number of days have to be included within the body of the handler. If you want to compute the number of minutes in 15 days you have to change the number of days to 15 in the above handler. If you need to repeatedly compute a different number of days you can copy the above handler and change the number of days each time the number of days needs to be different, but this too is awkward and inflexible. A better solution is to use a "parameter." A parameter (also called an argument) allows a value to be passed into a handler without the value having to be assigned within the handler.

Here’s an example using the same basic structure as the first handler, but this one uses a parameter:

06-days-to-minutes-parameter

Notice that we didn't need to include a line to set the value for the variable "days." This value comes from the parameter, so if we want to know how many minutes there are in 20 days we would call the handler in the Message Window like this:

07-days-to-minutes-msg-win


The number "20" now acts as a parameter to the "daysToMinutes" handler, so as long as a number is included when the message is sent it will insert that value and compute the result, just as though it had been written into the handler as a variable. In order to test this method you will need to create a simple Director movie and set it up for a movie script. To do this, follow the steps below:

01) Create a new Director movie.

02) Go to the Window menu and choose Script, or type COMMAND + 0 (Macintosh), or CONTROL + 0 (Windows).

You should now have an empty "movie" script window. To be sure, the name of the window should be "Movie Script 1," or at least say "Movie Script" followed by some number. If it doesn't say "Movie Script" you can get information for the cast member (i.e., the script) and choose "Movie Script" as the type from the popup menu that will appear.

03) Type the parameter script exactly as it appears below.

Note: You may notice that the algorithm on line 2 multiplies days times 60 times 24. Since this is just multiplication we don't need to group 60 times 24 in parentheses. The result will be the same whether we use the parentheses, or not. However, it is sometimes more convenient, in terms of thinking, to know that part of an expression is computed as a "chunk". In this case 60 * 24 is evaluated and computed by itself, then multiplied by the number of days. We could just as well multiply the days times 1440 (24 times 60), and we would save the computer a tiny amount of computation. By Leaving the parentheses in the example it also helps make the point that code in any computer language is interpreted according to algebraic rules, and expressions in parentheses are computed first.

In general, it is a good practice to optimize code so the computer processes things a sefficiently as possible. On the other hand, this particular equation can be computed so fast already that optimization is not really necessary. When you're learning, it is far more important that you structure code in a way that is easy for you to understand, while still producing a correct result. Optimization can be done when you have everything else working, and you have a solid understanding of Lingo.

08-movie-script

04) Check the syntax and recompile the script (click the black lightning bolt in the upper right side of the script window), and close the window.

09-black-lightning-bolt

You can now test the script using the message window without the movie needing to be running.

Note: The black lightning bolt forces Director to read through the entire script and check it for typos (syntax errors), as well as convert the script to a "ready to run" format. The process of converting a script into a "ready to run" format is called compiling. Once a script has been compiled you won't need to click the black lightning bolt for that script again unless you change the script. Even then, Director automatically recompiles scripts when a Director Movie file is loaded. To make sure Director is running the most current version of a script you are editing it is always a good idea to click the black lightning bolt before running it.

05) Go to the Message window and type daysToMinutes 20 followed by a return. You should see "28800" appear on the next line in the message window, indicating the number of minutes in 20 days. Save the movie so you can use it again.

07-days-to-minutes-msg-win

 

Behavior Handlers:

Handlers used in behaviors work just like the above Lingo code examples, but they are designed to be "attached" to specific sprites. Technically, a sprite is nothing more than a Cast member that has been placed in a channel in the Score. As soon as a Cast Member becomes a sprite it is given special object properties that allow it to send and receive messages exclusively with sprites and behaviors.

A behavior may also be attached to a frame in a movie. In this case it's called a Frame Script, but it's still a behavior, just one that is designed to work at the frame level. Since a behavior is always attached to a sprite or frame its handlers need a way to "remember" what sprite or frame they are attached to so the 'me' keyword is used. The 'me' refers to the object (a sprite or frame) to which the script is attached.

An example of a handler in a behavior that used a mouseUp message to move the playhead to a frame named "intro" would look like this:

10-behavior-handler

This is nearly identical to a handler that might be in a movie script, with the exception that the 'me' keyword would have no effect inside a movie script. Also, the scope of the above handler, when used with a sprite, would only activate if that particular sprite received a 'mouseUp' message. If the same handler were in a movie script, any 'mouseUp' message sent anywhere in the movie would trigger the handler to be called. To summarize, here is the above mouseUp handler in a Behavior format, and a movie script format.

11-behavior-and-movie-handlers

The 'me' keyword has properties of its own, including the sprite channel to which it is affiliated. This can be extremely handy for writing behaviors that are reusable. Below is a handler that moves a sprite in channel 1, 10 pixels to the right every time it is clicked by the mouse.

12-numbered-sprite-channel

This works fine for sprite 1, but it won't work for any other sprite. By using the 'spriteNum' property of 'me' we can automatically determine which sprite the script is attached to and use the script for any sprite in any channel.

13-relative-sprite-channel

The above handler is much more versatile, so you will find that it's best to use the 'me.spriteNum' property for nearly all of your behaviors.

 

Functions and Handlers:

By basic computer science definition, a function is anything that returns a value. The most common functions are used for mathematical processing, but many functions are designed to work with any kind of data, including strings (i.e., text). Functions always include parenthesis "()" as a part of the function name.

Here are some of the most common mathematical functions that Lingo understands:

Function

Description

Example

abs

Returns the absolute value of the number (i.e., strips off the negative sign from any number less than 0).

spacerabs(-12) = 12

float

Converts the number to a floating point number.

spacerfloat(5) = 5.00

integer

Converts a floating point number to an integer using rounding. Integers that are already integers are left the same.

spacerinteger(4.8) = 5

mod

In computing, the modulo operation finds the remainder of division of one number by another. Mod can be used for a variety of things, including limiting a number to a range. The limit always starts with 0, and goes up to the specified number.

spacer4 mod 3 = 1

sqrt

Returns the square root of the number.

spacersqrt(9) = 3

There are other trigonometric functions such as atan(), cos(), and sin(), and others, but they’re needed only in special cases.

Let’s suppose we want to write a function that returns the area of the wall in a room in square feet, given the width and height of the wall in feet. This handler, written as a function, might look like this:

14-function-example

The function looks almost identical to a handler with parameter variables, but it differs in one distinct way; it includes the "return" keyword, which returns the value of the function. Using the movie you saved from the above parameter handler activity, open the movie script you created, and add the "findWallArea()" function handler to it.

Once you close the script window you can test the findWallArea() function using the Message Window.

Useful Script Tip

You can compile a script, close its window, and immediately see the stage view of your movie by hitting the ENTER key on the numeric keypad when you are in the script editing window.

Type the following in the message window:

15-wall-area-function

When you hit the return key you should see "300" appear on the next line in the message window, indicating the area, in square feet, of a 15’ by 20’ wall.

Note: A handler and a function can accept multiple parameters, as shown in the above example. To use more than one parameter you must separate them with commas, but otherwise you may have as many parameters for a handler as will fit within 255 characters, including the commas. This gives you many possibilities for more sophisticated functions having many parameters, if you need them.

Handlers and function parameters may also contain strings (text), but string parameters must be enclosed within double quotation marks when they are defined. To try using a string as a parameter, type the following in the "Movie Script" window of the movie you created earlier.

16-multiple-parameters

Close the movie script window and type the following in the message window:

17-multiple-parameters-msg-win

The message window should return a line that says:

"First name is Stanley, and last name is Kubrick."

Even though the grammar is poor you can see how the string parameters were embedded as a part of the function. You will find that parameters that use numbers and strings afford a great deal of flexibility for the Lingo programmer, and allow a single "Movie Script" to contain a number of handlers and functions that can be used over and over again throughout your movie, very easily.

 

Events:

Events are messages sent by the system, or from user-defined handlers or functions. There are two types of events that occur when a movie plays, system events and user-defined events. System events occur without a user interacting with the movie, and are predefined and named in Director. For example, when the playhead enters a frame (enterFrame), when a sprite is clicked (mouseUp), etc. User-defined events occur in response to actions that you define. For example, you could create an event that occurs when the foreground color of a sprite changes from one color to another, or when a sound has played a certain number of times, and so on.

Shown below is a simplified diagram of specific events processed by Director, and the order these events are executed, from left to right.

18-director-frame-events


Basic Frame & Sprite Script Handlers
:

A frame script is often used to control the playhead in a movie. One of the most common uses for a frame script is to keep the playhead on one frame indefinitely so the user can choose what to do. This commonly used script looks like this:

19-hold-frame-behavior

This handler essentially tells the playhead to go to the frame having the value of "the frame," which is always the current frame where the playhead is located. This forces the playhead to go nowhere, which is the desired effect. Other scripts, such as a sprite script, work well in conjunction with the above frame script to allow the user to navigate to different places within the same movie, or to go to a completely different movie. Some common sprite navigation handlers are listed below.

Make the playhead:

Sprite Script

Go to frame number 20.

on mouseUp
spacer_movie.go(frame 20)
end

Go to a frame labeled "intro."

on mouseUp
spacer_movie.go("intro")
end

Stay on the current frame indefinitely.

on mouseUp
spacer_movie.go(_movie.frame)
end

Go to the previous marker.

on mouseUp
spacer_movie.goPrevious()
end

Go to the next marker.

on mouseUp
spacer_movie.goNext()
end

Repeatedly loop between a frame and the
closest marker to its left.

on mouseUp
spacer_movie.goLoop()
end

Go to a different movie.

on mouseUp
spacer_movie.go(1,"mars")
end

Go to a different frame of a different movie.

on mouseUp
spacer_movie.go(10,"mars")
end


A text file containing all of the _movie.go variations may be downloaded here.

A lot of information was presented in this exercise, but you should now have a better understanding of how handlers are constructed in Lingo, how to write basic functions, and how to use messages to control the playhead in a movie.

<     Table of Contents     >