Advanced Action Script Examples

 

Learning Goals

  • Learn about drag-drop actionscript
  • Learn more about variables as objects
  • Learn about single-frame navitaton designs

Readings (Green & Dias)

  • Chapter 14: Building Stuff

Resources

Within Advanced ActionScript Folder

  • drag_Location.fla
  • multiple_page_menu_scheme.fla

Activities

  • Complete Chapter 14 exercises

 

Variables as Objects

Up to this point we have presented variables as holders of information, which conveys is a true but simple understanding of what a variable is. In order to advance your actionscript skills we need to expand on this definition.

Variables in actionscript are holders of information because variable names reference (or "address", or "point to") some number of memory locations. We can call the memory associated with a given variable a "block" of memory. To actionscript, a block of memory is an object. Therefore all variables point to actionscript objects. (To Flash, even a function is an object, and is instanced, and memory allocated to, when the function declaration is encountered in the actionscript code.)

When you declare a variable, the actionscript compiler allocates a block of memory and uses the variable name to reference the memory locations in that block. That's nice, because you can retrieve the information stored there using the variable name (it's easier for you if the computer keeps track of where in the computer's memory the information actually is - all you need to know is the variable name).

How large an object's memory block is, and its structure, depends on the type of variable you have declared. Some variable types are complex objects, and some are very simple. The simplest variable types are the int (integer) and boolean, and are only allocated a few bytes by the actionscript compiler. Others (such as Arrays, TextFields, MovieClips, and Sound, variable types) point to objects that are very large and complex - they are composed of many sub-variables, or "fields" or "properties".

In actionscript we use the term "properties" to denote the variables contained "inside" of complex objects.

Exercise: Create your own complex objects with properties.

Open a new Flash file and enter (or copy and paste) the following script into the actionscript editor on the first frame of layer 1, test and view the output:

objects 1

// create some objects

var jane = new Object();
jane.name = "Jane Jones";
jane.weight = 120;

 

var john = new Object();
john.name = "John Jones";
john.weight = 170;

 

trace ( "jane = "+ jane );

trace ( "jane's name is " + jane.name + " and weighs" + jane.weight + " lbs..." );

trace ( "john = " + john )

trace ( "john's name is " + john.name + " and weighs " + john.weight + " lbs..." );

 

// lets do a test, is jane lighter than john?

 

if( jane.weight > john.weight ){

trace( "then, " + jane.name + " is heavier than " + john.name + "!" );

}else{

trace( "then, " + jane.name + " is lighter than " + john.name + "!" );

}

You have just instanced two generic actionscript objects, each with two properties. You used the values stored to run a test and display some information. The objects are instanced first, using the "new" keyword, and then you add properties to the object using the variable names you declared. Note the properties act like variables, pointing to the values they hold within the complex object using the dot syntax. The variables jane and john point to their respective objects so we can access the objects' properties.

It is important that you understand that variables are pointers to, or references to, or addresses, of objects. It is only through the varaible jane, that we can access the object and the information its properties, in turn, point to. If we lose the object jane points to, we can no longer access its information:lost object

Modify the above code, adding the following at the end:

jane = john;

trace( jane.name );

// oops! no more jane!

You will have lost the object jane originally pointed to, for now jane points to the same object as the variable john. Once an object reference is broken in such a manner, the original object is lost forever and will be garbarge-collected.

Exercise: use variables, objects and properties to point to other variables, objects and properties.

Now lets extend your understanding of objects and properties further. Modify the above script, or copy and paste the following over your existing example. What will the trace statement display?

objects

var jane = new Object();
jane.name = "jane Jones";
jane.weight = 120;

 

var john = new Object();
john.name = "John Jones";
john.weight = 170;

 

jane.friend = john;

 

trace( "jane's friend is " + jane.friend.name );

You have just used the variable jane, that points to an object whose property, friend, points to another object - the same object john points to. Are you getting dizzy yet? Once you learn that variables reference objects, you can tap that knowledge to accomplish some powerful actions efficiently. You can package up whole groups variables into properties of objects rather than keeping separate varaibles.

You have already employed this concept, perhaps without realising it! Nearly all Flash objects employ this concept, and just like you added properties to the objects you created above, you can also add your own properties to MovieClips, TextFields, Sprites, and Sounds. When you add a properties to an object, we say that you "extend" the object.

[ Note in the above example we only gave the object that jane refers to a property, friend, but not the object that the variable john refers to. That's fine - actionscript doesn't care, we can add properties to objects as we like or need, at will. The only difficulty we would encounter is if we tried, in the above sample, to trace john.friend.name - why is that a problem? Try it and see. You will find out john has no friend property in a very rude way! ]

Extending objects example:

So you may extend many of Flash's objects by adding your own properties to track any extra information you like. For example, want to know how many times each movie clip has been clicked on? Rather than keeping a separate variable for each clip you want to track, just extend the movie clips:

t1_mc.clickCount = 0; //assumes movie clip instances t1_mc & t2_mc exist on the stage

t2_mc.clickCount = 0;

t1.addEventListener( MouseEvent.MOUSE_DOWN, doMe );

t2.addEventListener( MouseEvent.MOUSE_DOWN, doMe );

 

function doMe( evt : MouseEvent ){

evt.target.clickCount++;

trace( evt.target.name + " has been clicked " + evt.target.clickCount + " time(s)!" );

}

Try it!:

Content on this page requires a newer version of Adobe Flash Player.

Get Adobe Flash player

download the extend_movieClip.fla

One function to rule them all:

The discussion of the concepts above illustrates another important strategy in dealing with MouseEvents. In the past you may have written separate event handling functions for each button or object you want to have react to mouse clicks (or other mouse events). These are not necessary, and (though sometimes it can be advantageous to create them, it depends on what you are trying to do) usually your code can be greatly simplified by using one event handling function for all your buttons (the example immediately above did exactly that).

Let's look again:

t1_mc.addEventListener( MouseEvent.MOUSE_DOWN, doMe );

t2_mc.addEventListener( MouseEvent.MOUSE_DOWN, doMe );

 

function doMe( evt : MouseEvent ){

trace( evt.target.name + " is an " + evt.target );

if( evt.target == t1_mc ){

// replace these trace statments with what ever code you want for each button

trace( "t1_mc jump to some frame." );

}else if( evt.target == t2_mc ){

trace( "OK, t2_mc, jump to some other frame instead." );

}

}

Note that we pass the same function reference, doMe, to the addEventListener function for both movie clips, t1_mc and t2_mc. There is no problem doing this, but we need to know, inside of the function doMe, what movie clip reacted to the MouseEvent.

Every event handling function receives an event object as a parameter, and in the above code you see we are catching the event object in the evt variable defined in the function declaration.

The event object has a property, target. The target, in the case of a MouseEvent, is a reference to the button or movie clip that reacted to the mouse event - in this example a MOUSE_DOWN event. We can use that fact to detect what movie clip (or button) was clicked, and then react using an if else construct to perform a different action for each button.

Try it:

Content on this page requires a newer version of Adobe Flash Player.

Get Adobe Flash player

download the one_function_movieClip.fla

Using one fuction has the advantage of simplifying your code. You use the properties of the event object to determine what button was clicked, and act accordingly. In the next section we'll see that the event object taget property, is also a complex object, and as properties that let us detect which object was under the target when we drop a movie clip in a drag and drop operation.

There is one caveat: if you use a MovieClip object as a button, and it in turn contains child movie clips nested in side of it, then you must set the mouseChildren property of the enclosing parent movie clip to false. If you do not, the target property of the event object will reference the child movie clip that detected the event. mouseChildren is true by default, so you must turn it off to make nest clips ignore events.

t1_mc.mouseChildren = false; // makes nested movie clips ingnore events attached to the parent clip

Try it:

Content on this page requires a newer version of Adobe Flash Player.

Get Adobe Flash player

download the mouseChildren_example.fla

 

Applying the concepts to drag and drop:

Well use the fact that we can add any properties we like to extend Flash's built-in objects to look at a complex drag and drop example:

Suppose you want to create a drag and drop exercise, are there are multiple items to drag and multiple possible places where they could be dropped, but only certain items could be dragged to certain places - only some drops are correct for a given draggable object. Further let's stipulate that once an item is dropped in the correct location, no other object can be dropped in the same location, and any object that cannot be correctly dropped must snap back to its original location. What information do we have to keep track of to make all that possible?

1. we need the home or starting x and y location of each draggable object, so we can snap back if it is not correctly dropped, or if the correct drop location is already occupied.
2. we need to keep track of each possible correct target drop x and y location for each draggable object.
3. we to know if a possible target is already occupied by a dropped object, so that we do not allow other objects to be stacked on top of the same location.

If we are only dragging two objects and have one target, the problem is fairly simple, and the necessary information can be tracked with a few variables. But when we want to have many draggable objects and targets, this type of complex interaction can quickly get out of hand. We will use the knowledge that variables point to objects, and objects can be given new properties that point to other objects to track all the necessary information in a much more concise fashion.

When you place a movie clip on the stage from the library, it is an object that you can reference through its instance name. We can also add properties to the instance name just as we did with the objects above - we can reference a movie clip from a property we give to another movie clip.

For example, say we place one of our draggable objects with instance name, myMovie1_mc, on the stage. We want to give it a home location to start from and snap back to if it is incorrectly dropped, so we place another movie clip on the stage to act as the home location, and give it an instance name myMovie1_Home_mc. (we can even use the same symbol for both instances). We position myMovie1_Home_mc where we would like the starting location of myMovie1_mc to be. Then we set up the code:

myMovie1_mc.homePos = myMovie1_Home_mc;

// we have added a property to a movie clip that points to another movie clip.

To send the draggable object, myMovie1_mc, to it's home location (which will be the location of whatever clip is pointed to by the property, homePos ) at the start of our animation, (and we'll use the same code when we do not correctly drop it), we add the statements:

myMovie1_mc.x = myMovie1_mc.homePos.x;
myMovie1_mc.y = myMovie1_mc.homePos.y;

// wherever myMovie1_mc was on the stage, it is now over the top of myMovie1_Home_mc

// we do this so we can reference the home position of myMovie1_mc from myMovie1_mc - its home location is self-contained!

Next, how to track the possible correct drop targets? We'll add a movie clip that will act as the correct drop location, call it target1_mc, and set up the following code:

myMovie1_mc.correctPos = target1_mc;

If we want to stop other objects from being dropped on the same target once the target has been correctly dropped upon, we would add a property to our target movie clip:

target1_mc.occupied = false;       //we start with no object on the target

That way, in our drag and drop code where we drop, we can check the drop target object to see if we dropped on the correct movie clip.

Important note: In a MOUSE_UP actionscript event handler, the target property of the event object contains a property, dropTarget, which points to a shape which is under the location of the mouse at the location where the event was triggered. It is the parent movie clip of that shape that is the desired target: so we need to check the event.target.dropTarget.parent:

// inside the event handler where we catch a mouse up event triggering a "drop"

//             we can use the same event handler for all our draggable objects

if( mouse_up_event.target.dropTarget.parent == mouse_up_event.target.correctPos ){

// is our target already occupied?

if( ! mouse_up_event.target.dropTarget.parent.occupied ){

 

// then we got a correct drop, snap to the target x and y location

mouse_up_event.target.x = mouse_up_event.target.correctPos.x
mouse_up_event.target.y = mouse_up_event.target.correctPos.y

 

//also, mark the target as occupied

mouse_up_event.target.dropTarget.parent.occupied = true;

 

}else{

// target is occupied, then snap to homePos as noted above

mouse_up_event.target.x = mouse_up_event.target.homePos.x;
mouse_up_event.target.y = mouse_up_event.target.homePos.y;

}

}else{

// incorrect drop, then snap to homePos as noted above

mouse_up_event.target.x = mouse_up_event.target.homePos.x;
mouse_up_event.target.y = mouse_up_event.target.homePos.y;

}

That's basically it! By extending your movie clip instances to carry their own information, you can handle a complex drag and drop problem in a generic fashion much more efficiently than you could if you used separate variables to track the x and y locations of your draggable objects, targets, and home locations.

One final important note: If you create drag and drop using this method, where your drop target movie clips are themselves complex objects composed of nested movie clips, you need to set the mouseChildren property to false for the parent movie clip - the desired drop target clip. Failure to do so will cause the event.target.dropTarget to return one of the nested clips, and may not be what you expect.

See the full documentation in the FLA for the following example:.

Example 3: Drag Object to Specific Location

Content on this page requires a newer version of Adobe Flash Player.

Get Adobe Flash player

Drag Object to Specific Location Example File (FLA)


Multiple Pages Menu Scheme

As you begin to work on your final project, the organization of the scenes/pages can become very complicated it you do not use an efficient strategy. In previous unit example, you have been shown how to put scenes on different frames and to pass variables between the frames. An alternative method is to have all of the scenes on the same frame, but only make them visible when an action request (e.g. button) to view the scene. If your each of your scenes/pages are within a movieclip, you can use the "visible" property to decide when the user will be able to see the content. See the following action script:

//hide the movie clip with instance name of intro_mc
intro_mc.visible=false;

For your final project, using the visible property will make it very easy to implement the Quit required element. See the following example for implementing multiple pages and the quit option.

Content on this page requires a newer version of Adobe Flash Player.

Get Adobe Flash player

Multiple Page Menu Scheme File (FLA)

Here is the same FLA, but the pages have been positioned on top of each other to demonstrate the concept more as we would expect:

Content on this page requires a newer version of Adobe Flash Player.

Get Adobe Flash player

 

Summary

Using a single page navigation design will help you avoid situations where your swf creates null object errors. Because your actionscript and Flash content are all contained on one frame, your design is easy to code and understand, and debug as a result! Any interaction pertaining to specific pages can be contained within the page symbols. Save frame designs for animation, not navigation.