AGE - How to support physic engines

In the previous post, we have seen how to use the Box2D support into the AGE engine. Now I just want to show you how simple it is to add a new framework/engine support.

For example, we are going to add the Nape support.

For those of you who don’t know, Nape is a Haxe/AS3 physics engine. Since Nape is really close to Box2D, it will be simple to understand how box2d has been added to AGE.

The behavior

Since AGE is based on a behaviors system, we are just going to create a new behavior, that we will call NapeMovementBehavior :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class NapeMovementBehavior implements IBehavior
{
    private var _entity : BasicEntity;
    public var enabled(default, null) : Bool;

    public function update():Void {}
    
    public function enable()
    {
	enabled = true;
    }
    
    public function disable()
    {
	enabled = false;
    }

    public function destroy():Void {}
}

Now we are going to initialize the data needed by Nape for the behavior’s entity :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
private var _body : Body;
public static var world : Space;
public function new(pEntity: BasicEntity, pDynamic:Bool)
{
    if(world == null)
        world = new Space( new Vec2(0, 500) );

    _body = new Body( (pDynamic ? BodyType.DYNAMIC : BodyType.STATIC), 
                       new Vec2(pEntity.x + pEntity.halfWidth, pEntity.y + pEntity.halfHeight)
                   );
	    
    var block:Polygon = new Polygon(Polygon.box(pEntity.width,pEntity.height));
	    
    _body.shapes.add(block);
    _body.align();
				
    _body.space = world;
	
    _entity = pEntity;
}

If you need more information on how Nape is working, go check the documentation. So for now, we have a basic entity initialized for working into Nape.

We have to update the entity position into the game based on the Nape’s one :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public function update():Void
{
    #if cpp
    _entity.x = _body.position.x;
    _entity.y = _body.position.y;
    #else
    _entity.x = _body.position.x - _entity.halfWidth;
    _entity.y = _body.position.y - _entity.halfHeight;
    #end
        
    _entity.rotation = _body.rotation * 57.2957795;
}

There is some differences between c++ and flash: with the flash renderer, we must have the center point at the top left position (for now).

Now the destroy function (called after the behavior has been removed) :

1
2
3
4
public function destroy():Void
{
    world.bodies.remove(_body);
}

If you have noticed, the world variable is static, because we have to update it on each frame. So to keep the behaviors system intact, we are going to use the BehaviorsManager :

1
2
3
4
5
6
7
8
9
public function new(pEntity: BasicEntity, pDynamic:Bool)
{
    if(world == null)
    {    
	world = new Space( new Vec2(0, 500) );        
        BehaviorsManager.getInstance().registerUpdater(globalUpdate);
    }
    // [...]
}

Now the globalUpdate() function is going to be called on each frame :

1
2
3
4
public function globalUpdate():Void
{
    world.step(1/30, 10, 10);
}

How to use it ?

Now to use this behavior with an entity, just add the NapeMovementBehavior to the behaviors list :

1
2
3
4
var e : BasicEntity = new BasicEntity(0, 0);
e.makeGraphic(32, 32, 0xFFFF0000); // create a rectangle
e.addBehavior( new NapeMovementBehavior(e, true) ); // add the behavior
add(e); // add the entity to the game

Here is a quick demo (drag the blocks) :

You can see the NapeMovementBehavior class here and the NapeEntity class here.