17
votes

Guys, I am thoroughly surprised that there is no Flash Hidden Features post yet in the Hidden Features series that I've been tracking for a while now.

There is a recent AS3/Flex one but it's not very active and I don't exactly mean just AS3 when I say Flash here.

The Hidden Features series is great for people who are new to a certain language. It shows the ropes and certain valuable tricks, all in one place. I think it's a brilliant idea. Even experts sometimes find tricks they'd never heard about.

When I started with Flash, I was taken aback by the Flash IDE and odd concepts of Flash, compared to other programming languages.

So, here goes: what are some hidden features of Flash as a language (AS2/3) and the Flash IDE?

Let the fun begin.

23

23 Answers

11
votes

[AS3] Tips for working with arrays or Vectors

Fastest way through an array, always from the back

var i:int = array.length;
var item:Object;
while(i--)
{
   item = array[i];
}

Clearing an array,

//faster than array = []
array.length = 0;

//garbage friendly
while(array.length)
{
    array.pop();
}

Pushing and splicing

//faster than array.push();
array[array.length] = "pushed value";

//faster than splice(index, 1)
var index:int = array.indexOf(splicee);
array[index] = null;
array.splice(array.length, 1);

Cloning

//fastest way to clone
var newArray:Array = array.concat();

//fastest manipulation
var mapFunction:Function = function(item:Object, index:int, source:Array):Object
{
    return //your cloning or morphing here
}
var newArray:Array = array.map(mapFunction);
8
votes

MovieClip.addFrameScript() is a undocumented ActionScript 3.0 feature that allows you to specify a function that is called when the playhead of the Movieclip timeline enters a particular frame number.

function someFunction():void {

}

movieclip_mc.addFrameScript(4,someFunction);

The frame number is zero based (1st frame = 0) and needs to be whole numbers only, however if you wanted to use frame labels you could use something like this:

function addFrameLabelScript(frame:String, func:Function):void{
    var labels:Array = currentLabels;
    for(var i:int=0;i<labels.length;i++){
        if(labels[i].name == frame){
            addFrameScript(labels[i].frame-1,func);
        }
    }
} 
7
votes

[Flash IDE]

This isn't a feature as much as it is a gotcha. When specifying a document class for an FLA, the compiler does not subclass that class, it modifies it.

This can cause problems when you have several SWFs with the same document class, all being loaded into another SWF (since two classes with the same name cannot be loaded side-by-side into the same application domain). It results in the first being loaded and the second using the first's modified class, producing weird errors (as you can imagine).

The solution is either:

  • Create a proxy class for each FLA that subclasses the document class
  • Load each SWF into a new child application domain
5
votes
Graphics::drawRoundRectComplex (x:Number, y:Number, width:Number, height:Number, topLeftRadius:Number, topRightRadius:Number, bottomLeftRadius:Number, bottomRightRadius:Number) : void;

It's not documented anywhere, but a forum post explains more.

4
votes

[AS3]

The || (logical or) operator can be used for any truthy/falsey values.

var obj : Object = nullObject || instance; // instance
var val : int = 5 || 10; // 5
var val : int = 0 || 10; // 10

Also, you can use & and | (bitwise and/or) to do a non-short-circuted expression:

function functionA() { return false; }
function functionB() { return true; }

if (functionA() && functionB()) { trace("something"); } // methodB won't be executed
if (functionA() & functionB()) { trace("something"); } // methodB WILL be executed
3
votes

[AS3]

When you use the trace statement in AS3 you can pass in multiple parameters and AS3 will format the output so that there is a space between each.

trace("Hello","World");

would output "Hello World".

AS2 does not support multiple parameters for trace so you are forced to do something like

trace("Hello "+"World");
3
votes

[AS3]

var list : Vector.<Object> = new Vector.<Object>();

becomes slightly shorter by writing

var list : Vector.<Object> = new <Object>[];

You can even predefine values:

var list : Vector.<Object> = new <Object>["one", "two", "three"];
2
votes

ActionScript 2

every class is a function and every function a class ... AS2 is prototype based ...

trace.prototype = { };
var f = trace;
trace(new f());//will yield [object Object]

accessing Function::prototype allows extending classes at runtime:

MovieClip.prototype.moo = function () {
    trace(this+" says 'moooooooo' ...");
}
_root.moo();//_level0 says 'moooooooo' ...

Object::__proto__ ... allows you to change the prototype of an object, which can be used for runtime reclassing:

var o = trace;
o.__proto__ = [];
trace(o.push("foo", "bar", "foobar"));//3 here
trace(o.length);//also 3
trace(o[1]);//bar

in this example, the function trace is reclassed to Array ... pretty cool, huh? :)


Function::apply and Function::call allow applying any function as a method to any object:

Array.prototype.push.apply(trace,[1,2,3]);
trace(trace.length);//3
trace(Array.prototype.splice.call(trace, 1,1));//2 ... actually, this is [2] (the array containing 2)

using the three above, instantiation of a class MyClass with parameters param_1, ..., param_n can be written as:

var instance = {};
instance.__proto__ = MyClass.prototype;
MyClass.call(instance, param_1, ..., param_n);

a corelation of Function::push and Function::apply is that this is simply a function argument, that is passed automatically ... as any other function argument, it can be written to ...

var f:Function = function () {
    this = [];
    this.push(1,2,3);
    trace(this);//1,2,3
    this = _root;
    trace(this);//_level0
}
f();

Object::__resolve ... settings this method allows you to react to lookups on undefined properties ... this is fun and useful for proxying, mocking, composition, delegation, and so on ...

import mx.utils.Delegate;

var jack:Carpenter = ...
var jim:BlackSmith = ...
...
var guys:Array = [jack, jim, ...]
var o = { __resolve : function (name:String) {
    for (var i:Number = 0; i < guys.length; i++) {
        var guy = guys[i];
        if (guy.hasOwnProperty(name)) {
            var ret = guy[name];
            if (ret instanceof Function) {
                ret = Delegate.create(guy, return);
            }
            return return;
        }
    }
    return "sorry man, but nobody knows, what '" + name + "' means";
});

//some really imaginary stuff (i hope it makes the point):
trace(o.saw);//[object Hammer]
trace(o.anvil);//[object Anvil]
trace(o.ventilator);//"sorry man, but nobody knows, what 'ventilator' means"
trace(o.makeSword());//[object Sword]

that's it for now ... there's an awfull lot more ... the thing is simply, that AS2 is an exiting language, but painfully slow ... AS3 in comparison is boring as hell, but the speed increase is really great ...

greetz

back2dos

2
votes

You can create weak references in ActionScript3 by using the Dictionary object.

2
votes

[AS3]

When looking for a the value of a variable, the player will run up the scope chain until it finds what it's looking for. So using nested (anonymous) functions you do things like make asynchronous calls and handle it using variables that were defined on the scope of the calling method. e.g.

function loadData(myAwesomeObject : AwesomeObject) : void
{

   var urlLoader : URLLoader = new URLLoader();
   urlLoader.addEventListener(Event.COMPLETE, function(event : Event) : void
   {
      myAwesomeObject.someReallyAwesomeMethod(event.target);
   });
   urlLoader.load(new URLRequest("http://someService"));

}

Loads of other uses for this and it's really very useful

2
votes

For those of you using FlashDevelop, there is some nifty conditional compilation functionality:

// Use it to generate different code paths
CONFIG::debug {
   txt.text = "Debug Version running...";
}
CONFIG::release {
    txt.text = "Welcome to Stark Industries";
}

// Or use it as a const in code
if ( CONFIG::debug && yourCondition ) {
    // Do stuff
}

read more about it here

1
votes

Its not really hidden (very obscured in the documentation), but updateAfterEvent is quite an unknown and useful method under certain circumstances...

1
votes

[AS3]

I wouldn't necessarily call this a 'feature', but you can actually access variables before they are defined (even with strict compilation) due to the way the compiler works:

trace(hb); // null
var hb : HBox = new HBox;
trace(hb); // [object]

It can actually lead to frustration when refactoring code (since it compiles).

1
votes

[Flash IDE]

When you export a MovieClip as a swc you can add it to the components panel of by dropping it into the folder

C:\Documents and Settings\USER_NAME\Local Settings\Application Data\Adobe\Flash CS3\en\Configuration\Components\SOME_COMPONENT_FOLDER

Restart flash and it'll be in the components panel for you to use.

1
votes

Well this might not be a hidden feature but maybe people have missed that there are external tweening engines you can use. My latest favourite is Greensocks. The only thing in my opinion it has lacked seems to be improving, workflow. Have not tested v.11 yet but definitely will on my next AS project: http://blog.greensock.com/v11beta/

1
votes

Not exactly hidden, but what about the often overlooked "include" macro (yes, it still exists in as3)? - very useful for faking multiple inheritance (when used side by side with an interface), even if it usually is a bad practice.

1
votes

when using flashvars write a utility method getFlashVars().

function getFlashVars():Object {
return Object(LoaderInfo(this.loaderInfo).parameters);

}

then when I'm coding I always add an extra || so that I won't have to flashvars while debugging.

localVar = getFlashVars().sampleVar || "default.xml";
1
votes

[as3]

prototype based inheritance :

import flash.display.MovieClip;

var myRectangle = function(target,x,y){
    var internalTarget = target;
    var myMovieClip = new MovieClip();
    var myGraphic = myMovieClip.graphics;
    myGraphic.beginFill(0xAAAAAA);
    myGraphic.drawRect(0,0,100,100);
    myGraphic.endFill();
    trace(typeof internalTarget);
    Sprite(internalTarget).addChild(myMovieClip);
    myMovieClip.x = x ;
    myMovieClip.y = y ;
}
var aRectangle = new myRectangle(this,10,10);
1
votes

Here's something most people don't know: MouseEvents are tracked outside of the application window if the MOUSE_DOWN event has been fired, but not MOUSE_UP. You can grab mouse positions outside of the application window (and even outside of the browser window) as long as whatever you're doing makes the user hold their mouse down. To test this, try running the following code:

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
           xmlns:s="library://ns.adobe.com/flex/spark" 
           xmlns:mx="library://ns.adobe.com/flex/mx"
           creationComplete="init()">
<fx:Script>
    <![CDATA[
        protected function init():void {
            addEventListener(Event.ADDED_TO_STAGE, magic)
        }

        protected function magic(e:Event):void {
            stage.addEventListener(MouseEvent.MOUSE_MOVE, moreMagic);
        }

        protected function moreMagic(e:MouseEvent):void {
            magicalButton.label = "Hold me down! " + String(e.stageX) + "x" + String(e.stageY);
        }
    ]]>
</fx:Script>    
<s:Button id="magicalButton" label="Hold me down!"/>

1
votes

This package will get you all the DisplayObjects in DisplayObjectContainer by setting class types.

Note: It wont count frames in MovieClips.

package {

import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.utils.getQualifiedClassName;

/**
 * 
 * @author Cansın Şenalioğly @ [email protected]
 *   
 */ 

//--------------------------------------
//  Class description
//--------------------------------------
/**
 * <p>Gets all DisplayObject types in DisplayObjectContainer.</p>
 *
 * @langversion 3.0
 * @playerversion Flash 9.0.28.0
 * @includeExample examples/ButtonExample.as
 *  
 *  @playerversion AIR 1.0
 */

public class DisplayObjectFinder
{

    /**
     * 
     * 
     * 
     * <p>Gets all DisplayObject type in DisplayObjectContainer</p>
     * <b>Example:</b><br> 
     * <p>var items:Array = DisplayObjectFinder.getAllDOTypeInDOC(stage,MovieClip,callBack);<br>
     * trace(items.length);<br>
     * function callBack(object:MovieClip):void{ trace(object.name) };</p>
     *
     * @param container Objects parent (DisplayObjectCotainer);
     * @param typeClass Objects Class type;
     * @param forEach For every object call back function;
     * 
     * @langversion 3.0
     * @playerversion Flash 9.0.28.0
     *  
     *  @playerversion AIR 1.0
     */ 
    public static function getAllDOTypeInDOC(container:DisplayObjectContainer,typeClass:Class,forEach:Function=null):Array {
        var a:Array = [];
        var len:int = container.numChildren;
        while(len--){
            var o:DisplayObject = container.getChildAt(len);
            if(flash.utils.getQualifiedClassName(o) == flash.utils.getQualifiedClassName(typeClass)){
                a[a.length] = o;
                if(forEach != null)
                    forEach(o);
            }
            if(o is DisplayObjectContainer){
                var aa:Array = getAllDOTypeInDOC(o as DisplayObjectContainer,typeClass,forEach);
                var lena:int = aa.length;
                while(lena--){
                    a[a.length] = aa[lena];
                }
            }
        }
        return a;
    }
}
}
1
votes

In Flash Professional, you can change a MovieClip symbol to a Sprite by redirecting it's base class from flash.display.MovieClip to flash.display.Sprite, and the symbol icon color in the library will change from blue to green.

enter image description here

enter image description here

0
votes

Custom metadata isn't something that's well documented or promoted, but it's very helpful - without modifying a variable or changing its namespace, you can give it custom annotations similar to the way that you can in Java.

It is gone over in depth by Christophe Conraets on his blog.

The simplicity of it is that you can put all of your own metadata, and then you just use describeType() and you will see all of your custom metadata at run time :)

0
votes

Here's another gotcha:

By default Flash tools strips any metadata tags that you have. Many frameworks depends on these metadata tags. What you need to be careful is that this doesn't only apply to the compiler, but also to the optimizer. Be sure to run both your compiler and optimizer with -keep-as3-metadata-tag option to keep your metadata tag in there.