flash predefined_symbols_instancing
Instancing symbols through programming
As in ActionScript 1 and 2, a clip symbol can not be dynamically attached by programming if the Export for ActionScript option in the Linking properties panel is not activated.
In reality we don’t give a name to the clip link any more in ActionScript 3, but we specify a class name.
In ActionScript 3’s publication mode the Identifier field is greyed out so we can no longer use it.
By selecting our Ball symbol in the library we chose the link option then we check the Export for ActionScript box:
The Basic class field indicates the class which our symbol will inherit. Once the Export for ActionScript option is checked it is automatically checked. Our Ball symbol is a clip and therefore inherits the flash.display.MovieClip class.
The class field contains by default the symbol name in the library. The new thing here is that it is possible to define a class name associated with the symbol. We keep Ball.
When clicking OK, Flash CS3 searches for a class called Ball within our .fla file. If it doesn’t find a class with this name it automatically generates one.
The following panel shows us this information:
Beware that this class will not be accessible for editing. It will be used internally by the compiler to instantiate our symbol.
Instantiating predefined symbols
In ActionScript 1 and 2 the attachMovie method allowed you to attach symbols through programming. From the outset this method wasn’t very simple to comprehend, its numerous parameters made memorizing it difficult. Furthermore we were obliged to call this method on an instance of MovieClip forcing us to keep a reference to the clip to be able to instantiate other clips from the library.
In ActionScript 3 the keyword new allows us to instantiate the symbols present in the library and therefore offer much more flexibility in the attachMovie method.
We can write the following code to instantiate our Ball symbol without any reference to an existing MovieClip:
var myBall:MovieClip = new Ball();
The use of the keyword new to instantiate graphic objects and particularly symbols resolves another great weakness of ActionScript 2 that we will look at in the article Extending native classes.
We have used the movieClip to store the reference to our instance of the ball symbol, even though this symbol has a specific type that we have informed using the Linking properties panel.
In the line below we type the variable with the help of our Ball:
var myBall:Ball = new Ball();
In testing our Ball clip we can see that it has many communal types:
var myBall:Ball = new Ball(); // displays : true trace( myBall is MovieClip ); // displays : true trace( myBall is Ball );
Remember that our graphic object is outside the display list at the moment. To see it we add our symbol to the main timeline using the addChild method:
var myBall:Ball = new Ball(); addChild ( myBall );
Our symbol is positioned at 0 on the X axis and at 0 on the Y axis.
The instance of the Ball class is therefore consists of a MovieClip wrapper containing a vetcorial shape which is in this case a circle. It would therefore seem obvious that the wrapper contains a child graphic object of the flash.display.Shape type. The following code gets the child object of our Ball clip with the help of the getChildAt method:
var myBall:Ball = new Ball(); addChild (myBall); // displays : [object Shape] trace( myBall.getChildAt ( 0 ) );
We could delete the content of our clip with the removeChildAt method:
var myBall:Ball = new Ball(); addChild (myBall); // displays : [object Shape] trace( myBall.removeChildAt ( 0 ) );
ActionScript 3 offers an unprecedented flexibility for the manipulation of graphic objects.
It would be interesting to instantiate many Ball objects and to position them randomly on the stage with different sizes. To do this we will go into a for loop to create multiple instances of the Ball class and add them to the display list:
var myBall:Ball; for ( var i:int = 0; i< 10; i++ ) { myBall = new Ball(); addChild( myBall ); }
If we test the previous code we obtain ten instances of our Ball class positioned at 0,0 on our stage.
This is a behavior that has always existed in Flash player. All the objects displayed are positioned by default at 0 for both the X and Y axis.
We will randomly position them on the stage using the Math.random() method.
We will therefore have to recuperate the total size of the stage to know what size to generate our random values for the X and Y axis. In ActionScript 1 and 2 we would have written:
myBall._x = Math.random()*Stage.width; myBall._y = Math.random()*Stage.height
In ActionScript 1 and 2, the Stage.width and Stage.height properties returned the size of the stage. In ActionScript 3 the Stage object has four properties relative to its size which may seem disconcerting.
The width and height properties still exist but return the width and height occupied by the group of DisplayObjects contained by the Stage object:
In an empty SWF the stage.width and stage.height properties return 0.
The illustration above shows an animation where three instances of the *Ball* symbol are placed on the stage. The stage.width and stage.height properties return the surface occupied by the graphic objects present in the display list.
To get the total size of the stage and not the surface occupied by the graphic objects we use the stage.stageWidth and stage.stageHeight properties:
// displays : 550 trace( stage.stageWidth ); // displays : 400 trace( stage.stageHeight );
In generating a random value on the total width and height we randomly position our instances of the Ball symbol:
var myBall:Ball; for ( var i:int = 0; i< 10; i++ ) { myBall = new Ball(); myBall.x = Math.random()*stage.stageWidth; myBall.y = Math.random()*stage.stageHeight; addChild( myBall ); }
The code generates the following animation:
If we don’t want to see our occurrences leaving the stage, we will integrate a constraint by generating a random taking into consideration the size of occurrences.
var myBall:Ball; for ( var i:int = 0; i< 10; i++ ) { myBall = new Ball(); myBall.x = Math.random()*(stage.stageWidth - myBall.width); myBall.y = Math.random()*(stage.stageHeight - myBall.height); addChild( myBall ); }
Random positioning of the Ball class without overflowing instances:
Worth remembering
- To instance a predefined symbol we use the keyword new.
- The stage.width and stage.height properties return the size occupied by the DisplayObject present in the display list.
- To get the dimensions of the stage, we use the stage.stageWidth and stage.stageHeight properties.
- To get the dimensions of the stage we use the properties.
Dynamically extracting a class
In previous versions of ActionScript we could store the names of symbol links in the array, then traverse it in order to attach the graphic objects:
// array containing the link identifiers of symbols var ArrayLinks:Array = ["polygon", "Ball", "polygon", "square", "polygon", "square", "square"]; var lng:Number = ArrayLinks.length; var ref:MovieClip; for ( var i:Number = 0; i< lng; i++ ) { // display of symbols ref = this.attachMovie ( ArrayLinks[i], ArrayLinks[i] + i, i ); }
By using the keyword new in order to instantiate graphic objects, we can instantiate a graphic object using a simple character string.
To create the equivalent code in ActionScript 3, we must first extract a definition of the class then instantiate this definition. To do this we use the flash.utils.getDefinitionByName function:
// array containing class names var ArrayLinks:Array = ["Polygon", "Ball", "Polygon", "Square", "Polygon", "Square", "Square"]; var lng:Number = ArrayLinks.length; var Reference:Class; for ( var i:Number = 0; i< lng; i++ ) { // extraction of class references Reference = Class ( getDefinitionByName ( ArrayLinks[i] ) ); // instancing var instance:DisplayObject = DisplayObject ( new Reference() ); // added to the display list addChild ( instance ); }
This functionality allows the evaluation of the class name to be extracted in a dynamic way. We could imagine an XML file containing the name of different classes to instantiate. A simple XML file could therefore describe a whole graphic interface by specifying the graphic objects which would need to be instantiated.
Worth remembering
- The function getDefinitionByName allows you to extract a class definition in a dynamic way.
The button symbol
When we create a button in the author environment it is no longer a Button type as in ActionScript 1 and 2 but is a flash.display.SimpleButton type.
It is totally possible to create and graphically enrich buttons through coding which was impossible with previous versions of Flash. We cover this subject in the article entitled Interactivity.
We will create a button in the current document then place an instance of it on the main stage. In our example the button is a rectangle as shown below:
We give it the instance name of myButton then we test the following code:
// displays : [object SimpleButton] trace( myButton );
When testing our animation we can see that our myButton button displays a cursor when you hover over it representing a clickable object. To trigger a specific action when we click on it we use the event model that we discussed in the article The event model.
The event broadcast by the SimpleButton object when a click is detected is the MouseEvent.CLICK event.
We attach a listener function to it by targeting the flash.events.MouseEvent class:
myButton.addEventListener( MouseEvent.CLICK, clickButton ); function clickButton ( pEvt:MouseEvent ):void { // displays : [object SimpleButton] trace( pEvt.target ); }
Our clickButton function executes on each click of the myButton button. The target property of the broadcasted event object gives us a reference to the object which broadcase the event, in this case our button.
In order to dynamically attach our instances of the Ball symbol when clicking on our myButton button, we place the instantiation process, which we previously created, in the clickButton function:
myButton.addEventListener( MouseEvent.CLICK, clickButton ); function clickButton ( pEvt:MouseEvent ):void { var myBall:Ball for ( var i:int = 0; i< 10; i++ ) { myBall = new Ball(); myBall.x = Math.random()*(stage.stageWidth - myBall.width); myBall.y = Math.random()*(stage.stageHeight - myBall.height); addChild ( myBall ); } }
When clicking our button, ten instances of the Ball symbol are attached to the main timeline:
We risk being confronting by an overlap problem so it would be interesting to raise our button to the foreground to avoid it being masked by the instances of theBall class as illustrated here:
To bring a graphic object back to the foreground we need to work on the index in the display list. We know that the numChildren property returns us the total number of children numChildren-1 corresponds therefore to the highest object index in the pile.
By exchanging the index of our button and the last child object with the setChildIndex method we obtain the anticipated result:
myButton.addEventListener( MouseEvent.CLICK, clickButton ); function clickButton ( pEvt:MouseEvent ):void { var myBall:Ball for ( var i:int = 0; i< 10; i++ ) { myBall = new Ball(); myBall.x = Math.random()*(stage.stageWidth - myBall.width); myBall.y = Math.random()*(stage.stageHeight - myBall.height); addChild( myBall ); } setChildIndex ( myButton, numChildren - 1 ); }
Here is the result:
The addChild method stacks each instance without ever deleting the graphic objects already present on the stage.
To delete all of the graphic objects we can search the stage deleting each occurrence of the Ball type. The idea would be to add a clean function before the for loop, in order to delete the Ball symbol occurrences already present on the stage:
myButton.addEventListener( MouseEvent.CLICK, clickButton ); function clean ( pContainer:DisplayObjectContainer, pClass:Class ):void { var myDisplayObject:DisplayObject; for ( var i:int = pContainer.numChildren-1; i >= 0; i-- ) { myDisplayObject = pContainer.getChildAt ( i ); if ( myDisplayObject is pClass ) pContainer.removeChild (myDisplayObject); } } function clickButton ( pEvt:MouseEvent ):void { clean ( this, Ball ); var myBall:Ball; for ( var i:int = 0; i< 10; i++ ) { myBall = new Ball(); myBall.x = Math.random()*(stage.stageWidth - myBall.width); myBall.y = Math.random()*(stage.stageHeight - myBall.height); addChild( myBall ); } setChildIndex ( myButton, numChildren - 1 ); }
The clean function searches the Container made into a parameter in this case our stage, then gets each child object and stores its references in a myDisplayObject variable of the flash.display.DisplayObject type.
We use this type for our myDisplayObject variable as it can bring different sub-types of the DisplayObject class to be referenced. We chose this type which is the type common to all child objects.
We test its type with the help of the keyword is. If this is the Ball type we delete the instance in the display list. We would obtain a more simple structure by creating a graphic object container in order to take in instances of the Ball symbol, and then completely empty it without testing.
If we want to move the objects at a later date, this approach would be more judicious:
myButton.addEventListener( MouseEvent.CLICK, clickButton ); var Container:Sprite = new Sprite(); addChildAt ( Container, 0 ); function clean ( pContainer:DisplayObjectContainer ):void { while ( pContainer.numChildren ) pContainer.removeChildAt ( 0 ); } function clickButton ( pEvt:MouseEvent ):void { clean ( Container ); var myBall:Ball; for ( var i:int = 0; i< 10; i++ ) { myBall = new Ball(); myBall.x = Math.random()*(stage.stageWidth - myBall.width); myBall.y = Math.random()*(stage.stageHeight - myBall.height); Container.addChild( myBall ); } }
The clean function integrates a while loop deleting each child object when they exist. By clicking on our button we clean the flash.display.Sprite type container then we add our instances of the Ball symbol to it.
Let’s come back to some parts of the previous code and let’s create a flash.display.Sprite type container. We use a Sprite object as using a MovieClip here will have no use. A Sprite will suffice as a simple way to store child objects:
var Container:Sprite = new Sprite; addChildAt ( Container, 0 );
We create a Container then we add it to the display list using the addChildAt method by placing it at index 0 already occupied by our button which is the only graphic object present at that time. Our Container therefore takes the index from the button moves the button to index 1. Our button therefore finds itself above the Container object, avoiding being hidden by the instances of the Ball class.
The clean function cleans the Container parameter and deletes each child when they are found:
function clean ( pContainer:DisplayObjectContainer ):void { while ( pContainer.numChildren ) pContainer.removeChildAt ( 0 ); }
This clean function can be reused to delete all the child objects of any DisplayObjectContainer.
Worth remembering
- In ActionScript 3 it is recommended to create Containers in order to more easily manipulate a group of graphic objects.
The button symbol
Our button symbol in the library can also be dynamically attached to a timeline by associating a specific class to it thanks to the linking panel.
By selecting the linking option on our Button symbol we bring up the Linking properties panel:
By checking the Export for ActionScript option we make our symbol available for programming. We specify myButton as a class name then we click on OK.
We dynamically instance our Button:
var myButton:MyButton = new MyButton(); addChild ( myButton );
You will probably remember that it is impossible in ActionScript 1 and 2 to create Buttons through programming. Developers had to use clips using a button behavior.
We will see in the article entitled Interactivity that the use of the SinpleButton class proves to be rigid in reality and doesn’t offer an equivalent flexibility to the MovieClip class.
The graphic symbol
When a graphic symbol is placed in the library it can be manipulated via coding and can be dynamically instantiated in the application. By its non-interactivity this is of the flash.display.Shape type.
The Shape class doesn’t inherit the flash.display.interactiveObject class and can therefore not have any interactivity due to mouse or keyboard activity.
When we select the link option on a graphic symbol all of the options are greyed-out:
It is however possible to manipulate a graphic object placed on the stage while reaching it using the access methods of the display list getChildAt. We are obliged to point to our graphic object by passing an index as no occurrence name can be affected with an occurrence of a graphic symbol.
If we place an occurrence of a graphic object on an empty stage we can however access it by programming using the following code:
var myGraphicObject:DisplayObject = getChildAt ( 0 ); // displays : [object Shape] trace( myGraphicObject );
We could be tempted to give it a name by the name property and to make reference to it using the getChildByName method defined by the flash.display.DisplayObjectContainer class.
Unfortunately, the modification of the name property of a grphiac object placed using the author environment is impossible.
By looking at the inheritance of the Shape class we can see that it doens’t inherit the flash.display.DisplayObjectContainer class and can therefore not contain child objects.
Note that if we create a graphic in the Flash author environment and overlap it inside a clip, our overlap will be conserved on execution.
It can happen however that a clip is overlapped in a graphic by the author environment, even if this doesn’t pose any problems in the author environment, this overlapping can be conserved on execution.
The clip will leave the graphic to become a direct child of the parent of the graphic. The two objects both find themselves at the same level as the overlapping, this behavior even though it is troubling proves to be logical and should be known in order to avoid being a source of misunderstanding.
Worth remembering
- The graphic symbol cannot be associated with a subclass.
Bitmap classes
We have always been able to integrate different type bitmap images in the library. In Flash, we should consider a bitmap image as a symbol.
In Flash 8 we could attribute a linking name to an image and dynamically attach it using the BitmapData.loadBitmap method then display it using the MovieClip.attachBitmap method.
To attach an image to the library we need to call the loadBitmap method of the BitmapData class:
import flash.display.BitmapData; var ref:BitmapData = BitmapData.loadBitmap ("LogoWiiFlash");
By passing a identifier name given by the linking panel we get our image in the form of BitmapData then we display it with the attachBitmap method:
import flash.display.BitmapData; var myBitmap:BitmapData = BitmapData.loadBitmap ("LogoWiiFlash"); attachBitmap ( myBitmap, 0 );
In ActionScript 3, the images instantiate themselves as all graphic objects with the Keyword new.
Import an image of any type in the library then right-click on it to select the linking option as illustrated here:
By checking the Export for ActionScript option we make the Class and Basic class field editable.
We specify the class name LogoWiiFlash and leave the basic class flash.display.BitmapData. Our image will therefore be of the LogoWiiFlash type and an inherit from Bitmap.Data. Then we instantiate our image:
var myBitmapData:LogoWiiFlash = new LogoWiiFlash();
If we test the previous code we get the following error message:
1136: A number of arguments incorrect. 2 expected.
In ActionScript 3, a BitmapData object cannot be instantiated without specifying a width and height particular to the constructor. In order not to be blocked upon compilation we have to use a width and height of 0,0.
var myBitmapData:LogoWiiFlash = new LogoWiiFlash(0,0);
Upon execution the player displays the image at its original size.
Worth remembering
- In order to instantiate a bitmap image from the library we have to specify a height and width of 0 pixels. Upon execution the player displays the image at its original size.
Mediabox Training Centre © 2000 - 2008 All rights reserved.
Adobe Authorized Training Centre. State convention under number 25 14 02167 14.
Mediabox : SARL au capital de 62.000€ - Activity number: 25 14 02167 14 - SIRET : 493 716 468 00027
MEDIABOX, 102 Avenue des Champs Elysées, 75008 PARIS - Tel. +33(0)2.31.91.96.89 - Fax. +33(0)2.72.68.56.42












