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 09-03-2006 10:25 AM

Quote:

Originally Posted by AdamSchroeder
These are great tips Senocular! Thank you so much for taking the time to write them and explain them.

I was wondering if you give a tip on the best way to capture the onMouseReleaseOutside event that existed in AS2.0 but no longer exist in AS3.0.

It would fit right in with your current tips explaining how the event system works.

Yes, I'm working up to that one ;)

senocular 09-03-2006 10:56 AM

Preventing Event Propagation
 
If you want to prevent an event from propagating further, you can stop it from doing so within an event listener using stopPropagation() (flash.events.Event.stopPropagation()) or stopImmediatePropagation() (flash.events.Event.stopImmediatePropagation()). These methods are called from the Event objects passed into event listeners and essentially stop the event from happening - at least past that point.

stopPropagation prevents any objects beyond the current from recieving the event, and this can be within any phase of the event. stopImmediatePropagation does the same but also takes the extra step of preventing additional events within the current target receiving the event from happening too. So where as stopPropagation would prevent sprite A's parent from receiving the event, stopImmediatePropagation would prevent sprite A's parent as well as any other listeners listening to sprite A from receiving the event.

Example: toggle between using stopPropagation and stopImmediatePropagation
ActionScript Code:

var circle:Sprite = new Sprite();
circle.graphics.beginFill(0x4080A0);
circle.graphics.drawCircle(50, 50, 25);
addChild(circle);

circle.addEventListener(MouseEvent.CLICK, clickCircle1);
circle.addEventListener(MouseEvent.CLICK, clickCircle2);
stage.addEventListener(MouseEvent.CLICK, clickStage);

function clickCircle1(evt:MouseEvent):void {
    evt.stopPropagation();
    // evt.stopImmediatePropagation();
    trace("clickCircle1");
}
function clickCircle2(evt:MouseEvent):void {
    trace("clickCircle2");
}
function clickStage(evt:MouseEvent):void {
    trace("clickStage");
}


Click the circle and see how the event is stopped with each method. stopPropagation prevented the stage from receiving the event while stopImmediatePropagation also prevented clickCircle2 from recognizing the event

normal output
Code:

clickCircle1
clickCircle2
clickStage


stopPropagation output
Code:

clickCircle1
clickCircle2


stopImmediatePropagation output
Code:

clickCircle1

senocular 09-03-2006 11:13 AM

Global Events
 
Sometimes in ActionScript you'll want to determine when an event happens globally, whether it starts on this object or that object or even no objects. For mouse clicks, ActionScript 1 and 2 had onMouseDown and onMouseUp events which were called globally despite the location of the mouse and which object it was over. If the mouse was clicked, these events would fire. In ActionScript 3, these events now only relate to mouse events specific to the object under the mouse. A normal sprite would not receive the mouseUp event if the mouse was over an empty area of the stage when the mouse was released.

To get these events to be recognized globally within ActionScript 3, you will need to have to use event listeners with the Stage object. Since the stage is the end parent of all display objects, all events pass through the stage.

Now, one might think a simple use of addEventListener with a listener function would be all you need, but its not that easy. What happens when someone listens for an event like mouseDown for a sprite and then stops propagation for that event? Then the event would never bubble up to reach the stage. However, the event would still reach the stage in the capturing phase so if a listener is set for the stage using capture, it will be recognized before it even reaches the target. This, however, does not account for instances where the stage itself was clicked. For that, you would need to use addEventListener twice for the stage, one for captures and one to get the at target phase of the event if the stage is clicked. The only problem with this is that if an instance on the stage is clicked and it doesn't stop propagation, the stage would receive the event twice, once during capture and once during bubbling. To prevent this, you can just have your listener function only react to the capturing and at target phases by checking the eventPhase property of the Event instance passed to it.

Example:
ActionScript Code:

var circle:Sprite = new Sprite();
circle.graphics.beginFill(0x4080A0);
circle.graphics.drawCircle(50, 50, 25);
addChild(circle);

// using stage for a global mouse up
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp, true);
function mouseUp(evt:MouseEvent):void {
    // only care about capturing and at target phases
    if (evt.eventPhase == EventPhase.BUBBLING_PHASE) return;
   
    trace("global mouseUp");
}

// circle stops propagation in its mouse up
circle.addEventListener(MouseEvent.MOUSE_UP, mouseUpCircle);
function mouseUpCircle(evt:MouseEvent):void {
    trace("mouseUpCircle");
    evt.stopPropagation();
}


Even though the circle here stops propagation of the event, the stage is still able to receive the event because it uses the capturing phase.

click stage output
Code:

global mouseUp

click circle output
Code:

global mouseUp
mouseUpCircle


senocular 09-03-2006 11:40 AM

Detecting a mouseUp Outside
 
Unlike ActionScript 1 and 2, there is no onReleaseOutside event for ActionScript 3. mouseDown and mouseUp events only fire for display objects when the mouse is over the display object. The only way to detect a mouseUp outside is to detect a global mouseUp after the target instance recieves a mouseDown. If the target of that mouseUp event is then not the object clicked, you have a mouseUpOutside. In addition to the mouseUp, you will also need a way to determine whether or not the object originally clicked was also the instance you had in mind, otherwise the global mouseUp would occur for all mouseUps whether the instance was clicked or not. This can be done using a simple variable.

Example:
ActionScript Code:

// variable to determine which instance was clicked
var clicked:DisplayObject;

var circle:Sprite = new Sprite();
circle.graphics.beginFill(0x4080A0);
circle.graphics.drawCircle(50, 50, 25);
addChild(circle);

function mouseDown(evt:MouseEvent):void {
    trace("mouseDown");
    clicked = circle;
}
function mouseUp(evt:MouseEvent):void {
    trace("mouseUp");
}
function mouseUpOutside(evt:MouseEvent):void {
    trace("mouseUpOutside");
}

// listeners for circle when pressed and stage for global release
circle.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
stage.addEventListener(MouseEvent.MOUSE_UP, captureMouseUp);
stage.addEventListener(MouseEvent.MOUSE_UP, captureMouseUp, true);

function captureMouseUp(evt:MouseEvent):void {
    if (evt.eventPhase == EventPhase.BUBBLING_PHASE) return;
   
    // make sure the circle was clicked
    if (clicked == circle) {
        clicked = null; // remove reference for subsequent clicks
       
        var target:Sprite = evt.target as Sprite;
        // if circle is target, mouse released over circle
        if (target == circle) {
            mouseUp(evt);
        }else{
            // mouse released outside circle
            mouseUpOutside(evt);
        }
    }
}


With this you have the equivalent of the onPress, onRelease, and onReleaseOutside events of AS1 and AS2 in AS3.

clicking on and releasing over circle output
Code:

mouseDown
mouseUp


clicking on and releasing outside circle output
Code:

mouseDown
mouseUpOutside


clicking on the stage results in no output.

Note: alternatively, instead of using a variable to store the clicked display object, you could also set the event listeners for mouseUp in the mouseDown event and then remove them in the mouseUp/mouseDown event.

saxplayer13 09-03-2006 11:41 AM

@Senocular:

How would you direct all keyboard events to one class? I've tried doing this in a game I'm developing, but it is very buggy and it keeps losing focus... I think what I need is a way to lock focus on one DisplayObject, but I can't seem to figure it out.

senocular 09-03-2006 11:46 AM

Quote:

Originally Posted by saxplayer13
@Senocular:

How would you direct all keyboard events to one class? I've tried doing this in a game I'm developing, but it is very buggy and it keeps losing focus... I think what I need is a way to lock focus on one DisplayObject, but I can't seem to figure it out.


Use the stage. See the tips above ^^^

AdamSchroeder 09-04-2006 12:31 PM

Thanks for the these latest tips. Particurarly the onMouseReleaseOutside example was very helpful. All of these tips are so useful... saves you so much time seeing them explained properly with examples vs. trial and error on your own to figure out.

I do want to add one tip that others new to AS3.0 might run into. The stage is now longer global but is a property of a DisplayObject IF it has been attached to a DisplayObject already placed on the stage.

So
var s:Sprite=new Sprite();
s.stage //is null
addChild(s)
s.stage //correctly reference the stage.

In pratical terms if you are extending the MovieClip to make your own classes you can not add events to the stage in your constructor (unless an argument you pass has access to it).

I had to pull my event adding code into a seperate function to call after the movieclip was already added.

example:
var e:ExtendedMovieClipClass = new ExtendedMovieClipClass();
addChild(e);
e.setupEvents();

Maybe you could get a reference from the actual Stage (capital S) class, but I haven't looked into that yet.

senocular 09-04-2006 01:09 PM

That is correct. The stage property is only accessible from display objects attached to the stage. There has been some discussion about this and approaches to access the stage eariler in this thread.

senocular 09-06-2006 08:05 AM

Flash 9: Document Class
 
ActionScript 3 with Flash 9 lets you specify a "Document Class" (aka Application class) for the main timeline. This represents the class of the root object - the display object in which (essentially) all other display objects are placed.

You can set the Document class in the Document Class option of the Property Inspector for a document with nothing selected. You can also set the Document Class in the ActionScript 3 Settings dialog using File > Publish Settings > Flash [Tab] > Settings... [Button (for ActionScript 3)]. When defining the Document class, you simply provide the name of the class which is to pose as the class for your document. Note: This class should exist within your class path.

The Document Class for Flash needs to extend Sprite or any subclass of Sprite (flash.display.Sprite) to be valid. If you use the main timeline for ActionScript at all in Flash, you would want your document class to extend MovieClip (flash.display.MovieClip) since MovieClips, unlike Sprites, support frames.

A document class should also be public (along with its constructor which is inherently public). A non-public class will result in an error when you publish your movie.

When published from Flash, SWF meta tags within Document Classes are ignored and the settings within Flash are used.

Unlike other display object classes you make, the stage property of a Document class will always be accessible since the document class is inherently a child of the stage. Similarly, if you place any objects on the main timeline in Flash, the will already be children of the Document class when its instantiated.

Example of a Document class:
ActionScript Code:

package {

    import flash.events.Event;
    import flash.display.MovieClip;
   
    public class CustomDocument extends MovieClip {
       
        public function CustomDocument() {
            addEventListener(Event.ADDED, checkChildren);
            checkChildren(new Event("initialize"));
        }
       
        private function checkChildren(evt:Event):void {
           
            // only allow one child in root
            if (numChildren > 1) {
                throw (new Error("This movie can have only one child instance"));
            }
        }
    }
}


This class only allows one child. If more are added, an error is thrown. Notice that the checkChildren method is also automatically called in the constructor since its possible that objects could have been added to the timeline within Flash which would have been before the added event listener was created.

v_gyku 09-06-2006 11:05 PM

Will the following code run? or is it somthing more I need to code?
I copy pasted the following code in the actions panel and tested the movie.
It gave a compile error: 1037: Packages cannot be nested.
Output window: ReferenceError: Error #1065: Variable MainTimeline is not defined.

Am i doing somthing wrong?

Quote:

Originally Posted by mathew.er
So that example at livedocs makes it pretty clear... "stage" is a global object allowing you to view and change its properties or to register events with it.

ActionScript Code:


package {</p>


<p> import flash.display.Sprite;</p>
<p> import flash.display.StageAlign;</p>
<p> import flash.display.StageScaleMode;</p>
<p> import flash.events.Event;</p>
<p>&nbsp;</p>
<p> public class StageExample extends Sprite {</p>
<p>&nbsp;</p>
<p> public function StageExample() {</p>
<p> stage.scaleMode = StageScaleMode.NO_SCALE;</p>
<p> stage.align = StageAlign.TOP_LEFT;</p>
<p> stage.addEventListener(Event.ACTIVATE, activateHandler);</p>
<p> stage.addEventListener(Event.RESIZE, resizeHandler);</p>
<p> }</p>
<p>&nbsp;</p>
<p> private function activateHandler(event:Event):void {</p>
<p> trace("activateHandler: " + event);</p>
<p> }</p>
<p>&nbsp;</p>
<p> private function resizeHandler(event:Event):void {</p>
<p> trace("resizeHandler: " + event);</p>
<p> trace("stageWidth: " + stage.stageWidth + " stageHeight: " + stage.stageHeight);</p>
<p> }</p>
<p> }</p>
<p>}




@fabiopb: Why? Isnt this just a sign, that flash goes on pretty well? If your worried anout the Adobe Flash application itself, then you dont need to be... Flex is just for something else than Flash. It wont also disappear from the Internet as everybody has the plugin, people are used to use it and it still has great potential.


v_gyku 09-07-2006 12:45 AM

Are there any basic tutorials or samples to start with action script 3?
I have developed many simple games in flash with AS 2.
What I tried to do with AS 3.0 is, simple on(press). which didn't work.
Can you tell me some basic tutorials, sort of "hello world" tutorials..

Thanks...

ven 09-07-2006 02:08 AM

In the duplicateDisplayObject example i get an error which i dont quite understand:

Error: Access of possibly undefined property constructor through a reference with static type flash.display:DisplayObject.

var targetClass:Class = target.constructor;


Ive tried many diffrent changes and read around in the manual, but i cant understand what im supposed to do.

senocular 09-07-2006 04:59 AM

Quote:

Originally Posted by v_gyku
Are there any basic tutorials or samples to start with action script 3?
I have developed many simple games in flash with AS 2.
What I tried to do with AS 3.0 is, simple on(press). which didn't work.
Can you tell me some basic tutorials, sort of "hello world" tutorials..

Thanks...


Like AS2, AS3 classes (those defined with package) must be placed in external files. Code on the timeline is not explicitly defined in classes (though becomes part of a class as explained in tip 38).

The first post in this thread has links to some documentation and tutorials.

senocular 09-07-2006 05:17 AM

Quote:

Originally Posted by ven
In the duplicateDisplayObject example i get an error which i dont quite understand:

Error: Access of possibly undefined property constructor through a reference with static type flash.display:DisplayObject.

var targetClass:Class = target.constructor;


Ive tried many diffrent changes and read around in the manual, but i cant understand what im supposed to do.


That is the result of having strict mode turned on in your ActionScript 3 settings. Strict mode uses a more strict compiler check to determine the validity of your code and it doesn't recognize the constructor property because it is added to Object's prototype dynamically (as mentioned in tip 21). To get rid of that error you can turn off strict mode or use something like
ActionScript Code:

var targetClass:Class = target["constructor"];


which should be able to bypass it.

Also, in using that function with Flash 9, make sure that you with the symbol(s) you are duplicating you export for ActionScript and give them explicit class names (even if the class is auto-generated). Otherwise, duplicateDisplayObject will not be able to duplicate the class properly.

v_gyku 09-07-2006 08:58 AM

goto one movieclip from another
 
There are two movie clips (background_mc, char_mc) on the main timeline.

This is the code on the keyframe inside char_mc.

Code:

_root.background_mc.gotoAndPlay(2);

I have searched macromedia live docs. I found that the closetst substitute for the _root is stage. I tried somthings which didn't work out.

any suggestion?

Thanks...

ignitrix 09-07-2006 09:22 AM

Quote:

Originally Posted by v_gyku
...
Code:

_root.background_mc.gotoAndPlay(2);

I have searched macromedia live docs. I found that the closetst substitute for the _root is stage. I tried somthings which didn't work out...


There has been a fair amount of discussion throughout this thread about the "stage" that should more than thoroughly answer your question.

~JC

senocular 09-07-2006 04:11 PM

I will try to make the next post a comprehensive stage access post.

v_gyku 09-08-2006 12:05 AM

I tried this and it worked.

Code:

root.background_mc.gotoAndPlay(2);

Quote:

Originally Posted by v_gyku
There are two movie clips (background_mc, char_mc) on the main timeline.

This is the code on the keyframe inside char_mc.

Code:

_root.background_mc.gotoAndPlay(2);

I have searched macromedia live docs. I found that the closetst substitute for the _root is stage. I tried somthings which didn't work out.

any suggestion?

Thanks...


senocular 09-08-2006 03:52 PM

Access to stage and root
 
In Flash it is often useful to reference the main timeline, or the root, of a movie. In ActionScript 3, the root instance of the SWF loaded into a player represents the first instance of the stage (flash.display.Stage). The stage object in Flash is the primary container in which all other display objects, including root, exist.

A Flash application only has one stage. However, there can be multiple root instances in an application if external content is loaded into the player using the Loader class (flash.display.Loader).

All DisplayObject (flash.display.DisplayObject) instances have stage and root properties. These properties, however, are null unless the display object is attached to the stage or a display list that is attached to the stage. The stage property, when accessible, will always reference the stage object. The root property references different objects depending on the display object:
  • For the stage, root always references the stage
  • For the main timeline of the SWF and all display objects within it, root references the main timeline
  • If an object is added directly to the stage from any timeline, the root property for it and its children references the stage
  • For display objects in loaded SWF files, root references the main timeline of that SWF file
  • For loaded bitmap images, root references the Bitmap instance of the image loaded
  • Loader objects used to load external SWFs and images follow the rules of all other display objects within the SWF it is being used

Keep in mind that only display objects have access to stage and root and only when attached to the stage or a display list on the stage. This is contrary to ActionScript 1 and 2 in two respects:
  1. All "display objects" (movie clips) in AS1 and AS2 were attached to the "stage" or an active timeline upon creation. This is no longer true with AS3; in fact, the only display object which is inherently attached to the stage upon instantiation is the document class (or, in Flash 9, objects existing on the timeline in the IDE before publish).
  2. All ActionScript in AS1 and AS2 are defined in timelines, even classes. AS a result, essentially all scopes gained access to _root through the timelines (MovieClip instances) in which they were defined. Since classes in AS3 are not defined in timelines, they no longer have access to root (or stage) unless they themselves are DisplayObject instances already attached to the stage

This greatly limits your access to stage and root within your scripts. For example, non-display object classes in AS3 can only access stage or root if explicitly given a reference. Ex:
ActionScript Code:

package {
   
    import flash.display.Stage;

    public class CustomObject {
   
        private var stage:Stage;
   
        public function CustomObject(stageRef:Stage) {
       
            // stage access through
            // constructor argument
            stage = stageRef;
        }
    }
}


Also, your display object classes will not inherently have stage or root access in their constructor unless they are used for the document/application class of your movie.
ActionScript Code:

package {
   
    import flash.display.Sprite;
    import flash.events.Event;

    public class CustomDisplayObject extends Sprite {
   
        public function CustomObject() {
       
            // stage not acessible until
            // added to stage or display
            // list on the stage
            trace(stage); // null
        }
    }
}


This can make it difficult if you need to access the stage for things like adding event listeners. You would need to either pass a reference of the stage (or root) to your custom display objects as with the CustomObject class or not attempt to access stage or root until the object has been added to a display list allowing it to be accessible. And for this you can manually call a setup or init function after the instance has stage accessible or detect it automatically using the StageDetection class (com.senocular.events.StageDetection).

Another approach to stage or root access would be to create a static property of a known class that would be accessible from any class. This class can be instantiated in the document class or it can be a DisplayObject subclass and you can have your document classes extend it as opposed to Sprite or MovieClip. For example, if you have your document classes always extend this TopLevel class, any class would be able to access stage or root (assuming they want root to be the document class extending this) using TopLevel.stage and TopLevel.root.
ActionScript Code:

package {
   
    import flash.display.DisplayObject;
    import flash.display.MovieClip;
    import flash.display.Stage;
   
    public class TopLevel extends MovieClip {
       
        public static var stage:Stage;
        public static var root:DisplayObject;
           
        public function TopLevel() {
            TopLevel.stage = this.stage;
            TopLevel.root = this;
        }
    }
}


Example document class using TopLevel
ActionScript Code:

package {
       
    public class MyDocumentClass extends TopLevel {
           
        public function MyDocumentClass() {
            // code
        }
    }
}


Example non-DisplayObject class used in MyDocumentClass application accessing stage:
ActionScript Code:

package {
       
    public class RandomClass {
           
        public function RandomClass() {
            trace(TopLevel.stage); // [object Stage]
        }
    }
}


Of course, ideally, you wouldn't need reliance on a class like TopLevel, especially if you are developing classes that might be shared with other developers. If someone is not in a position to have their document class extend TopLevel or simply don't have access to the class, any other class referencing it would fail. Passing around a reference of the stage (or root) or using the added (or added to stage) event(s) would be a safer way to go.

senocular 09-11-2006 04:11 PM

Namespaces: use namespace Directive
 
Like the name qualifier operator (name qualifier operator), the use namespace directive (use namespace directive) is a way for specifying namespaces in ActionScript 3. Unlike the name qualifier operator, use namespace is more generalize and applies to entire blocks of code rather than specfic references.

When used it is placed in a code block (package, class, method) and applies to all references within that code block. Though you cannot nest use namespace commands, you can use the name qualifier operator to reference other namespaces.

Example:
ActionScript Code:

package {
   
    public namespace company = "http://www.example.com/company";
    public namespace individual = "http://www.example.com/individual";
       
    public class UsingNameSpaces {
       
        use namespace individual;
       
        company var value:int = 10;
        individual var value:int = 2;
       
        public function UsingNameSpaces(){
            showValue(); // traces individual::2
            company::showValue(); // traces company::2;
        }
       
        company function showValue() {
            trace("company::" + value);
        }
       
        individual function showValue() {
            trace("individual::" + value);
        }
    }
}


Notice the use namespace individual; line within the class block. This inherently implies that the namespace for all references in that block is for individual. This makes the first call to showValue call individual::showValue. company::showValue can still be referenced using the name qualifier, but because it wasnt used for the value variable within it, its value defaults to individual::showValue which is why it shows as 2 instead of 10.

Krilnon 09-11-2006 04:53 PM

Are the namespace declarations supposed to be outside of the class definition? I run into errors when I have them declared outside of the class.

senocular 09-11-2006 04:59 PM

Quote:

Originally Posted by Krilnon
Are the namespace declarations supposed to be outside of the class definition? I run into errors when I have them declared outside of the class.


You should be able to have them both out of and in the class. Having them in the class means that they are only accessible from within the class while outside in the package block, they are accessible anywhere the package is accessible. the mx_internal namespace, for example, would be defined in the package block outside of the class block (allowing you to import it).

I compiled this example using Flash 9 alpha, not mxmlc, so there might be some differences there. What kind of errors are you getting? The only thing I can think of off the top of my head is possibility that, like with classes and packaged functions, namespaces defined outside of class blocks might need their own .as file for mxmlc.

Krilnon 09-11-2006 05:11 PM

Originally I was testing this in another class, but I just switched to your example and the same error comes up:

Quote:

Originally Posted by UsingNameSpaces.as
A file found in a source-path can not have more than one externally visible definition. company;individual;UsingNameSpaces


Quote:

Originally Posted by senocular
The only thing I can think of off the top of my head is possibility that, like with classes and packaged functions, namespaces defined outside of class blocks might need their own .as file for mxmlc.


That sounds reasonable.

Edit: These errors aren't at compile-time, they are just given by Flex before I try to debug, however, trace isn't outputting anthing.

ven 09-12-2006 03:28 AM

About loading external xml

I have problems finding some kind of errorhandling, like Flash 8 XML.status

[Edit]

Never mind, solved with:

PHP Code:

try {
    
myxml.parseXML(loader.data);
    
trace(myxml);
} catch (
error:Error) {
    
trace("Error: "+error);



And:Run-time Errors


[Edit2]

Actually, do mind...
Cause using XMLDocument as i did ine the example (XMLDocument.parseXML) is the old XMLobject, while XML is the new E4X-one.


When trying to get data from:

myXML = loader.data;

i get "Type Coercion failed" (error 1034)

and when i try

myXML = loader.data as XML;

myXML still contains null (nothing)

[Edit3]

and thats solved so easy i have to take 100 pushups

try {
myXML = new XML(loader.data);
(...)

senocular 09-12-2006 11:34 AM

No More Color Class; Use ColorTransform
 
ActionScript 3 does not have a Color class. Instead, you would use the ColorTransform class (flash.geom.ColorTransform). This is essentially the same ColorTransform class that was introduced in Flash Player 8. Though the Color class will continue to exist in Flash 9 using ActionScript 1 and 2, it will not be available when using ActionScript 3.

Note, in ActionScript 3, the rgb property of ColorTransform has been renamed to color.
ActionScript Code:

// creates a red square
var square:Shape = new Shape();
square.graphics.beginFill(0x000000);
square.graphics.drawRect(0, 0, 100, 100);

var colorTransform:ColorTransform = square.transform.colorTransform;
colorTransform.color = 0xFF0000;
square.transform.colorTransform = colorTransform;

addChild(square);


senocular 09-15-2006 07:59 AM

Runtime Errors; Error Class
 
Flash Player 9 with ActionScript 3 now handles native run-time errors that can warn you of conflictions or errors experienced within your code. If you are using the debug versions of the player (these players are often used by SWF authoring tools), a dialog will appear explaining any runtime error that might have occured.

When such an error occurs, an instance of an Error object (Top Level Error) is created and is "thrown" causing the reaction by the player. Though the Error object existed in ActionScript 1 and 2, it was only used by developers to throw their own errors using the throw keyword (throw statement); the Flash player did not throw errors itself as it does now with AS3.

Additional error types can be found in the top level (Top Level) and the flash.errors package (flash.errors). You can also create your own errors by extending the Error class which you would be able to throw yourself with throw.

An example of code that would generate a runtime error is:
ActionScript Code:

var value:* = new Array();
trace(value.getChildAt(0));


This throws a TypeError (Top Level TypeError) since value is of type Array, not DisplayObjectContainer which is the class that really contains the getChildAt method.

More information on run-time errors

senocular 09-15-2006 08:59 AM

Errors: try..catch..finally and Exception Handling
 
To handle errors, you would want to make use of the try..catch..finally statement (try..catch..finally statement). This statement lets you create codes block that can intercept thrown errors and deal with them appropriately (handle exceptions). If errors throw by the player aren't intercepted and "caught" the current script will terminate. Because ActionScript 3 throws errors on its own now, it will be increasingly more important to use this statement in your code.

Each try, catch, and finally (optional) represent 3 different types of code blocks that can be used within a try..catch..finally statement.
ActionScript Code:

try {
     // statements
} catch (error:Error) {
     // statements
} finally {
     // statements
}


The try block is the testing grounds that executes code that could potentially throw an error. This is the first block in the statement.

Following try is one or more catch blocks that can react to errors thrown in try. Each catch block is associated with an Error type that will run if that kind of error is thrown in try. If the type of the error thrown does not match the error type in the first catch block, the next catch block is checked until there is a match or until there are no more catch blocks to check (resulting in an uncaught exception). Because of this hierarchy of checking, its often a good idea to have your last catch block catch errors of type Error which would include all errors thrown.

After the catch block(s) comes one optional finally block which runs after the try and catch blocks. What's special about the finally block is that it will always run after try and catch, even if any one of those blocks used a return statement to exit the current function block or there is an uncaught error not handled in any of the catch blocks used (at which point any script following the try..catch..finally would not run).

Example:
ActionScript Code:

try {
    var value:* = new Array();
    trace(value.getChildAt(0));
   
} catch(error:IOErrorEvent) {
    trace("IOErrorEvent catch: " + error);
   
} catch(error:TypeError) {
    trace("TypeError catch: " + error);
   
} catch(error:Error) {
    trace("Error catch: " + error);
   
} finally {
    trace("Finally!");
}

trace("Continuing with script...");


This outputs
Code:

TypeError catch: TypeError: Error #1006: getChildAt is not a function.
Finally!
Continuing with script...

The TypeError was recognized in the catch(error:TypeError) block, caught, and the script was able to continue normally, but not before finally runs, of course. Though a catch(error:Error) was used here, it was not used because a catch(error:TypeError) was included that correctly matched the error thrown. If the TypeError catch was not there, the Error catch would have been used instead. What about what happens if only the unrelated IOErrorEvent is used?
ActionScript Code:

try {
    var value:* = new Array();
    trace(value.getChildAt(0));
   
} catch(error:IOErrorEvent) {
    trace("IOErrorEvent catch: " + error);
   
} finally {
    trace("Finally!");
}

trace("Continuing with script...");


Here is the output from Flash 9:
Code:

Finally!
TypeError: Error #1006: getChildAt is not a function.
        at Timeline0_a24dfc5f2aa9864b9d4de27c9fa097db/::frame1()

No erorr was caught, so the script was terminated after the finally block and the default error message was raised.

senocular 09-15-2006 09:27 AM

Errors: Asynchronous Exception Handling
 
Some errors in ActionScript 3 do not occur at the time of a function call and, instead, occur sometime after the call, asynchronously. The most common example of this is loading content from the web. Consider a URLLoader instance (flash.net.URLLoader) loading content like xml from the web. If the url used in URLLoader.load is an invalid url, the Flash Player won't know until it has been given the time to attempt a connection with url and determine whether or not it exists. While it tries to do this, the script in the player will continue run normally until such an error occurs. Since the script continues, a try..catch..finally statement would be of no use in attempting to catch these asynchronous errors since no error happens at the time those blocks run.

Example:
ActionScript Code:

var loader:URLLoader = new URLLoader();
loader.load(new URLRequest("Invalid XML URL"));
trace("Continuing with script...");


This outputs (Flash 9):
Code:

Continuing with script...
Error #2044: Unhandled ioError:. text=Error #2032: Stream Error. URL: file:///C|/DOCUME%7E1/senocular/LOCALS%7E1/Temp/Invalid XML URL
        at Timeline0_5650dafd68b564789d938267b772078/::frame1()

The error here happened after the "Continuing with script..." trace showing that it did not relate to the load call itself but rather an error that occured in the background as the player was working on that request.

Instead, what you would need to do is use event handlers "catch" asynchronous errors during error-related events which essentially prevents the error from being thrown in the first place. This is all done automatically without the need of try..catch..finally. Simply having an error event handler allows the error to be caught.
ActionScript Code:

var loader:URLLoader = new URLLoader();

loader.addEventListener(IOErrorEvent.IO_ERROR, catchIOError);
function catchIOError(event:IOErrorEvent){
    trace("Error caught: "+event.type);
}

loader.load(new URLRequest("Invalid XML URL"));
trace("Continuing with script...");


This outputs:
Code:

Continuing with script...
Error caught: ioError

showing the error was caught within the event handler which traced the event type.

Depending on your code, you may find the need to use both try..catch..finally and error handlers together.

Yakuza 09-17-2006 07:09 AM

err...sorry to interupt your tips...lol

want to ask question about Flash 9 actionscript 3.0 preview

I've tried the "stage.frameRate = 12;" to change my framerate dynamically...why it doesn't work? Even the trace will see as undefine object, do I need to import anything or what?

I'm not a coder for myself and I'm still pretty new to actionscript.

senocular 09-17-2006 07:17 AM

If you have it on the timeline in Flash 9, it should work fine (make sure your publish settings are for AS3). Other than that, if you're using it in a class, you would have to make sure you have access to stage. There is mention of this a few tips back, but it can be confusing, especially for a new coder.

senocular 09-18-2006 07:43 AM

XML: Children (.) and Decendants (..)
 
As you've probably seen, using E4X with ActionScript 3, you can get a list of children from an XML object or List using the children dot (.) operator (XML dot operator). Example:
ActionScript Code:

var myXML:XML =
    <foo>
        <bar />
        <bar />
        <bar />
    </foo>;
   
trace(myXML.bar.toXMLString());


Output:
Code:

<bar/>
<bar/>
<bar/>


This is the same as using the elements method in XML (XML.elements()).
ActionScript Code:

trace(myXML.elements("bar").toXMLString());


There's a similar operator that is two dots (..), the descendant accessor operator (descendant accessor operator). Its It works much like dot operator only it accesses not only children, but all children's children and their children etc. (decendants). Example:
ActionScript Code:

var myXML:XML =
    <note>
        <replying-to>
            <note>
                <author>Julie</author>
                <title>Reminder</title>
                <body>Take out the trash</body>
            </note>
        </replying-to>
        <author>Kevin</author>
        <title>Re: Reminder</title>
        <body>I will.</body>
    </note>;
   
trace("Children:");
trace(myXML.author.toXMLString());
trace("Decendants:");
trace(myXML..author.toXMLString());



Output:
Code:

Children:
<author>Kevin</author>
Decendants:
<author>Julie</author>
<author>Kevin</author>

You can see where children stopped in the current node (the XML object itself) the decendants operator will pick up all descendants of the node. The method equivalent of the descendant accessor operator is decendants (XML.descendants()).
ActionScript Code:

trace(myXML.descendants("author").toXMLString());


senocular 09-19-2006 09:51 AM

Array.indexOf (Array.lastIndexOf())
 
The Array class (Top level Array) in ActionScript 3 has a few new methods associated with it. Two are indexOf and lastIndexOf
Code:

AS3 function indexOf(searchElement:*, fromIndex:int = 0):int
AS3 function lastIndexOf(searchElement:*, fromIndex:int = 0x7fffffff):int

These work just like String.indexOf and String.lastIndexOf allowing you to find the position of objects within an array. As with String, if an object doesn't exist, -1 is returned.
ActionScript Code:

var sprite:Sprite = new Sprite();
var object:Object = new Object();
var boolean:Boolean = true;
var number:Number = 10;

var array:Array = new Array(sprite, object, number);
trace(array.indexOf(sprite)); // 0
trace(array.indexOf(number)); // 2
trace(array.indexOf(boolean)); // -1
 


senocular 09-19-2006 10:05 AM

asfunction: Now event:
 
As with ActionScript 1 and ActionScript 2, ActionScript 3 allows you to associate ActionScript events with links in text. Though not much has changed functionally (you can still not detect link rollovers, only clicks), the name of the string used to associate links with script has changed from asfunction to now being simply event (flash.text.TextField.event:link) in AS3.

In addition, with the new method of event handling in AS3, event (asfunction) no longer calls a method you defined but, rather, sends out an TextEvent (flash.events.TextEvent) of the type TextEvent.LINK for the text field instance in which it exists. The text following the event: keyword in the link is accessible from the TextEvent object through its text property.

Example:
ActionScript Code:

var linkText:TextField = new TextField();
linkText.htmlText = 'Link: <a href="event:Link Clicked">Click</a>';
addChild(linkText);

linkText.addEventListener(TextEvent.LINK, linkEvent);

function linkEvent(event:TextEvent):void {
    trace(event.text); // Link Clicked
}


Ordinathorreur 09-19-2006 10:20 AM

looking at your example, I suppose this means that AS3 now returns a reference to a dynamically created textfield?

senocular 09-19-2006 10:59 AM

Do you mean through new TextField? new TextField is much different than createTextField. createTextField is a function that attaches a text field to the screen. With new TextField you have a text field class which you are instantiating with the new keword. Whenever you use new [class name] the result is a new instance of that class; there's no option on whether or not to return references as is the case with functions like createTextField. In ActionScript 3, attachMovie and createTextField no longer exist. Instead you just create new instances and add them to the screen using addChild, so its not exactly the same.

senocular 09-21-2006 06:09 AM

Proxy: Property Enumeration (nextName(), nextValue(), and nextNameIndex())
 
Given the dynamic nature of Proxy (flash.utils.Proxy) instances, like with setProperty and callProperty, you are able to control Proxy instance enumeration (looping through properties of a Proxy instance using for..in and for each..in) using class methods. The methods that do this are:
  • nextName(index:int):String
  • nextValue(index:int):*
  • nextNameIndex(index:int):int
Both nextName and nextValue are the functions that let you decide what comes next in a for..in or a for each..in loop (nextName relates to for..in loops while nextValue relates to for each..in). The value returned by nextName is the key given in a for..in and the value returned by nextValue is a value for a for each..in. The index argument in their calls represents the number provided by nextNameIndex.

nextNameIndex is called before each loop iteration and allows you to do two things" a) set the index value that is to be received by nextName and nextValue (and itself for the following call) or b) stop the loop. Both of these are dictated by the return value coming from nextNameIndex. Any non-zero integer is used for the current loop interation and passed to nextName or nextValue which are called directly following nextNameIndex and a zero value stops the loop after nextNameIndex and exits the for..in or for each..in block used on the instance. The initial index value received by nextNameIndex is 0. Each subsequent value is the value it last returned (and was given to nextName and nextValue) unless 0 is returned and the loop is stopped. For example, assuming a proxy instance has 3 "properties" to loop over in a for..in, here is how nextNameIndex and nextName are used:
ActionScript Code:

for (var prop:String in proxy) {
    trace(prop);
}


Code:

for (var prop:String in proxy) {
        [ proxy.nextNameIndex(0) -> return 1 ]
        [ proxy.nextName(1) -> return "x" ]
        [ prop = "x" ]
        trace(prop); // x
        (end for block, repeat)
        [ proxy.nextNameIndex(1) -> return 2 ]
        [ proxy.nextName(2) -> return "y" ]
        [ prop = "y" ]
        trace(prop); // y
        (end for block, repeat)
        [ proxy.nextNameIndex(2) -> return 3 ]
        [ proxy.nextName(3) -> return "visible" ]
        [ prop = "visible" ]
        trace(prop); // visible
        [ proxy.nextNameIndex(3) -> return 0 ]
        (0 index, break from for block)
}

If a for each..in was used, nextValue would be called instead and the prop variable could be set to value, not just a string.

Because of the use of index to keep track of looping, you'll commonly see Proxy instances keep their enumerable properties or values in arrays. Then in nextName or nextValue you would just return the element in the array at index-1 (remember, nextName and nextValue would never receive 0 since that would have caused the loop to stop if returned from nextNameIndex). Here's an example of a proxy class that makes use of nextName and nextNameIndex and outputs what was seen above. Remmeber, proxy methods are defined in the flash_proxy namespace.
Class:
ActionScript Code:

package {
   
    import flash.utils.Proxy;
    import flash.utils.flash_proxy;
   
    public class ProxyEnum extends Proxy {
       
        private var props:Array = ["x", "y", "visible"]; // properties array
       
        // nextNameIndex called when the loop starts
        override flash_proxy function nextNameIndex (index:int):int {
            if (index < props.length) {
                // first call is 0, return 1 + index the index
                // starts with 1, then 2, then 3... etc.
                return index + 1;
            } else {
                // after outside of props bounds,
                // stop the loop returning 0
                return 0;
            }
        }
       
        // nextName called after nextNameIndex returns non-zero
        override flash_proxy function nextName(index:int):String {
            // return the array item in index - 1
            // this relates to a property name in a for..in
            return props[index - 1];
        }
    }
}


Usage:
ActionScript Code:

var proxy:ProxyEnum = new ProxyEnum();
for (var prop in proxy) {
    trace(prop);
}
/* output:
x
y
visible
*/



With this, you should also define nextValue and even getProperty to make sure that when users get these values in a for..in (or try a for each..in) its still valid. The modified class uses the same properties but adds a nextValue method and a getProperty to connect the dots between the values seen in for..in (making them relate to a display object passed into the proxy instance).
Class:
ActionScript Code:

package {
   
    import flash.display.DisplayObject;
    import flash.utils.Proxy;
    import flash.utils.flash_proxy;
   
    public class ProxyEnum extends Proxy {
       
        private var props:Array = ["x", "y", "visible"]; // properties array
        private var