kirupaForum

kirupaForum (http://www.kirupa.com/forum/index.php)
-   Flash ActionScript (http://www.kirupa.com/forum/forumdisplay.php?f=9)
-   -   ActionScript 3 Tip of the Day (http://www.kirupa.com/forum/showthread.php?t=223798)

senocular 08-18-2006 08:14 AM

Proxy: getProperty and setProperty
 
getProperty and setProperty are methods used in Proxy classes that are used to manage property access. When a property not defined within a proxy instance is retrieved, getProperty is called to retrieve it. When set, setProperty is used to set it.

As with all methods of the Proxy class, getProperty and setProperty are defined within the flash_proxy namespace (flash.utils.flash_proxy) to prevent conflicts with public. When you override these methods within your own Proxy subclasses, you will want to be sure to use the flash_proxy namespace.

The following example, CustomObject, extends Proxy and uses getProperty and setProperty to manage dynamic properties set for its instances.
ActionScript Code:

package {
   
    import flash.utils.Proxy;
    import flash.utils.flash_proxy;
   
    dynamic public class CustomObject extends Proxy {
       
        public var classProperty:String = "classProperty"; // generic class variable
        private var customProperties:Object = new Object(); // store custom variables
       
        public function CustomObject() {
        }
       
        // called when getting dynamic variables
        override flash_proxy function getProperty(name:*):* {
            if (name in customProperties) {
                return customProperties[name];
            }
            return "Property does not exist";
        }
        // called when setting dynamic variables
        override flash_proxy function setProperty(name:*, value:*):void {
            customProperties[name] = "Property "+name+": "+value;
        }
    }
}


ActionScript Code:

// usage example
var myObj:CustomObject = new CustomObject();
trace(myObj.foo); // Property does not exist
myObj.foo = "bar";
trace(myObj.foo); // Property foo: bar

trace(myObj.classProperty); // classProperty
myObj.classProperty = "bar";
trace(myObj.classProperty); // bar
 


Notice that when getting and setting the foo property, getProperty and setProperty are used to control its ultimate value which is stored within a customProperties defined for the class. Also, since classProperty is not a dynamic variables, instead being one defined for the class, getProperty and setProperty to not apply.

senocular 08-18-2006 11:33 AM

Flash 9: Display Object Variables and Instance Names
 
In Flash 9 when you create MovieClip instance on the screen and give it an instance name, you are doing two things:
  1. You're assigning the name property of the MovieClip instance to be the string equivalent to the instance name provided
  2. You're creating a variable in the current timeline with the name of the instance name that references that MovieClip instance

Flash does this behind the scenes when you publish your SWF to help you manage your movie clips on the screen. It's important to note that this behavior (specifically #2) is not seen with ActionScript. For Example:
ActionScript Code:

// my_mc is the instance name of a movie clip
// created on this timeline
trace(my_mc); // [object MovieClip]
trace(my_mc.name); // my_mc

// create a new movie clip via AS
// add it to my_mc
var another_mc:MovieClip = new MovieClip();
another_mc.name = "child_mc";
my_mc.addChild(another_mc);

// instance name not available in parent timeline
trace(another_mc)// [object MovieClip]
trace(my_mc.child_mc); // undefined
trace(my_mc.another_mc); // undefined
 



You can see that neither the instance name (name property) nor the variable to which the new MovieClip created with ActionScript was assigned is referencable through the movie clip in which it was added (my_mc). This is because another_mc was created and added to the timeline dynamically. Flash will only save instance names as variables for movie clips created on the timeline in Flash.

If you want to use an instance name to get a MovieClip (or any DisplayObject) instance from the timeline in which it exists, you can use getChildByName();
ActionScript Code:

trace(my_mc.getChildByName("child_mc"))// [object MovieClip]);
 


This will work for all movie clips despite where or how they were located as long as they are within the timeline/movie clip from which getChildByName was used.

NiñoScript 08-18-2006 07:07 PM

maybe you can do something like
ActionScript Code:

my_mc.another_mc = new MovieClip();
my_mc.another_mc.name = "child_mc";
my_mc.addChild(my_mc.another_mc);

trace(another_mc)// [object MovieClip]
trace(my_mc.another_mc); // ???
 


(^thats a question^, i don't know if its that easy to make variables inside of movieclips)

senocular 08-19-2006 08:28 AM

Quote:

Originally Posted by NiñoScript
maybe you can do something like

You can assign the movie clip to the movie clip you place it in if you want. I was just showing that flash automatically does that with instances on the timeline.

snick 08-19-2006 10:48 PM

Quote:

The CustomDispatcher helper class above doesn't inherit from EventDispatcher but uses aggregation to obtain EventDispatcher functionality through an instance of EventDispatcher initialized in the constructor.

I was just wondering... if you were going to use a helper class anyway, why would you not just do this:

Code:

package test
{
        import flash.events.Event;
        public class Test
        {
                public function Test() {
            var dispatcher:CustomDispatcher = new CustomDispatcher();
            dispatcher.addEventListener("customEvent", handleEvent);
            dispatcher.dispatchEvent(new Event("customEvent"));
        }
     
        private function handleEvent(event:Event):void {
            trace(event.type); // "customEvent"
        }
        }
}
        import flash.events.EventDispatcher;
       
class CustomDispatcher extends EventDispatcher
{
       
}


I'm just confused as to why one would want to abstract the EventDispatcher class in a helper. Is that so the helper could extend something else?

Nick
http://www.velloff.com

senocular 08-20-2006 08:42 AM

Quote:

Originally Posted by snick
I was just wondering... if you were going to use a helper class anyway, why would you not just do this:
...
I'm just confused as to why one would want to abstract the EventDispatcher class in a helper. Is that so the helper could extend something else?


It was just an example to show implementation. The helper class was used because MyDispatcher, as the application class, extends Sprite which already makes it an event dispatcher. To keep the example encapsulated in one file, I just used a helper class for the ED implementation.

senocular 08-20-2006 08:42 PM

XML: XML and XMLList
 
When working with E4X in ActionScript 3, you deal with 2 kinds of objects, XML (Top level XML) and XMLList (Top level XMLList), both of which are very similar in nature. The big difference between the two is that with XML you are dealing with one specific object (which could potentially contain any number of children) and with XMLList you are dealing with a collection of 1 or more objects. Consider the following:
Code:

// XML:
<foo>
        <foo />
        <foo />
        <foo />
</foo>

Code:

// XMLList:
<foo />
<foo />
<foo />

Since you are dealing with one root node in the first example, it represents an XML object. In the second example, you have multiple nodes meaning you have an XMLList.

Unlike the old XML object (now XMLDocument) in previous versions of ActionScript, the XML and XMLList classes do not deal specifically with nodes. Though XML and XMLList can represent a collection of nodes, they can also represent other values such as attributes. Example:
ActionScript Code:

var myXML:XML = <foo>
    <foo bar="bar1" />
    <foo bar="bar2" />
    <foo bar="bar3" />
</foo>;

trace(myXML.foo.@bar.toXMLString());
/* Output:
bar1
bar2
bar3
*/

trace(myXML.foo.@bar is XMLList); // true
 



Note that attributes are always returned as XMLList instances, even if one value is returned. Consider getting the bar attribute value from the first foo node:
ActionScript Code:

trace(myXML.foo[0].@bar is XMLList); // true
 


Though one element is returned, it is retuned as an XMLList. You can get the XML value of that attribute by returning the first value off of that list:
ActionScript Code:

trace(myXML.foo[0].@bar[0] is XML); // true
 


The same applies to XML
ActionScript Code:

var myXML:XML = <foo>
    <foo />
</foo>;
trace(myXML.foo is XMLList); // true
 


The XML operations that can return more than one value (nodes, attributes, etc) will return XMLList instances.

senocular 08-22-2006 03:32 AM

Constants
 
ActionScript 3 allows you to define constants for your classes. Constants are special kinds of variables that can be defined only once. Typically you'll see constants defined with capital letters. Event.ENTER_FRAME, for example, is a constant.

You define constants in AS3 using the const keyword (const keyword). This is used in place of what would otherwise be var (var keyword).
ActionScript Code:

package {
   
    import flash.display.Sprite;

    public class MyClass extends Sprite {

        public const MY_CONSTANT:String = "constant";

        public function MyClass () {
        }
    }
}


Though constants can't be redefined, if they are object values, methods can still be called that otherwise modify that value. If the constant is an array, for example, Array.push() can be used to add additional elements to that array. As a constant, it just means that the actual value of the variable itself can't be changed. That is to say that array variable will always be that same array and couldn't be defined as another or a new array.

ActionScript Code:

package {
   
    import flash.display.Sprite;

    public class MyClass extends Sprite {

        public const MY_CONSTANT:Array = new Array(1,2,3);

        public function MyClass () {
            MY_CONSTANT.push(4); // ok
            MY_CONSTANT = new Array(5,6,7); // error
        }
    }
}


Deviant1853 08-22-2006 03:55 AM

This all works fine aslong as you dont have strict mode on. If you have the strict mode on it will have a compile error because the constant isnt set at the class initialization. It doesnt even allow it in the constructor funnily enough. The simple answer is to just work with strict mode off :)

senocular 08-22-2006 04:00 AM

Quote:

Originally Posted by Deviant1853
This all works fine aslong as you dont have strict mode on. If you have the strict mode on it will have a compile error because the constant isnt set at the class initialization. It doesnt even allow it in the constructor funnily enough. The simple answer is to just work with strict mode off :)

Actually, I might be wrong on that one. I should do some testing before commiting to that behavior (I might be thinking of something else).

[edit]Ok, doesnt look like it enforces constants at all without strict, and AS3 isnt happy defining constants outside of the declaration so I'm going to keep it there - thanks for pointing that out Deviant1853 :)[/edit]

Deviant1853 08-22-2006 05:21 AM

Any time Senocular :)

senocular 08-24-2006 07:01 AM

duplicateMovieClip Replacement
 
ActionScript 3 no longer has a duplicateMovieClip method for MovieClip instances (or any DisplayObject instances). Instead, it's suggested that you just create a new instance of the display object you wish to duplicate using its constructor. This, however, is not the same as duplicateMovieClip, and, really, is more like using AS1 and AS2's attachMovieClip. For a more accurate representation of duplicateMovieClip in AS3, consider the following function:
ActionScript Code:

package com.senocular.display {
   
    import flash.display.DisplayObject;
    import flash.geom.Rectangle;
   
    /**
     * duplicateDisplayObject
     * creates a duplicate of the DisplayObject passed.
     * similar to duplicateMovieClip in AVM1
     * @param target the display object to duplicate
     * @param autoAdd if true, adds the duplicate to the display list
     * in which target was located
     * @return a duplicate instance of target
     */

    public function duplicateDisplayObject(target:DisplayObject, autoAdd:Boolean = false):DisplayObject {
        // create duplicate
        var targetClass:Class = target.constructor;
        var duplicate:DisplayObject = new targetClass();
       
        // duplicate properties
        duplicate.transform = target.transform;
        duplicate.filters = target.filters;
        duplicate.cacheAsBitmap = target.cacheAsBitmap;
        duplicate.opaqueBackground = target.opaqueBackground;
        if (target.scale9Grid) {
            var rect:Rectangle = target.scale9Grid;
            // Flash 9 bug where returned scale9Grid is 20x larger than assigned
            rect.x /= 20, rect.y /= 20, rect.width /= 20, rect.height /= 20;
            duplicate.scale9Grid = rect;
        }
       
        // add to target parent's display list
        // if autoAdd was provided as true
        if (autoAdd && target.parent) {
            target.parent.addChild(duplicate);
        }
        return duplicate;
    }
}


As you can see, this function (duplicateDisplayObject) takes care of making sure a duplicated instance also retains all the information retained by duplicateMovieClip such as transformation, filters, chaching as bitmap, etc.

Note: There is currently a bug in Flash Player 9 that causes incorrect values to be returned from the scale9Grid property of display objects. This function compensates for that but may need to be edited should this bug be fixed.

Usage:
ActionScript Code:

import com.senocular.display.duplicateDisplayObject;

// create duplicate and assign to newInstance variable
// using true for autoAdd automatically adds the newInstance
// into the display list where myOldSprite is located
var newInstance:Sprite = duplicateDisplayObject(myOldSprite, true);
newInstance.x += 100; // shift to see duplicate
 



The only thing duplicateMovieClip does that this does not is copy dynamic drawing information. Currently, the graphics object in display objects cannot be duplicated so there is no way to obtain that information for duplicates in duplicateDisplayObject.

Deviant1853 08-24-2006 07:42 AM

I am quite supprised that Adobe didnt create a non-final method clone() on Object to be overridden for each subclass. I cant see any reason why they wouldnt want to do this :S

senocular 08-24-2006 08:28 AM

Proxy: callProperty
 
The callProperty method of the Proxy class lets you define an action for methods called from Proxy instances. When a method not defined within a proxy instance is called, callProperty is run passing the name of the method called along with an array of the arguments used.

As with all methods of the Proxy class, callProperty is defined within the flash_proxy namespace (flash.utils.flash_proxy) to prevent conflicts with public. When you override these methods within your own Proxy subclasses, you will want to be sure to use the flash_proxy namespace.

The following example, CustomObject, extends Proxy and uses callProperty to manage dynamic methods called for its instances.
ActionScript Code:

package {
   
    import flash.utils.Proxy;
    import flash.utils.flash_proxy;
   
    dynamic public class CustomObject extends Proxy {
       
        private var variables:Object = new Object(); // stores variables
       
        public function CustomObject() {
        }
       
        // called when calling dynamic methods
        override flash_proxy function callProperty(name:*, ... args):* {
           
            // convert name into string
            name = String(name);
           
            var callType:String = name.slice(0,3); // get or set
            var callVariable:String = name.slice(3); // variable name behind get or set
           
            switch(callType) {
               
                case 'get':
                    // if get, get from variables object if exists
                    if (callVariable in variables) {
                        return variables[callVariable];
                    }
                    return null;
                   
                case 'set':
                    // if set assign to variables object
                    variables[callVariable] = args[0];
            }
        }
    }
}


This example uses callProperty to accept generic get and set methods to get and set dynamic "variables" which are stored in the variables object.
ActionScript Code:

// usage example
var myObj:CustomObject = new CustomObject();
trace(myObj.getMyVar()); // null
myObj.setMyVar("foo");
trace(myObj.getMyVar()); // foo
myObj.setMyVar("bar");
trace(myObj.getMyVar()); // bar
trace(myObj.MyVar); // doesnt exist (get property error)
 


at first getMyVar returns null since "MyVar" was not yet set (using setMyVar). After being set, getMyVar returns the value it was given through getMyVar.

ignitrix 08-24-2006 08:44 AM

Nice work on the duplicateDisplayObject Senocular. I started doing some tests with it... if the constructor of the DisplayObject you are creating has 1 or more required parameters, it fails. Other than that, it seems to work excellent--even with complex Sprites.

~JC

senocular 08-24-2006 08:45 AM

Creating graphics Copies
 
Though you can't directly copy graphics created in Sprite and Shape instances' graphics property in ActionScript 3, you can use the Proxy class to create a substitute graphics-like property that will be able to record all methods you use with graphics. Consider the following class, GraphicsCopy:
ActionScript Code:

package com.senocular.display {
   
    import flash.display.Graphics;
    import flash.utils.flash_proxy;
    import flash.utils.Proxy;
   
    /**
     * a graphics property substitute for DisplayObject instances
     * that can be duplicated
     */

    public class GraphicsCopy extends Proxy {
       
        private var _graphics:Graphics;
        private var history:Array = new Array();
       
        /**
         * graphics instance to recieve
         * drawing commands given to this GraphicsCopy instance
         */

        public function get graphics():Graphics {
            return _graphics;
        }
        public function set graphics(g:Graphics):void {
            _graphics = g;
           
            // apply the graphics history to Graphics instance
            copy(this);
        }
       
        /**
         * constructor
         * @param graphics Optional Graphics instance to recieve
         * drawing commands given to this GraphicsCopy instance
         */

        public function GraphicsCopy(graphics:Graphics = null) {
            _graphics = graphics;
        }
       
        /**
         * copies the graphics of a GraphicsCopy into this GraphicsCopy
         */

        public function copy(graphicsCopy:GraphicsCopy):void {
            var hist:Array = graphicsCopy.history;
            history = hist.slice();
            if (_graphics) {
                var i:int;
                var n:int = hist.length;
                _graphics.clear();
                for (i=0; i<n; i += 2) {
                    _graphics[hist[i]].apply(_graphics, hist[i + 1]);
                }
            }
        }
       
        // PROXY overrides
        override flash_proxy function callProperty(methodName:*, ... args):* {
            methodName = String(methodName);
            switch(methodName) {
                case "clear":
                    history.length = 0;
                    break;
                default:
                    history.push(methodName, args);
            }
            if (_graphics && methodName in _graphics) {
                return _graphics[methodName].apply(_graphics, args);
            }
        }
    }
}



Instead of using the graphics property for your sprites or shapes, you can use a GraphicsCopy instance that references that object's graphics property. Then, every method used on the GraphicsCopy is recorded by GraphicsCopy but still applied to graphics thanks to Proxy and its callProperty method. Example:
ActionScript Code:

// MyClass.as Shape class using GraphicsCopy
package {
   
    import flash.display.Shape;
    import com.senocular.display.GraphicsCopy;
   
    class MyShape extends Shape {
       
        // graphicsCopy property
        private var _graphicsCopy:GraphicsCopy;
        public function get graphicsCopy():GraphicsCopy {
            return _graphicsCopy;
        }
       
        // constructor
        function MyShape(){
            _graphicsCopy = new GraphicsCopy(graphics);
        }
    }
}


ActionScript Code:

// in Flash
// draw shape 1
var shape1:MyShape = new MyShape();
shape1.graphicsCopy.beginFill(0xFF80);
shape1.graphicsCopy.lineStyle(2, 0);
shape1.graphicsCopy.drawRect(0, 0, 50, 50);

// draw shape2 using shape1's copied drawing
var shape2:MyShape = new MyShape();
shape2.graphicsCopy.copy(shape1.graphicsCopy);

// add to display list
addChild(shape1);
addChild(shape2);
shape2.x += 100;



Running this will show to green squares, the first drawn using GraphicsCopy (shape1) and the other duplicated from GraphicsCopy (into shape2's GraphicsCopy) using the copy method of that class.

Note: Since Proxy classes cannot inherit from Graphics (its abstract anyway), GraphicsCopy instances do not have a Graphics class type associated with them so will not work with methods expecting a Graphics instance. I don't believe there are any inherit methods that use Graphics parameters, but you might make your own or have functions/methods from other sources that do. Using a type of Object or * would allow both Graphics and GraphicsCopy instances to work in that case.

senocular 08-24-2006 08:53 AM

Quote:

Originally Posted by ignitrix
Nice work on the duplicateDisplayObject Senocular. I started doing some tests with it... if the constructor of the DisplayObject you are creating has 1 or more required parameters, it fails. Other than that, it seems to work excellent--even with complex Sprites.

~JC


Yeah, for the sake of simplicity I went with the assumption that display objects used would follow with the consistency of Flash display objects and require no constructor parameters :)

ignitrix 08-24-2006 12:34 PM

Quote:

Originally Posted by senocular
...The Stage class (flash.display.Stage) is the class assigned to the stage object which is accessible from your main movie sprite/movie clip (or others within the same security sandbox) using the stage property...

Is there anyway to give a static, non-DisplayObject class access to the stage? I tried many different workarounds, but could not figure out how to give it access to the stage without making it a non-static object...

Deviant1853 08-24-2006 01:22 PM

Quote:

Originally Posted by ignitrix
Is there anyway to give a static, non-DisplayObject class access to the stage? I tried many different workarounds, but could not figure out how to give it access to the stage without making it a non-static object...


I have got around this problem by creating a singleton MyStage class. It requies on the root of your movie to use: MyStage.init(stage); but other than that it works pretty much how you want. It gives static access to the stage.

PHP Code:

/**
    My Stage
    version 1.0.0
    Created by Matthew Lloyd
    http://www.Matt-Lloyd.co.uk/
    
    This is release under a Creative Commons license.
    More information can be found here:
    http://creativecommons.org/licenses/by-nc-sa/2.0/uk/
    
    ----------------------------------------------------------------

*/
package com.deviant
{
    
import flash.display.*;

    
public class MyStage extends Sprite
    
{
        
public static var instance:MyStage = null;
        
        
public function MyStage()
        {}
        
        
public static function getInstance():MyStage
        
{
            if(
instance == null)
                
instance = new MyStage();
            return
instance;
        }
        
        
public static function getStage():Stage
        
{
            return
getInstance().stage;
        }
        
        
public static function init(stg:Stage):void
        
{
            
stg.addChild(MyStage.getInstance());
            
stg.scaleMode = StageScaleMode.NO_SCALE;
            
stg.align = StageAlign.TOP_LEFT;
        }
    }
}


The scale mode and the alignment arent nessicary they are just very useful for my needs.

ignitrix 08-24-2006 01:38 PM

This worked excellent! Thanks Deviant

icio 08-24-2006 01:51 PM

I tried this code:
ActionScript Code:

package {
    import flash.display.Sprite;
    public class stage_test extends Sprite {
        public function stage_test() {
            var myClass:MyClass =  new MyClass();
        }
    }
}

import flash.display.Stage;
import flash.display.Sprite;
   
class MyClass {
    public var stage:Stage = (new Sprite()).stage;
    public function MyClass():void {
        trace(stage);
    }
}



But it didn't work. It would appear that the `stage` property of a Sprite isn't set when the Sprite is created. Where does the value of the `stage` property come from, then ?

Thanks

senocular 08-24-2006 02:15 PM

Quote:

Originally Posted by icio
I tried this code:
...

But it didn't work. It would appear that the `stage` property of a Sprite isn't set when the Sprite is created. Where does the value of the `stage` property come from, then ?

Thanks

display objects only have access to the stage when they are within a visible display list (or, rather, a display list attached to the stage). To be able to have a valid reference to the stage from a sprite, you'd have to use addChild to add it to a container - either the stage itself or some other container attached to it.

A suggestion I've used before was have your application or document class extend a custom subclass of sprite rather than sprite itself. This class could then have that static stage reference which would instantly available since the application/document class is inherently a child of the stage when the SWF starts.

On a similar topic, I have a class allowing you to detect when the stage property is available for a display object (i.e. when it has been added to a visible display list) but I was saving that for another tip of the day. If anyone is interested, I can post that one next.

Enemу 08-24-2006 04:03 PM

Hi, Sen and everyone :)

I have a tip request: Singleton in AS3

private
is no longer available as constructor's attribute, it makes me just unhappy :bored:

I've found two workarounds for this, here about singletons in general and here
more concrete.

But, there are a lot of discussions and comments about what way is more hackish or useful. I'm confused.

The question: Singleton in AS3: best practice, the most common and easy to use (and understand) way, if any...

Thanks!

senocular 08-24-2006 04:42 PM

Quote:

Originally Posted by Enemу
Hi, Sen and everyone :)

I have a tip request: Singleton in AS3

private
is no longer available as constructor's attribute, it makes me just unhappy :bored:

I've found two workarounds for this, here about singletons in general and here
more concrete.

But, there are a lot of discussions and comments about what way is more hackish or useful. I'm confused.

The question: Singleton in AS3: best practice, the most common and easy to use (and understand) way, if any...

Thanks!


gskinners post is your best approach (private variable usage prefered over helper class).

Enemу 08-25-2006 04:41 AM

Quote:

Originally Posted by senocular
gskinners post is your best approach (private variable usage prefered over helper class).


You mean throwing an error if allowInstantiation == false ?

But what about compile time errors?

senocular 08-27-2006 08:37 AM

TextField.appendText()
 
The TextField class (flash.text.TextField) in ActionScript 3 has a new method called appendText (flash.text.TextField.appendText()). This method allows you to add additional text onto the end of the text contained within the current text field. This should be used in place of TextField.text += newText since appendText is faster and more efficient.
ActionScript Code:

var my_tf = new TextField();
my_tf.text = "Hello";
my_tf.appendText(" world!")// my_tf.text == "Hello world!"
 


senocular 08-28-2006 06:14 PM

include Directive
 
ActionScript 3 continues to allow you to include code located in external files within your scripts at compile time using the include directive (include directive).
ActionScript Code:

include "scripts/myscript.as"


Notice that the include directive in ActionScript 3 does not contain a # before "include" as it did in ActionScript 1 and 2.

Note: You should keep as files included in your ActionScript outside of your class path(s) so that they are not accidentally interpreted as classes.

senocular 08-28-2006 06:31 PM

Duplicate Variable Definitions
 
In ActionScript 1 and ActionScript 2, it was possible to define a variable twice in the same scope without error. For example:
ActionScript Code:

// ActionScript 1 and 2 
var i:Number = 1;
var i:String = 2;


This is no longer allowed in ActionScript 3. In ActionScript 3, once you define a variable for a scope, that variable is set for that scope and cannot be redefined as a new variable or as a new type. This, of course, doesn't mean you cannot change the value of a variable. It just means, essentially, that the var keyword should only be used once to declare/define any one variable given any scope.
ActionScript Code:

// ActionScript 3 
var i:Number = 1;
var i:String = 2; // ERROR: duplicate definition or undefined property
 


For ActionScript 3, if you need a new type, you will need to create a new variable to contain that type. Also, if you have situations where var was used twice in, for instance, two separate if blocks, you will want to first declare the variable outside the blocks and assign them within.
ActionScript Code:

// ActionScript 3 INCORRECT
// (but works in AS1 and AS2)
if (my_btn.enabled == true) {
    var returnValue:Number = 1;
}else{
    var returnValue:Number = 0;
}
if (provideAsString == true) {
    var returnValue:String = "1";
}else{
    var returnValue:String = "0";
}


The correct way to do this for AS3 is:
ActionScript Code:

// ActionScript 3 CORRECT
var returnValueNum:Number;
var returnValueStr:String;
if (my_btn.enabled == true) {
    returnValueNum = 1;
}else{
    returnValueNum = 0;
}
if (provideAsString == true) {
    returnValueStr = "1";
}else{
    returnValueStr = "0";
}


Notice that two different variables were used instead of 1 since they have different types. Also the variables were declared once outside of the if blocks instead of twice within. Alternatively, you could also use one variable with the * type.
ActionScript Code:

// ActionScript 3 ALSO OK
var returnValue:*
if (my_btn.enabled == true) {
    returnValue = 1;
}else{
    returnValue = 0;
}
if (provideAsString == true) {
    returnValue = "1";
}else{
    returnValue = "0";
}


senocular 08-30-2006 07:59 AM

mouseEnabled and Event Blocking
 
In ActionScript 1 and 2, instances with button events like onPress and onRollOver intercepts control of all button events that occurred over that instance. This means that if there was overlap between two instances with button events, the events occuring within the overlapping area would always go to the instance on top and never on the one below since those events were intercepted by the overlapping instance. Events to the underlying instance could be accessible in those overlapping areas only if all button events were removed from the topmost instance.

In ActionScript 3, the same concept applies, but the behavior is no longer dependant on button events like onPress since events are now handled exclusively with EventDispatcher. Instead, a property is used: mouseEnabled (flash.display.InteractiveObject.mouseEnabled).

The mouseEnabled property actually kind of serves two purposes. First it prevents (true, default) or allows (false) mouse events going to instances below the topmost instance. It also enables (true, default) or disables (false) mouse instances from being dispatched to the that instance. It acts very much like the enabled property of AS1 and AS2.

Notice the behavior of the following AS3 script. The topmost circle will be clicked when it is enabled. When not, events will go to the underlying circle.
ActionScript Code:

function createCircle(name:String = ""):DisplayObject {
    var circle:Sprite = new Sprite();
    circle.name = name;
    circle.graphics.lineStyle(0);
    circle.graphics.beginFill(0xFF8080);
    circle.graphics.drawCircle(50, 50, 50);
    return circle;
}

circle1 = createCircle("circle 1");
circle2 = createCircle("circle 2");
circle2.x += 25;

addChild(circle1);
addChild(circle2);

circle1.addEventListener(MouseEvent.MOUSE_DOWN, click);
circle2.addEventListener(MouseEvent.MOUSE_DOWN, click);

function click(e) {
    trace(e.target.name + " clicked."); // trace name
   
    // disable and re-enable circle2 with each click
    circle2.mouseEnabled = !circle2.mouseEnabled;
}



Keep in mind that mouseEnabled is true by default. This means that even without button (or any) events associated with a display object instance, it will block events to those instances below it. If you don't want that to happen, you will have to appropriately set mouseEnabled = false where needed.

Enemу 08-30-2006 11:01 AM

Quote:

Originally Posted by senocular
since appendText is faster and more efficient.


I'm just curious, what makes it faster?

Any ideas about what implementation brings this improvement are welcome.

senocular 08-30-2006 11:34 AM

Quote:

Originally Posted by Enemу
I'm just curious, what makes it faster?

Any ideas about what implementation brings this improvement are welcome.


Its an internal method that doesn't rely on the get/set of the text property. Essentially any single method used to replace += will be much more efficient.

senocular 09-03-2006 08:19 AM

mouseChildren with Event Propagation
 
The mouseChildren property (flash.display.DisplayObjectContainer.mouseChildren ) is a new property that allows you to essentially control the mouseEnabled of all the children of a sprite (or other display object container). This allows the parent sprite to have its own events without having to worry about interference with events coming from its children.
ActionScript Code:

spriteInstance.mouseChildren = false;



Though ActionScript 3 now has a SimpleButton class (flash.display.SimpleButton). this property would play an important role in making custom buttons with the MovieClip or Sprite classes. Consider what would happen if you created a rollover event that caused a sprite or movie clip-based button to remove its current graphics and create new ones for a rollover state. With the children of that sprite capable of receiving mouse events, events would fire for the children within the button - events which would propagate to the main sprite. This could mean duplicate events as well as making the event target for those events the children of the button instead of the button itself. Setting mouseChildren to false you can prevent that from happening.

The easiest demonstration is a simple click of a sprite containing another sprite. Change the value of mouseChildren between true and false and notice which sprite is designated as the target of the event:
ActionScript Code:

// main button
var spriteButton:Sprite = new Sprite();
spriteButton.name = "spriteButton";
spriteButton.mouseChildren = true;

// graphics
var spriteGraphics:Sprite = new Sprite();
spriteGraphics.name = "spriteGraphics";
spriteGraphics.graphics.beginFill(0x4080A0);
spriteGraphics.graphics.drawCircle(50, 50, 25);

// add to display list
spriteButton.addChild(spriteGraphics);
addChild(spriteButton);

// events
spriteButton.addEventListener(MouseEvent.CLICK, click);
function click(evt:MouseEvent):void {
    trace(evt.target.name);
}


When true (default), the sprite within the button that was clicked is marked as the target. When false, the button sprite itself is the target - something which is more desirable in this case.

mouseChildren = true; output
Code:

spriteButton
mouseChildren = false; output
Code:

spriteGraphics

senocular 09-03-2006 08:38 AM

rollOver and rollOut vs. mouseOver and mouseOut
 
The InteractiveObject class (flash.display.InteractiveObject) in ActionScript 3 has both rollOver and rollOut events as well as mouseOver and mouseOut events.

Both sets of events determine when a mouse enters or leaves the graphics area of an interactive object. The rollOver and mouseOver events fire when the mouse comes in contact with an interactive object, while rollOut and mouseOut occur when the mouse leaves the interactive object.

Where they differ is with their interaction with interactive object children. The roll events (rollOver and rollOut) simplify the process and prevent interference with child events. Essentially, this is the same as using mouseOver and mouseOut with mouseEnabled set to false. mouseOver and mouseOut with mouseEnabled provide a parent sprite with events from its children. rollOver and rollOut keeps the events on the parent object.

Example: toggle between the use of the ROLL_OVER & ROLL_OUT and MOUSE_OVER and MOUSE_OUT events.
ActionScript Code:

// main button
var spriteButton:Sprite = new Sprite();
spriteButton.name = "spriteButton";

// graphics
var spriteGraphics1:Sprite = createGraphics("spriteGraphics1", 0xFF, 50, 50, 25);
var spriteGraphics2:Sprite = createGraphics("spriteGraphics2", 0x80, 50, 50, 15);

// add to display list
spriteButton.addChild(spriteGraphics1);
spriteButton.addChild(spriteGraphics2);
addChild(spriteButton);

// events
spriteButton.addEventListener(MouseEvent.ROLL_OVER, over);
spriteButton.addEventListener(MouseEvent.ROLL_OUT, out);
//~spriteButton.addEventListener(MouseEvent.MOUSE_OVER, over);
//~spriteButton.addEventListener(MouseEvent.MOUSE_OUT, out);

function over(evt:MouseEvent):void {
    trace("over: " + evt.target.name);
}
function out(evt:MouseEvent):void {
    trace("out: " + evt.target.name);
}

// create circles
function createGraphics(name:String, color:uint, x:Number, y:Number, radius:Number):Sprite {
    var circle:Sprite = new Sprite();
    circle.name = name;
    circle.graphics.beginFill(color);
    circle.graphics.drawCircle(x, y, radius);
    return circle;
}


You'll notice that with rollOver and rollOut, spriteButton is the target and doesn't receieve events from its children while the opposite is true for mouseOver and mouseOut.


rollOver and rollOut output
Code:

over: spriteButton
out: spriteButton
over: spriteButton
out: spriteButton

mouseOver and mouseOut output
Code:

over: spriteGraphics1
out: spriteGraphics1
over: spriteGraphics2
out: spriteGraphics2
over: spriteGraphics1
out: spriteGraphics1


senocular 09-03-2006 08:47 AM

DisplayObjectContainer contains()
 
With ActionScript 3, you can easily determine if a sprite or other display object container contains any otherr display object using the contains method (flash.display.DisplayObjectContainer.contains()). The contains method returns true if the display object passed is within the target display object container or any of its children.

Example:
ActionScript Code:

var king:Sprite = new Sprite();
var queen:Sprite = new Sprite();
var jack:Sprite = new Sprite();
var joker:Sprite = new Sprite();

queen.addChild(jack);
king.addChild(queen