Tutorials, extensions, and source files for ActionScript, Flash, and other Adobe products.

 

Pages: 1 | 2 | 3 | 4 | 5

Display Objects

One of the more drastic changes (if not the most) in ActionScript 3 probably has to be working with display objects, or objects visible on the screen. Along with the well established and popular MovieClip (flash.display.MovieClip), ActionScript 3 supports additional display object instances including but not limited to:

Sprites are a new kind of light-weight MovieClip that doesn’t technically have any frames, at least not in the conventional sense.  In a more practical, Flash-like sense, you can see a Sprite as having one frame in which it keeps its content or children, but there is no navigation to any frames beyond that first. Since MovieClip instances you create dynamically through ActionScript cannot have frames anyway, chances are you'd want to use a Sprite in place of a MovieClip for all dynamically created MovieClip instances.

Shapes are like Sprites but are impeded by the fact that they offer no form of mouse or keyboard interactivity.  In other words, these display objects cannot receive events like mouseDown or keyUp.  Additionally, Shape instances cannot contain any other kind of display objects nor have children of their own.  You can only draw vector shapes within them using the vector drawing API (beginFill, lineTo, endFill, etc). This comes as an advatage to Shapes since they use less memory and are more efficient than MovieClips and Sprites.

Bitmap instances are much like Shapes except instead of being able to contain vector drawings, they contain bitmap images defined by a BitmapData instance.  They, too, cannot contain any other display objects or children. Like Shapes, Bitmaps cannot interact with the mouse and keyboard.

Loader is a Sprite-like display object which, like Sprite, has no timeline, but is designed specifically to facilitate the loading of external display content such as external SWFs and bitmap images. When loaded, those assets displayed in the Loader instance and are accessible through the Loader's content property.

You can read more in the Flash CS3 documentation about Core display classes.

Timeline based symbols

Most elements on the timeline which are not text or symbols from the library are created as Shapes instances.  These Shapes include not only vector drawings in Flash, but bitmap images as well; instead of using a Bitmap instance for the timeline, Flash uses a Shape instance drawn with a bitmap fill.

Shape tweens on the timeline, instead of a Shape instances, are represented by a new class called MorphShape (flash.display.MorphShape).  MorphShape instances cannot be created dynamically and offer limited interactivity through ActionScript.

As with previous versions of Flash, the only available symbol types for your library are movie clip, button, and graphic.  When on the timeline, movie clip symbols are represented as MovieClip instances; buttons, instances of a top level Button class in ActionScript 2, are now instances of a new class called SimpleButton (flash.display.SimpleButton); and graphic symbols become, because of their lack of interactivity, Shape instances.  As a Shape, however, graphic symbols are not allowed to contain other children like MovieClips.  If you have an instance of a MovieClip in a graphic symbol, that MovieClip will become a child of the graphic's parent during playback, escaping from what would be the containing Shape instance..

For text, there are now two classes, TextField (flash.text.TextField) and StaticText (flash.text.StaticText).  The TextField class is for dynamic and input text.  As with previous versions of ActionScript, these kinds of text fields can be created dynamically through ActionScript.  The StaticText class used to represent static text on the timeline, however, cannot be created dynamically.  These instances are only available when a static text field has been placed on a timeline in Flash.

Note: Text Fields and Var

In older versions of ActionScript, you could assign a variable (Var) to be associated with a text field on the screen through the Property Inspector panel. This variable would reference the text value of that field. Like being able to define scripts on selected objects, this too has been removed as a feature for ActionScript 3. Instead you would need to use the text property of the text field through its instance name.

The most common way to gain access of text and symbol display objects on the screen through ActionScript is to assign them an instance name.  This name is added through the instance name field in the property inspector of the selected instance in Flash. 


Figure: Dynamic text field with instance name "myText"

By assigning an instance name, you are doing two things.  First you are assigning the name property of that instance to that of the instance name provided.  Secondly you are creating a variable in the timeline with the name of the instance name that, when the instance is present in the timeline, references that instance; otherwise its value is null.

Note: Changes with the name property in ActionScript 3

The name property in ActionScript 3 and the _name property in previous versions of ActionScript do not behave the same.  In ActionScript 2, by changing the _name property of a movie clip in ActionScript you also changed the timeline variable used to access that movie clip.

// ActionScript 2 changing _name
// Original movie clip instance name: my_mc
trace(my_mc); // traces _level0.my_mc
my_mc._name = "same_mc";
trace(same_mc); // traces _level0.same_mc
trace(my_mc); // traces undefined

With ActionScript 3 you cannot change the name property of a display object if it was placed on the timeline in Flash (you can if the object was dynamically created).  Even if you could, it would not change the variable used to reference that instance as they are not connected like they were in ActionScript 2.

As with ActionScript before, all display objects have a common set of properties that describe their presentation on the screen in Flash.  This includes properties for location, size, and color etc. In ActionScript 3, however, many of these properties' names have changed.  More specifically, the underscores used to preceded these properties are no more.  The x and y positions are no longer represented with _x and _y but simply x and y.  Similarly, the values to which some of these properties can be defined has also changed.  The scaleX, scaleY, and alpha properties, for example, no longer range from 0-100 but now 0-1 (scale properties still able to go beyond these bounds).  This may be something to watch for if you are porting code from older versions of ActionScript to ActionScript 3.  Not only have the property names changed, but also their potential values.

// ActionScript 2
myMovie._x = 50; // x position of 50
myMovie._xscale = 200; // 200% horizontal scale
myMovie._alpha = 50; // 50% transparent
// ...

// ActionScript 3 
myMovie.x = 50; // x position of 50
myMovie.scaleX = 2; // 200% horizontal scale 
myMovie.alpha = .5; // 50% transparent
// ...
Common MovieClip Property Names
ActionScript 2 ActionScript 3
_name name
_x x
_y y
_width width
_height height
_xscale (0-100) scaleX (0-1)
_yscale (0-100) scaleY (0-1)
_rotation rotation
_alpha (0-100) alpha (0-1)
_visible visible
_xmouse mouseX
_ymouse mouseY
_parent parent

Understanding the Class Inheritance Hierarchy

If you look a the documentation for a class like MovieClip (flash.display.MovieClip), you may notice that there may not be many definitions specific to the MovieClip class. There are only 9 properties and 10 methods. You won't see definitions for properties like name, x, y, etc. unless you click the "Show Inherited Public Properties/Methods" link at the top of those lists (these links appear as "Hide Inherited Public Properties/Methods" if the definitions are already visible) since those properties are not unique to the MovieClip class. Sure, the MovieClip class has those properties, but these properties are actually defined within another class and MovieClip inherits them to use as its own.

Since many classes use the same properties and methods in the same way - MovieClip, Sprite, and Shape, for example, each have x, and y properties and use them the same way - classes can be defined to reduce redundancy by having similar members defined in a single location (class) and then referencing those definitions for their own use. This is handled through what is known as class inheritance. A single base class (a.k.a. superclass) has definitions which may derived classes (a.k.a. subclasses) can use as their own as long as they do what is called extending that class.

It's an OOP concept, and though you may not be working specifically with OOP when you're programming ActionScript yourself, this is in particular is helpful to understand because the documentation is set up to reflect this association. And the documentation is something you should be very dependant on, especially when you first start learning ActionScript (or any language for that matter).

Taking a look back at the top of the MovieClip documentation page, you can see a path that represents the location of MovieClip within its inheritance hierarchy. For MovieClip this path is:

MovieClip > Sprite > DisplayObjectContainer > InteractiveObject > DisplayObject > EventDispatcher > Object

This shows that MovieClip inherits from Sprite and has all the properties and methods that Sprite does, which itself, has all the properties and methods that DisplayObjectContainer has... and so on and so forth until you reach the base class Object, the class from which all other classes in ActionScript inherit. This path shows just how similar MovieClips and Sprites really are. They are practically the same except for the extra frame-related properties and methods that are uniquely defined for MovieClip. Similarly all other objects that are visible on the screen will inherit from DisplayObject. And you know all the properties defined within the DisplayObject class will be within any display object instance that can be made visible on the stage in Flash. So don't be surprised when you click on the x link to look up the documentation of the x property and find yourself on th DisplayObject documentation page. They are one in the same.

Note: The Class Hierarchy and Typing

The types that these classes within the MovieClip class hierarchy represent, and the fact that there are so many within hierarchy (in ActionScript 2, MovieClip inherited only from the Object class) will become important later as types are discussed. For now, understand that an instance can be typed as it's own class type or any of the classes from which it inherits. A MovieClip, for example, can be correctly typed as DisplayObject.

Example: Referencing Movie Clips in the Timeline

In this example, you will create some display objects in the main timeline and use ActionScript to change their properties.

  1. Create a new ActionScript 3 document in Flash CS3

The Display List

The display list in ActionScript 3 represents the visual hierarchy of objects or display objects on screen within the Flash player. This starts with a top-most, always present display object known as the stage followed by the main timeline, or root, and all children within the main timeline as well as their children.


Figure: Example display list starting with stage instance

Usually when referring to the display list, you're referring to the entire display list within the Flash player. This is also sometimes called the active display list. However, you may also see the term display list used with individual display object containers - display objects of the type DisplayObjectContainer (flash.display.DisplayObjectContainer) which can contain other display objects (e.g. Sprite and MovieClip instances) - where each container is said to have their own display list. The display list of any container consists of all of that container's child display objects and all children within those children.

In AVM1 with ActionScript 2, it was not possible for a movie clip instance to exist without it being attached to some timeline and effectively being a part of the SWF's display list. AVM2 and ActionScript 3 has changed that. Now it is possible for display objects to exist within memory but not be associated with any particular timeline and therefore not be on screen. When this is the case, these instances are said to be off-list as they are not within the active display list and can only be referenced through ActionScript.

Also different with ActionScript 3 is how arrangement, or depth, is handled. Before, all movie clips could be placed in just about any depth where movie clips on the timeline actually initially existed in negative depths. Now all depths start at 0 and are contiguous. In other words, if you have 2 display objects within a container, they will have to exist at depths 0 and 1. You cannot have one at depth 0 and the other at 10 leaving 9 empty depths. This ultimately could mean less flexibility, but at the same time there is a more concise understanding of the arrangement of display objects within the display list since, if you know there are 5 objects in a display object container, you know at exactly which depths they occupy.


Figure: Depths in ActionScript 3 are contiguous and cannot be negative

The root and stage

The main timeline of a FLA or SWF is known as the root timeline. In ActionScript 2, you could access this timeline directly using the _root property. This reference continues to exist in ActionScript 3, but is now called root.

ActionScript 2 also had a class or object called Stage. Using the Stage object you could determine the size of the Flash player window, check to see when that size has changed, and specify how content was affected when it did change, etc. The concept of the stage also exists in ActionScript 3, but now it has taken a new form; instead of just being just an object or static class, the stage is an instance that also acts as the top-most display object in the display list hierarchy. It is the Flash player container for which all other SWF content on screen. Whereas in ActionScript 2, the main timeline was the top-most display object in the display list, in ActionScript 3 it is the stage instance followed by the main timeline (root) as its first child. As with the root property, you can access the stage instance in ActionScript 3 using the stage property (note the lowercase "s").

There are 2 very important qualities about root and stage that you need to come to terms with when working with ActionScript 3:

  1. The root and stage properties in ActionScript 3 are not global. These properties are instead properties of the DisplayObject class, so only display object instances have access to them. Other classes, namely custom classes, do not have access unless explicity given access by another class that does.
  2. The root and stage properties will be null unless the display object from which they are being referenced is a child of the active display list. Off-list display objects will not be able to access the root timeline and the stage through those respective properties.

When coding within the main timeline in Flash CS3 and not creating dynamic display object instances with ActionScript, these qualities normally don't apply. This is because you're writing ActionScript within a display object's timeline who gets automatically added to the active display list by Flash making the root and stage properties immediately available. Creating display objects dynamically means that you are working with an instance that starts off-list, and won't have access to root or stage until added to the active display list through ActionScript

// Main timeline in Flash CS3
// The main timeline always has access to root and stage
trace(root); // traces "[object MainTimeline]"
trace(stage); // traces "[object Stage]"

In the above example you can see that the output of tracing root actually produces an object instance of the type MainTimeline. This is an automatic MovieClip-based class that Flash generates to represent the instance used for the root timeline - It's basically just a MovieClip under a different name. The stage, similarly, is an instance of the Stage class (flash.display.Stage). This same output would be seen if this code was placed in the timeline of a movie clip placed on the main timeline.

Dynamic display objects

When you created dynamic movie clips in ActionScript 2, you had basically 3 options: you could duplicate an existing movie clip on the screen using duplicateMovieClip(), you could create an empty movie from scratch with createEmptyMovieClip(), or you could create an instance of a movie clip symbol within your library through attachMovie().

In ActionScript 3, it's all much simpler. All you need to do to make a dynamic movie clip is create a new instance of it like you would any other class using the new keyword. For new empty MovieClip instances, you just use new MovieClip(), or better yet, new Sprite() since empty MovieClip instances cannot be given new frames (and a Sprite is just a MovieClip with no frames).

// Create a new, dynamic, off-list Sprite
var mySprite:Sprite = new Sprite();

Because display objects in ActionScript 3 can exist off screen (off-list) creating a new dynamic instance in this manner does not mean that the new instance is visible on the screen. Before it can be made visible, it has to be added to the active display list. To do that you use one of two methods: addChild() which adds a display object at the end of a display list, or addChildAt() which adds a display object at a specific location within a display list.

// Create a new, dynamic, Sprite and add
// it to the current timeline's display list
// (ActionScript 3 equivalent to createEmptyMovieClip)
var mySprite:Sprite = new Sprite();
addChild(mySprite);

New Sprite instances, however, contain no content by default. Even though the above example places a Sprite on the screen, it cannot be seen because there's nothing in it to see. It's more likely that in Flash you would want to dynamically create an instance of a movie clip symbol in your FLA's library. Before you can create an instance of a movie clip that exists as a symbol in your library, then you first need to give that symbol a class name within the Linkage dialog (right or command-click on that symbol and select Linkage...) for that symbol.

In the Linkage dialog, you have a number of checkboxes providing you with some options for your symbol. Under Linkage you have two primary options, Export for ActionScript and Import for runtime sharing. Import for runtime sharing allows you to load in symbols from external SWFs. For dynamic movie clips, you need to Export for ActionScript. Additional options related to Export for ActionScript include Export for runtime sharing which is related to Import for runtime sharing, and Export in first frame which assures that your SWF will load this movie clip into the Flash Player prior to any of your frame scripts making it available for dynamic creation at any time.

Once Export for ActionScript is selected, two text fields within the Linkage dialog appear, Class and Base class. The Class field is the most important for creating dynamic movie clip instances from your library. It is needed to uniquely identify the symbol with a class (which will be automatically generated for you behind the scenes) so that it can be created with the new keyword. The Base class identifies the class from which the symbol inherits. Since you're working with movie clip symbols, this will usually be MovieClip, the default value. When working with custom classes, you could decide to put your own class as the Base class.


Figure: Assigning a custom class name to a movie clip in the library

Once a class name is specified for a movie clip symbol, you can create an instance of it with the new keyword and then add it to the active display list using addChild or addChildAt. The class name you defined represents the ActionScript 3 version of the ActionScript 2 linkage ID.

// Create a new, dynamic movie clip from the library
// and add it to the current timeline's display list
// (ActionScript 3 equivalent to attachMovie)
var myMovie:CustomMovieClass = new CustomMovieClass();
addChild(myMovie);

For every movie clip symbol (this also works with button symbols, though the Base class would be SimpleButton) you wish to add to the screen or create dynamically, you would need to define a unique class so that those instances can be created and added to the display list as seen above.

Unfortunately, there is no ActionScript 3 equivalent to duplicateMovieClip. Butin reality, it's not a function that the Flash world has had a whole lot of dependancy on since the introduction of attachMovie in Flash 5. ActionScript 3 developers will have to get by with out it.

Bitmaps

Bitmap images are another form of media that can exist within your Flash library. They too can be created and added to the screen dynamically with ActionScript 3. The images as they exist in the library, however, do not directly translate to on-screen display objects like movie clips do. Instead, images in the library represent BitmapData (flash.display.BitmapData) instances in ActionScript. To be visible on the screen, this data needs to be given to a Bitmap (flash.display.Bitmap) instance.

As with movie clips in the library, when creating bitmap images dynamically from your library in Flash, you need to assign it a unique class name through the Linkage dialog. This is done the same way it is done with movie clips only the base class for bitmaps will be BitmapData as opposed to MovieClip.

When you create new BitmapData instances with ActionScript, it is required that both a width and height be supplied for the new instance as it defines the size for that instance. Since images in your library are based off of the BitmapData class, they too require that width and height be set for them when new instances are created. Images in your library, however, already exist with a set width and height so the values used when creating new instances of your library bitmap image do nothing. If you know the image size you should use that; otherwise 0 works fine.

Once you create an instance of your library image, you need to give it to a Bitmap instance before it can be seen on the screen. This can be done through the Bitmap constructor or by setting the bitmapData property of the Bitmap instance. That Bitmap instance would then need to be added to the active display list before it could be made visible in Flash.

// Create an instance of a library bitmap 
// given the Class name of MyImage
var imageData:MyImage = new MyImage(0, 0);

// Give the instance to a Bitmap through its 
// constructor, then add it to the display list 
var imageBmp:Bitmap = new Bitmap(imageData);
addChild(imageBmp);

Removing

Once you have a display object on the screen, and it's time for it to be removed, you can use one of two removal methods, removeChild() which removes the specified display object from a display list, and removeChildAt() which removes the child at a specific location within a display list.

// Add movie clip from the library to display list
var myMovie:CustomMovieClass = new CustomMovieClass();
addChild(myMovie);

// Remove movie clip from the library from display list
removeChild(myMovie);

There are two important points to display object removal in ActionScript 3:

  • Removal is handled through the parent display object container, not the child as was the case with removeMovieClip() in ActionScript 2 (parentObject.removeChild(childObject) vs. childObject.removeMovieClip()).
  • Removing a display object from a display list does not destroy the display object or remove it from Flash's memory. As long as you still have a reference to a display object, it will still exist off-list even if not as a child of any other timeline or container.

The latter is especially important for ActionScript 2 veterns who are used to having movie clip references become invalid after the object has been removed from the screen. This is no longer true in ActionScript 3 since the instance remains valid, just off-list. To truely get rid of the instance, all references would need to be deleted (if dynamic) or set to null, just like any other kind of non-display object in ActionScript.

The first point should also not be seen as unimportant. This is a reflection of how you should be working with ActionScript - starting at the outside looking in as opposed to being on the inside looking out, which has become a popular approach for many ActionScript 2 developers, espcially commands like removeMovieClip which work from the child removing itself from it's own parent. What this basically means is that when working with movie clips and timelines, the best approach when writing script is not to be within a movie clip referencing data and methods that exist outside that movie clip, but instead to be looking into child movie clips and letting parent containers look into that movie clip. The less dependancy any movie clip or timeline has on objects outside of itself, the better.

Other properties and methods in addition to the add and remove methods that are useful when working with movie clips include those found in the DisplayObjectContainer class (flash.display.DisplayObjectContainer). These include:

  • numChildren
  • getChildAt
  • getChildByName
  • getChildIndex
  • setChildIndex
  • swapChildren
  • swapChildrenAt

Most are pretty self explanitory. For more information consult the DisplayObjectContainer documentation.

Tip: Reducing Display Object References

Since removeChild does not remove a display object from memory, only the removal of all references, you can limit your references to dynamic display objects by not creating any. Instead you can take advantage of the fact that addChild returns a reference to the added display object and use it to define a name for the new object added (which can be created directly within the call to addChild). Then if you ever need to reference the display object, you can use getChildByName.

// Minimize display object references
addChild(new CustomMovieClass()).name = "myMovie";
getChildByName("myMovie").x = 100;

If no other references are made, removing the child from its parent will remove it from memory (assuming the garbage collector catches it; for more information on how the garbage collector in Flash works, see Grant Skinners article AS3: Resource Management).

Example: Creating Dynamic Instances from the Library

This example will add symbols and bitmaps from the library randomly to the document at different locations on the screen. Then, based on their locations, a script will rearrange the objects so that the lower objects are positioned above the objects that are higher for the appearance of perspective.

Steps:

  1. In the source files, open RandomTreesWithArrangement.fla in the DisplayObjects directory. This file consists of one empty layer named ActionScript and two objects in the library, a tree movie clip symbol, and a tree.png bitmap image


Figure: Tree movie clip and bitmap assets

In order to be able to dynamically create the objects in the library with ActionScript 3, you will need adjust their linkage options and provide a unique class name by which to reference them.

  1. Right-click (Command-click on Mac) on the tree movie clip symbol in the library
  2. Select Linkage... from the context menu


Figure: Setting linkage properties from the library

  1. In the linkage dialog select Export for ActionScript
  2. Type for the Class name: Tree
  3. Repeat the steps fot the tree.png image only for its class use: TreeImageData
    Notice that BitmapData is the Base class for the image whereas for the movie clip it was MovieClip


Figure: Class name for tree.png bitmap

With the linkage definitions set up, we can now start coding the ActionScript to create them. First, define some variables that will apply to the example. In this case, there is only one, treeCount, to determine how many trees to generate.

  1. Select the first frame in the ActionScript layer and open the Actions panel.
  2. Add the following script to the Actions panel
// The number of trees to generate
var treeCount:int = 20;

Next we can define a function to generate the trees. This will rely heavily on the Math.random() function to

  1. determine if a movie clip or bitmap version of the tree is created and
  2. where on the screen (x and y locations) it is placed

A loop will be used to create and place the trees based on the value of treeCount which will be passed into the function when it is called.

  1. Add the following script to the Actions panel
// Create a number of trees randomly
// positioned within the document
function createTrees(numberOfTrees:int):void {
	
	// variable to store trees created
	// in the loop - the DisplayObject
	// type satisfies both MovieClip
	// and Bitmap instances
	var currTree:DisplayObject;
	
	// loop through the number of trees
	while(numberOfTrees--){
		
		// randomly add a tree either
		// as a bitmap or a movie clip
		if (Math.random() < .5) {
			
			// create a new Tree instance
			// Tree is the class name given to
			// the tree symbol in the library
			currTree = new Tree();
			
		}else{
		
			// create the tree BitmapData instance
			// from the library, then add it to a
			// new Bitmap instance
			var currTreeData:TreeImageData = new TreeImageData(0, 0);
			currTree = new Bitmap(currTreeData);
		}
		
		// position the new instance randomly on
		// the screen based on the stage's size.
		// subtracting the tree size from the stage
		// size keeps the trees on screen
		currTree.x = Math.random() * (stage.stageWidth - currTree.width);
		currTree.y = Math.random() * (stage.stageHeight - currTree.height);

		// don't forget to add the tree
		// to the display list
		addChild(currTree);
	}
}

As it is now, we can call the createTrees function and trees from the library will be created and added to the screen dynamically.

  1. Add the following script to the Actions panel
// Create the trees
createTrees(treeCount);
  1. Test your movie. You should see the following


Figure: Dynamic random tree objects

Because these trees were added dynamically and randomly, their arrangement does not seem quite right. You can see that trees higher on the screen seem to be overlapping those below them when you would expect the opposite to be true.

In ActionScript 2, this could easily be fixed during the creation of the tree objects by setting their depth to equal their y position. This does not work in ActionScript 3 since you cannot have and gaps in the display list - all depths must be contiguous. A solution for ActionScript 3 would be to put your objects in an array and sort that array based on the objects y (or other) value. That array's sorted arrrangement can then be used for the display list's arrangement. A new function can be created to facilirate that.

  1. Add the following script to the Actions panel
// Arrange all children in the specified
// container based on their y value
function sortChildrenByY(container:MovieClip):void {
	var i:int;
	var childList:Array = new Array();
	
	// first put all children in an array
	i = container.numChildren;
	while(i--){
		childList[i] = container.getChildAt(i);
	}
	
	// next, sort the array based on the
	// elements' y property
	childList.sortOn("y", Array.NUMERIC);
	
	// now match the arrangement of the array
	// with the arrangement of the display list
	i = container.numChildren;
	while(i--){
		
		// if the child at position i in the array
		// does not match the child at position
		// i in the display list, set that child
		// to the i position in the display list
		if (childList[i] != container.getChildAt(i)){
			container.setChildIndex(childList[i], i);
		}
	}
}

This function takes any container MovieClip and arranges its children so that the higher they are on the screen the lower they are in the display list using array-based sorting.

All that remains is calling this new function using the current timeline so that the trees created earlier will be properly arranged.

  1. Add the following script to the Actions panel
// Arrange the trees
sortChildrenByY(this);
  1. When you've completed adding the code, test your movie. You should see the following


Figure: Dynamic tree objects with arrangement

The similarities of the display list to an array makes it easy to use arrays for sorting display lists like this. Similarly, you could implement your own sorting algorithm using just the display list and methods like getChildAt() and setChildIndex() without the aide of arrays.

Dynamic graphics

Since Flash MX, ActionScript has had a drawing API for creating dynamic vector graphics in Flash. This API consists of methods like beginFill(), moveTo(), lineTo(), and curveTo() used within MovieClip instances. ActionScript 3 continues to make these methods available but they are no longer used with MovieClip instances, or even DisplayObject instances for that matter. Instead, they are used with Graphics (flash.display.Graphics) instances.

The Graphics class is now used to facilitate all dynamic drawings. Instances of this class are available as graphics properties within the classes that allow you to draw in them dynamically. These classes include:

  • Shape
  • Sprite
  • MovieClip
// Create a blue triangle with a red
// outline within the current timeline
graphics.lineStyle(2, 0xFF0000);
graphics.beginFill(0x0000FF);
graphics.moveTo(50, 0);
graphics.lineTo(100, 100);
graphics.lineTo(0, 100);
graphics.endFill();

When drawing methods are used for the Graphics object within these instances, dynamic drawings are created within a drawing layer within those instances. For Sprite and MovieClip, this drawing layer exists below child objects within their display list. There is no way to draw dynamic vectors above children of a Sprite or MovieClip instance.

In addition to the methods available in ActionScript 2, ActionScript adds some new methods to make drawing simple shapes like rectangles and circles a lot easier. These methods include:

  • drawCircle
  • drawEllipse
  • drawRect
  • drawRoundRect
  • drawRoundRectComplex

Example: Dynamic Drawings Created with ActionScript

This example uses the vector drawing API to create a checkerboard with ActionScript. It will use two of the new API methods, drawRect and drawCircle.

Checkerboards are a little tricky because they're checkered. This means that every other space within the checkerboard grid is the opposite color than the one adjacent to it. With ActionScript, the modulous, or mod, operator (%) can be used to help determine what color any location is base on the x and y location within the board. This will be helpful when creating checkboard and drawing each of the board's spaces.

The general idea here is to generate a checkerboard graphic within the main timeline and then add on top of that graphic a collection of checkers that could be played with in a checker game. Though there will be no interaction assigned to these checkers in this example, there could be some down the line, so each are placed in their own Sprite instance when added to the board allowing for each to be interacted with independently.

Steps:

  1. In the source files, open DrawingAPICheckerBoard.fla in the DisplayObjects directory. This file consists of one empty layer named ActionScript.
  2. Select the first frame in the ActionScript layer and open the Actions panel.

The first thing to do is define some variables that can be used to control the script. For this example, we will want control over the checkerboard color, the checkerboard space size and the size of the checkers within those spaces.

  1. Add the following script to the Actions panel
// Set up some variables
var player1Color:uint = 0x000000;
var player2Color:uint = 0xFF0000;
var spaceSize:Number = 40;
var checkerSize:Number = 30;

Next we'll define a function for drawing the board. This will use two for loops to loop through and draw each space in the board with the drawing API based on the space size. Using mod with the locations in the board grid (spaceX and spaceY), the correct color of that location can be determined.

  1. Add the following script to the Actions panel
// Draws the checkerboard
function drawBoard():void {
	var currColor:uint;
	var spaceX:int;
	var spaceY:int;
	
	// loop through x and y coordinates of board
	for (spaceX = 0; spaceX < 8; spaceX++){
		for (spaceY = 0; spaceY < 8; spaceY++){
		
			// alternate colors using modulous
			currColor = (spaceX%2 != spaceY%2) ? player1Color : player2Color;
			
			// draw square in graphics object

			// this will be drawn in the current timeline
			graphics.beginFill(currColor);
			graphics.drawRect(spaceX*spaceSize, spaceY*spaceSize, spaceSize, spaceSize);
			graphics.endFill();
		}
	}
}

Now the checkers drawing function can be defined. To make it a little easier to draw a large number of checkers, this function can be used to draw an entire row at a time. Each checker is drawn in a sprite and that sprite is added to the active display list (of the current timeline) so it can be seen on screen.

  1. Add the following script to the Actions panel
// Draws a row of checkers on the checker
// board. Each checker is in it's own Sprite
function drawCheckerRow(rowNumber:int, playerColor:uint):void {
	var spaceX:int;
	var checkerOffset:Number = spaceSize/2;
	var checkerRadius:Number = checkerSize/2;
	var checker:Sprite;
	
	// loop through each column in the row
	// skipping every other column
	for (spaceX = (rowNumber + 1)%2; spaceX < 8; spaceX += 2){
	
		// create a new Sprite for the checker
		checker = new Sprite();
		checker.x = spaceX*spaceSize + checkerOffset;
		checker.y = rowNumber*spaceSize + checkerOffset;
		
		// draw checker in checker sprite's graphics
		checker.graphics.lineStyle(2, player2Color);
		checker.graphics.beginFill(playerColor);
		checker.graphics.drawCircle(0, 0, checkerRadius);
		checker.graphics.endFill();
		
		// be sure to add it to the display list
		addChild(checker);
	}
}

All that remains is calling the functions so the drawings can be made. For a new checkerboard setup, you need 3 rows of checkers for each player, 6 total.

  1. Add the following script to the Actions panel.
// Call drawing functions drawing
// checkerboard and checkers
drawBoard();
drawCheckerRow(0, player2Color);
drawCheckerRow(1, player2Color);
drawCheckerRow(2, player2Color);
drawCheckerRow(5, player1Color);
drawCheckerRow(6, player1Color);
drawCheckerRow(7, player1Color);
  1. When you've completed adding the code, test your movie. You should see the following


Figure: Dynamically drawn checkerboard

The inclusion of the drawRect and drawCircle methods really made this a lot easier in ActionScript 3. In ActionScript 2, you would have to draw each line or curve individually or create your own functions that behaved like drawRect and drawCircle.

Note: Working with Display Objects

This section has only covered the basics in display object usage and their characteristics. There are many other important topics that relate to display objects that are covered in more detail in later sections.

Continue reading »

Pages: 1 | 2 | 3 | 4 | 5