Using Haxe with Flash9

You can use the Haxe language to build Flash9 SWF. To do that, simply compile using -swf-version 9 and the Haxe compiler will generate a Flash Player 9 compatible SWF.

Example - Test.hx:

class Test {
    static function main() {
         // creates a TextField         
         var tf = new flash.text.TextField();
         tf.text = "Hello World !";
         // add it to the display list
         flash.Lib.current.addChild(tf);
    }
}

Compile using the following HXML file - compile.hxml :

-main Test
-swf-version 9
-swf test.swf

When you compile a project for Flash9, you will have to use the new ActionScript3/Flash9 API instead of the old ActionScript2/Flash8 ones. You can find these described in the Haxe API (click on flash9 to unroll the menu). This API is exactly the same as that available from AS3 and it contains additional undocumented methods.

This API is documented on the Adobe livedocs

Although there might be some bugs left, the Haxe Flash9 code generator is working correctly and in some cases generates faster code than the official Flex compiler. Try it yourself and report your findings on the Haxe mailing list.

You can add debug information to your Flash9 swf by compiling with -debug. This will enable you to see Haxe source file names and line numbers when a runtime exception occurs.

Using the Library

If you have graphical resources that were created by the Flash IDE (either MX 2004 or CS3) or SwfMill, you can use them from your Flash9 code by doing the following :

  • create a library SWF, giving identifiers/linkage names/class names to your MovieClips.
  • statically link the library with haxe by using -swf-lib when compiling. E.g, in your hxml file :
    -main Example
    -swf example.swf
    -swf-version 9
    -swf-lib library.swf

If using Flash MX or swfmill for your library, then use a linkage name like you would when using the old attachMovie. With Flash CS3, use class names like you normally would for AS3.

Attaching By-Name

Haxe automatically creates classes for MovieClips that have linkage or class names, if there is not already one available. Use flash.Lib.attach("name") to create an instance of that MovieClip. For example, if there is a MovieClip in your library with a linkage or class name of "MyShape":

class Test {
   static function main() {
         var s = flash.Lib.attach("MyShape");
         flash.Lib.current.addChild(s);
   }
}

//@ emceekay

class Test {
   static function main() {
         var s = flash.Lib.eval("flash.display.Shape");
         flash.Lib.current.addChild(s);
   }
}

In case one of your graphics is a linkage identifier but no class is defined, you can catch the exception thrown by flash.Lib.attach or by using the Flash9 Debug Player.

Class binding

If on the other hand you want to redefine/extend the behavior of the MovieClip, then you can simply define a class in Haxe with the same name :

// Test.hx
class Shape extends flash.display.MovieClip {
   public function move() { x += 2; y += 2; }
}

class Test {
    static function main() {
         var s = new Shape();
         flash.Lib.current.addChild(s);
         s.move();
    }
}

Compile it using the following HXML :

-main Test
-swf-lib lib.swf
-swf-version 9
-swf test.swf

This will create a SWF that will, once opened, display the graphics named Shape and move it a little bit. In the case one of your graphics is a linkage identifier but no class is defined, the Flash Debug Player 9 should give you an error when loading it.

Embedding a font

If you want to embed a font, make a resource.xml file like this:

<?xml version="1.0" encoding="iso-8859-1" ?>
<movie version="9">
    <background color="#555555"/>
    <frame>
    <library>
        <font name="Symbols" import="font/dejavusans.ttf" 
glyphs="&#x2605;&#x2606;&#x2613;&#x2620;&#x2713;&#x2714;&#x2715;&#x2716;&#x2717;&#x2718;&#x2764;"/>
    </library>
    </frame>
</movie>

Use swfmill simple resource.xml resource.swf to build resource.swf with the font. Add the following somewhere:

class Symbols extends flash.text.Font {}

Next, use -swf-lib resource.swf to link resource.swf into the final .swf, and use your font using the name Symbols. Be sure to set embedFonts = true.

Additonal Note:
for glyphs you can use letters ie: 'abcdefghijklmnopqrstuvwxyz' but since its xml some characters can not be written in this way, here is a useful method to help you encode characters, there maybe more optimal method but this works fine.

    private function buildAscii( s_:String ):String
    {
        var ascii:  String  = '';
        var i:      Int     = 0;
        while( i < s_.length )
        {
            ascii += '&#' + s_.charCodeAt( i ) + ';'; 
            i++;   
        }
        return ascii;
    }

Incompatibilities

Some specific features will fail to compile or run on Flash9 :

  • having a try/catch block inside an expression, such as the following sample :
    var x = try f() catch( e : Dynamic ) null;
  • having a class implementing another class (accepted in Haxe but not in Flash9)
  • there is no equivalent of the Flash Error class in haxe, you can throw any object so you don't need to inherit from Error. It is a good practice in AS3 to throw objects of classes that inherit the Error class but it is not mandatory.
  • there are some issues with nullness of Int, UInt, Float and Bool (see below)

Everything else should work perfectly and provide the same result on all the supported platforms.

Nullness of Basic types

In Flash9, the basic types Int, Float and Bool can't be assigned or compared with the null value. Int variable default value is 0, Float is NaN and Bool is false.

If you want to be able to store null values in these basic types, please use the types Null<Int> , Null<Float> and Null<Bool> instead. This will work the same as basic types, except that at runtime a Dynamic (Object in AS3) type will be used, enabling the null value to be stored.

For optional arguments, the Null<...> type is automatically used.

Using Null instead of the basic type will degrade performance a bit, but there is no reason to worry unless it's used for speed critical methods (in that case don't use optional arguments or Null types).

This can also have some undesirable side effects. For example the following method will return null when called without arguments.

  function foo( ?x : Int ) : Null<Int> {
      return x;
  }

While the following will return 0 since null is converted to Int when returned :

  function foo( ?x : Int ) : Int {
      return x;
  }

The same problem can occur with Arrays :

   var a = new Array<Int>();
   trace(a[999]); // 0 , since it's Int default value
   var b = new Array<Null<Int>>();
   trace(b[999]); // null : it works this time

As a conclusion, while basic types are really faster, be careful when using them.

Attaching events to the stage

When your main class is created you can attach stage events by calling your init function after adding the application to the stage.

import flash.display.Sprite;
import flash.events.KeyboardEvent;

class Application extends Sprite {
  public static function main() {
    var app : Application = new Application();
    flash.Lib.current.addChild(app);
    app.init();
  }

  function init() {
    stage.addEventListener( KeyboardEvent.KEY_DOWN, onKeyPress);
  }
  
  function onKeyPress(e : KeyboardEvent) {
    trace("Key Code: " + e.keyCode);
  }
}

Compile it with the following command:

haxe -main Application -swf9 movie.swf

Another way of doing this is using the ADDED_TO_STAGE event.

version #13859, modified 2012-04-25 00:54:40 by foobar