8

HaxeNME – One language to rule them all?

Development

Everyone wants to make apps these days, but what is the best platform to do this? With all these smart people around, why would we still need to program all these complicated byte buffers and texture memory if all we want to do is make an interesting game? Well, search no more, NME is your answer.

I recently found out about the existence of NME, a platform that is able to compile applications (read games) for basically รกll relevant platforms: Android, iOS, WebOS, Blackberry, Windows, Linux and the Flash Player. And contrary to the Corona platform, NME is free, and therefore a more interesting option. NME is based on the HaXe language, which as well serves as some sort of super-language, able to compile or transform if you will, into different other languages, such as PHP and C++.

After some initial tests and studying the examples, I decided to work on something for myself, and see if I could easily create an app for my (older) Android phone; a HTC Legend. And what is a good way to measure performance on different platforms? Right,ย  a physics engine! NME has built-in support for different physics engines, but I started out with Joshua Granick’s simple Box2D example and from there on updated it to explore the possibilities of NME. Granick’s example is a good start, but is a bit dull in my opinion. So what I wanted to achieve was the following:

  • Android: dynamically change screen width and height to device screen dimensions
  • adding sprites to the box2d objects
  • Add interaction: Touch anywhere on screen to add new objects
  • Add interaction: Touch the objects to remove them

While working on these things I came across some things I want to explain in detail below, but you can also download the project files (already sorry for the project title, I am using crates, not balls)

If everything works correctly, you should be able to compile to Windows, Flash and html5 without any problems:

HaXe NME multi platform test

Crate Project running on Windows, Flash and HTML5

Getting screen dimensions from device

Getting the screen dimensions from the device on which the code is running is done as follows:

ScreenWidth = cast(Lib.current.stage.stageWidth,Int);
ScreenHeight = cast(Lib.current.stage.stageHeight, Int);

For debugging purposes I also added these values to a TextField on the background, just to be sure.

Adding sprites to box2D objects

When creating the box2D objects, you’ll need to specify UserData. This is a special field that can contain anything to help developers link the box2D framework to something more… tangible. In our case, we are going to create a sprite, and add it to the UserData field as follows:

var crateBitmap:Bitmap = new Bitmap(Assets.getBitmapData("assets/crate.png")); //Create the crate bitmap
crateBitmap.x = -(crateBitmap.width/2);
crateBitmap.y = -(crateBitmap.height / 2); //Add it in the middle of the sprite
var crate:Sprite = new Sprite();
crate.addChild(crateBitmap); //Add bitmap to sprite
body.setUserData(crate);
crate.addEventListener(MouseEvent.CLICK, removeCrate);
crate.name = "Crate" + Std.string(boxId);
boxId++; //Update boxid, keep it unique
addChild(crate); //Finally, add to stage

Now for each box2D object, a sprite exists on stage, but not on the right position and angle. To achieve this, each frame the program iterates trough the list of objects, finds out the position and rotations and maps the sprites on top of the box2D framework. However, the HaXe language does not support the regular for() syntax that can be found in lots of Actionscript tutorials. Therefore I had to program a special Iterator class, that could help HaXe to understand how to walk trough the box2D list. The iterator class looks like this:
//This is the class that makes sure iterating trough the Box2D bodylist goes well,
//more info on interating in haxe: http://haxe.org/ref/iterators
class BoxIter {
    var current : B2Body;
  var count: Int;
  var first: Bool;

    public function new(world:B2World) {
        this.current = world.getBodyList();
    this.count = world.getBodyCount();
    this.first = true;

    }

    public function hasNext() {
    try {
      if (Std.is(current.getNext(),B2Body)){
        return true;
      }
    } catch (unkown:Dynamic) {
    }
    return false;
    }

    public function next() {
    if (first) {
      first = false;
      return current;
    }
    if (current.getNext != null){
      current = current.getNext();
      return current;
    } else {
      return current;
    }
    }
}

And in order to walk trough the Box2D World object, and to actually add sprites to the Bodies, you’ll have to do something like this:
  //Updating the sprites to match with Box2D
  public function updateGraphics ():Void {
    var iter = new BoxIter(World);
         for (b in iter) {
       try {
        if (Std.is(b.getUserData(),Sprite)){ //Check if userdata is a (Crate) sprite
           var sprite:Sprite = cast b.getUserData();
           sprite.x = b.getPosition().x/PHYSICS_SCALE; //Match position and Angle
           sprite.y = b.getPosition().y/PHYSICS_SCALE;
           sprite.rotation = b.getAngle()*180/Math.PI;
        }
       } catch (unkown:Dynamic) { } //Sometimes null objects appear, then Std.is() will fail at runtime
         }
     }

Adding Touch Interaction

You might have already notice how similar HaXe is to AS3. For a full list of differences you can look at the following website. Therefore the next code, in order to add touch interaction to our app will probably look familiar to AS3 developers. The difference with AS3 here is that the stage cannot be called just by typing stage; the stage object is hidden inside the Lib.current library.

Lib.current.stage.addEventListener (MouseEvent.CLICK, screenClick);

I hope this example gave you an impression of the power of this programming language, and the possibilities it has to create cross-platform games easily.