Simple Box2D Example: AS3 and Haxe Side-By-Side

I posted a “Simple Box2D Example” a while ago, illustrating Box2D 2.1 running in Haxe.

To ensure feature parity between the Haxe version and the original, I created an alternate version in AS3 today. Since I have a bite-size project written in both AS3 and Haxe, I thought it might be a great opportunity to illustrate some of the differences between the languages.

Package declarations

AS3

package com.joshuagranick.simplebox2dexample { ... }

Haxe

package com.joshuagranick.simplebox2dexample;

The difference between package declarations in AS3 and Haxe is subtle. In AS3, you use brackets to surround your class declaration. In Haxe, you use a semi-colon. Class and type declarations are not surrounded by the package declaration.

Imports

AS3

import Box2D.Collision.Shapes.b2CircleShape;
import Box2D.Collision.Shapes.b2PolygonShape;
import Box2D.Common.Math.b2Vec2;
import Box2D.Dynamics.b2Body;
import Box2D.Dynamics.b2BodyDef;
import Box2D.Dynamics.b2DebugDraw;
import Box2D.Dynamics.b2FixtureDef;
import Box2D.Dynamics.b2World;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;

Haxe

import box2D.collision.shapes.B2CircleShape;
import box2D.collision.shapes.B2PolygonShape;
import box2D.common.math.B2Vec2;
import box2D.dynamics.B2Body;
import box2D.dynamics.B2BodyDef;
import box2D.dynamics.B2DebugDraw;
import box2D.dynamics.B2FixtureDef;
import box2D.dynamics.B2World;
import nme.display.Sprite;
import nme.display.StageAlign;
import nme.display.StageScaleMode;
import nme.events.Event;
import nme.Lib;

The imports are also similar between AS3 and Haxe. AS3 is loose in how you can capitalize your package and class names, while Haxe enforces lower-case package names and class names must begin with a capital. Personally, I prefer the second approach, which feels cleaner to me.

I am also using NME to publish my application in Haxe. Instead of using classes like “flash.display.Sprite” (which is still available), I am choosing to use the “nme” package so that I can receive more accurate code completion, for what is available in all targets and not only in Flash.

Class Declaration

AS3

public class SimpleBox2DExample extends Sprite { ... }

Haxe

class SimpleBox2DExample extends Sprite { ... }

Again, subtle differences. Class declarations in AS3 should be marked public (at least the first in each file). Class declarations in Haxe are always public.

The Constructor

AS3

public function SimpleBox2DExample () {
 
	super ();
 
	initialize ();
	construct ();
 
}

Haxe

public function new () {
 
	super ();
 
	initialize ();
	construct ();
 
}

The only difference in class constructors is that AS3 requires the constructor to have the same name as the class. In Haxe, the constructor is called “new”. Neither requires a return type.

The initialize () Method

AS3

private function initialize ():void {
 
	stage.align = StageAlign.TOP_LEFT;
	stage.scaleMode = StageScaleMode.NO_SCALE;
 
	PhysicsDebug = new Sprite ();
 
}

Haxe

private function initialize ():Void {
 
	Lib.current.stage.align = StageAlign.TOP_LEFT;
	Lib.current.stage.scaleMode = StageScaleMode.NO_SCALE;
 
	PhysicsDebug = new Sprite ();
 
}

Again, very similar. In Flash, the “stage” property is available after a DisplayObject has been added to the “display list”. In AS3, an exception is made for your “document class”, which has access to it immediately.

In Flash, you can wait until Event.ADDED_TO_STAGE is fired to access the stage, or Haxe provides a global property, “Lib.current”, which represents the top-level of the display list.

You can also see that AS3 uses “void” (lowercase) and Haxe uses “Void” (uppercase). All classes in Haxe begin with a capital letter. AS3 capitalizes most classes and types, but makes exceptions for things like “int” and “void”

The construct () Method

AS3

private function construct ():void {
 
	World = new b2World (new b2Vec2 (0, 10.0), true);
 
	addChild (PhysicsDebug);
 
	var debugDraw:b2DebugDraw = new b2DebugDraw ();
	debugDraw.SetSprite (PhysicsDebug);
	debugDraw.SetDrawScale (1 / PHYSICS_SCALE);
	debugDraw.SetFlags (b2DebugDraw.e_shapeBit);
 
	World.SetDebugDraw (debugDraw);
 
	createBox (250, 300, 500, 100, false);
	createBox (250, 100, 100, 100, true);
	createCircle (100, 100, 50, false);
	createCircle (400, 100, 50, true);
 
	addEventListener (Event.ENTER_FRAME, this_onEnterFrame);
 
}

Haxe

private function construct ():Void {
 
	World = new B2World (new B2Vec2 (0, 10.0), true);
 
	addChild (PhysicsDebug);
 
	var debugDraw = new B2DebugDraw ();
	debugDraw.setSprite (PhysicsDebug);
	debugDraw.setDrawScale (1 / PHYSICS_SCALE);
	debugDraw.setFlags (B2DebugDraw.e_shapeBit);
 
	World.setDebugDraw (debugDraw);
 
	createBox (250, 300, 500, 100, false);
	createBox (250, 100, 100, 100, true);
	createCircle (100, 100, 50, false);
	createCircle (400, 100, 50, true);
 
	addEventListener (Event.ENTER_FRAME, this_onEnterFrame);
 
}

In the construct () method, you can begin to see how I changed the naming convention on Box2D when I ported it over from AS3. The original C++ library uses a convention where classes begin with a lowercase, and methods begin with an uppercase letter. This can be strange and uncomfortable in AS3 or Haxe, which (almost always) do not use that convention. Capitalizing the start of the class names is required by Haxe, but I also lowercased the start of each method name.

The createBox () Method

AS3

private function createBox (x:Number, y:Number, width:Number, height:Number, dynamicBody:Boolean):void {
 
	var bodyDefinition:b2BodyDef = new b2BodyDef ();
	bodyDefinition.position.Set (x * PHYSICS_SCALE, y * PHYSICS_SCALE);
 
	if (dynamicBody) {
 
		bodyDefinition.type = b2Body.b2_dynamicBody;
 
	}
 
	var polygon:b2PolygonShape = new b2PolygonShape ();
	polygon.SetAsBox ((width / 2) * PHYSICS_SCALE, (height / 2) * PHYSICS_SCALE);
 
	var fixtureDefinition:b2FixtureDef = new b2FixtureDef ();
	fixtureDefinition.shape = polygon;
 
	var body:b2Body = World.CreateBody (bodyDefinition);
	body.CreateFixture (fixtureDefinition);
 
}

Haxe

private function createBox (x:Float, y:Float, width:Float, height:Float, dynamicBody:Bool):Void {
 
	var bodyDefinition = new B2BodyDef ();
	bodyDefinition.position.set (x * PHYSICS_SCALE, y * PHYSICS_SCALE);
 
	if (dynamicBody) {
 
		bodyDefinition.type = B2Body.b2_dynamicBody;
 
	}
 
	var polygon = new B2PolygonShape ();
	polygon.setAsBox ((width / 2) * PHYSICS_SCALE, (height / 2) * PHYSICS_SCALE);
 
	var fixtureDefinition = new B2FixtureDef ();
	fixtureDefinition.shape = polygon;
 
	var body = World.createBody (bodyDefinition);
	body.createFixture (fixtureDefinition);
 
}

This helps show a couple other small differences between the two languages. You may notice that “Number” is “Float”, or “Boolean” is “Bool” in Haxe. This is a little more consistent with other languages, but otherwise not important.

You may also see that the Haxe version does not have as much strict typing. You can add the same strict declarations in Haxe as you would in AS3, but they are unneeded. The compiler knows what type you will receive from a method, property or class constructor, and will provide completion appropriately.

If you did the same thing in AS3, you would receive compiler warnings (or might not compile on strict mode) and would not receive code completion for your objects. Especially for developers who are comfortable with languages that lack type declarations, like Javascript, Haxe’s “inferred types” for completion may be a big feature.

Conclusion

If you looked at the samples, you can see that both languages are very similar… almost like brothers. For those who don’t know already, Haxe grew out of MTASC, the first open-source Actionscript compiler. It is intended to be similar.

However, at the end of the day, AS3 publishes to Windows, Mac, iOS, Android and the internet, using Flash Player and Adobe AIR. You can use NME to publish Haxe to Windows, Mac, Linux, iOS, Android, webOS, Flash or HTML5, as SWF bytecode, native C++ code or Javascript… and you can still use Adobe AIR if you want to.

Not to mention, Haxe has other language features AS3 does not (iterators, generics, inlining, templates, macros, etc) which are nice. For me, the additional targets, and the significant gains I have seen by publishing to mobile using native C++ instead of Adobe AIR, have been completely worth it. Seeing a complex, physics-based isometric game engine run smoothly with NME at 30 FPS, compared to AIR with 6 FPS on a mobile device, is a big deal to me. There’s also something nice about knowing that my “future is in my hands” … in the past, I spent months waiting for Adobe to make good on their promises, or feeling disappointed as they did not commit to implement desired features. Now there’s no one stopping me.

Code

Feel free to try either project out yourself. I used FlashDevelop to work with each project, but you can use the editor of your choice. FlashDevelop has excellent support for Haxe and AS3. The Box2D library is included with the AS3 project, so you don’t have to download it yourself. For the Haxe version, you can open a command-prompt or terminal and install Box2D using haxelib:

haxelib install box2d

I hope this comparison has been helpful, and I’ll gladly answer other questions you may have.

http://joshuagranick.com/code/as3/Simple%20Box2D%20Example%20(AS3).zip

http://joshuagranick.com/code/haxe/Simple%20Box2D%20Example%20(Haxe).zip

  • Nacarlson

    Hi Joshua. I’m an experienced programmer, but I just started with NME today (as well as haxe). Thank you for this example project.

    I’d like to point out that there is a syntax error on line 33 of B2Math.hx. “1.7976931348623158e + 308” should be “1.7976931348623158e+308”.

    Also, would you happen to know how to enable auto-completion for your Box2d port? I’m using FlashDevelop 4. Some of the library is available for auto-completion, like B2World instantiations. However, I’m not seeing anything for B2PolygonShape nor B2FixtureDef. Is there a definition file somewhere that needs to be updated? 

    Thanks again!

  • Nacarlson

    I found the solution to the auto-completion problem.

    Set FlashDevelop->Tools->Program Settings->HaXeContext->Disable Compiler-based Completion to false.

  • Thanks! I just committed a new version of Box2D to haxelib. You can update by running “haxelib upgrade” from a command prompt.

    I noticed that B2PolygonShape had some commented out code, left over from C++. FlashDevelop doesn’t interpret code that occurs inside of condition #if #end statements, so (I think) the completion stops when it hits one. I killed the commented code in B2PolygonShape, so that might help with FlashDevelop’s completion of the class.

    If you run into other issues, let me know! I’d also love to hear how the experience works for you, and if there are things that could make things better.

    Have a great day!

  • Kubson

    I have some errors:

    C:Program FilesMotion-Twinhaxelibbox2d/1,06/box2D/collision/B2DynamicTreeBroadPhase.hx:98: characters 8-19 : Cannot access m_pairCount in static function
    C:Program FilesMotion-Twinhaxelibbox2d/1,06/box2D/collision/B2DynamicTreeBroadPhase.hx:103: characters 33-45 : Cannot access m_pairBuffer in static function
    C:Program FilesMotion-Twinhaxelibbox2d/1,06/box2D/collision/B2DynamicTreeBroadPhase.hx:118: characters 6-17 : Cannot access m_pairCount in static function

  • That’s strange. None of those functions appear to be static.

    Which version of haxe are you using?

  • Kubson

    Yes, that was the reason. I had 2.07 installed. With 2.08 works ok:)

  • Xander

    Hi Joshua,

    Does this example run on html5 as well?
    I tried to compile it, but I’m receiving the following error:

    process C:Motion-Twinhaxelibnme3,1,0/tools/command-line/html5/haxe/ApplicationMain.hx Export/html5/haxe/ApplicationMain.hx
    process C:Motion-Twinhaxelibnme3,1,0/tools/command-line/html5/haxe/nme/installer/Assets.hx Export/html5/haxe/nme/installer/Assets.hx
    process C:Motion-Twinhaxelibnme3,1,0/tools/command-line/html5/haxe/Reflect.hx Export/html5/haxe/Reflect.hx
    process C:Motion-Twinhaxelibnme3,1,0/tools/command-line/html5/hxml/debug.hxml Export/html5/haxe/debug.hxml
    process C:Motion-Twinhaxelibnme3,1,0/tools/command-line/html5/hxml/release.hxml Export/html5/haxe/release.hxml
    haxe Export/html5/haxe/release.hxml
    Error : float_of_string
    Called from ? line 1
    Called from InstallTool.hx line 549
    Called from InstallTool.hx line 94
    Called from installers/InstallerBase.hx line 116
    Called from installers/HTML5Installer.hx line 27
    Called from installers/InstallerBase.hx line 1002
    Called from InstallTool.hx line 285
    Uncaught exception – Error running: haxe Export/html5/haxe/release.hxml
    Build halted with errors (haxelib.exe).

    Regards,
    Xander

  • Bruno Imbrizi

    Hi Joshua. Thanks for the post. The example as it is runs fine on Android.

    I wanted to play a bit more with it, not only watch the shapes fall once, so I added mouse joints. It runs ok on Flash (
    http://brunoimbrizi.com/temp/nme/SimpleBox2DExample.swf ). But on Android all I got was a blank screen. Any ideas why adding mouse listeners would ‘break’ the example? I’m not sure how to track the error. If you have some time, please have a look at the modified file ( http://brunoimbrizi.com/temp/nme/SimpleBox2DExample.hx ). Thanks.

  • You should definitely be able to use a MouseJoint. I recently updated my Hoops basketball game to use this version of Box2D, and it worked fine on Android.

    Can you comment out your code, and try and increment step by step, to see what triggers the problem? If you run “nme test SimpleBox2DExample.nmml android” from a terminal, it should begin logging output from Android (so you can get trace messages, to make sure values are correct)

    Otherwise you can run “nme trace android” to get logging in a separate window

  • starPAUSE

    Joshua, great post! Very useful to read through the side by side comparison. 

    Xander, Kubson: I got this working with the html5 target on my winXP netbook tonight after doing a clean haxe 2.08 install, clean nme 3.2.0 install, running nme setup, restarting, collecting all the required haxelibs (box2d 1.11 and jeash 0.8.7).

  • Bruno Imbrizi

    I had to stay away from my NME tests for a while, but yesterday I got back to them and found what was causing the problem with mouse and Android. It was the useWeakReference = true as described in this thread: 
    http://www.haxenme.org/index.php?cID=1352&ccm_paging_p=1&time=1330816679#msg3256

  • Hi Joshua, Great example to start out with HaXe!
    I have elaborated on your code in an article, further elaborating on how to attach sprites to box2D and some other basic functionalities, such as CLICK (touch) events. Would you mind taking a look at it?

    http://blog.pepf.nl/2012/04/haxenme-one-language-to-rule-them-all/

  • Vishesh

    hey could you do a step by step tut on building a small html5 box2d app with haxenme and flashdevelop ?
    i want to dive into this but not getting a kikstart…

    ive dl’d nme for win & mac , currently dling visual-studio express and flash develop,
    i can start developing a test html5 project.

    but im a little lost here, i come from cocos2d background, so how can i get a similar experience with NME ?
    does it work like cocos2d ? do i start with a layer and add object to it and then attach box2d bodies to the sprites?

    kindly help me out here, i will download the box2d example when ive setup everything and try to have a go at it, but if you can post a small kikstarter tut,it’d be gr8

    regards
    vishesh

  • If you’d like to try out a game sample, here is one that I’ve tested with the HTML5 target:

    http://www.joshuagranick.com/blog/2012/04/12/html5-pirate-pig-sample/

    I might start there before playing with Box2D. I think this sample may compile for HTML5, but I haven’t tested it before. Let me know if you try it out, what happens.

  • And1

    Hi Joshua,

    I’ve tested your box2d class with the most recent version of haxe, nme, box2d and flashdevelop and I can’t seem to get any kind of code hinting for box2d stuff. (Code hinting works for nme classes fine).
    It does compile and run, but code hinting would be really useful. I tried setting all kinds of settings in haxecontext/ascontext, but none works really..