Nape Game Dynamics Logo

Using the Nape v2.0+ Physics Engine in ActionScript 3

Nape is a powerful 2D physics engine which compares favourably in many regards to the oft-used Box2DFlashAS3. It is free and, more importantly, simple and quite intuitive to use. 

With the release of version 2 in December 2012, some important changes to the API rendered my previous tutorial obsolete. This new version now fully works with Nape’s latest version. So, if you are ready to upgrade, read on!

Warning: you will need the latest version of Nape (2.0.3 at the time of this writing) in order for this tutorial to work. If, for whatever reason, you still want to work with an older version, check out my previous tutorial.

Nape is a lighter-weight 2D physics engine which will most likely satisfy all your needs while being much easier to use than Box2D. It is also usually faster than Box2D. It does have a few drawbacks but, overall, I highly recommend you try it out.

During this tutorial, you will learn how to create the following very simple physics world. It comprises a floor (just below the bottom) and beach balls that bounce on it and each other. Click on the clip to see how it works :

Kudos to Christian Dugas (famed designer) for his amazing work on the beach ball.

Before you begin the tutorial, be sure to grab the source code for this tutorial and open it in Flash Pro as you will need it to follow along. Now, how can we use this Nape thing…

1. Installation (download & linking)

Before we begin, there is one little thing about Nape that should be clarified. It has been written using the Haxe language. Haxe is a language that can be cross-compiled into a variety of other languages such as ActionScript 2/3, JavaScript, C++, C#, etc. This means we won’t be able to download a package containing a bunch of regular AS3 classes like we often do. Instead, we will download a .swc (pronounced “swic”) file and link it to our project. This does not change anything for those who simply want to use the library. But for those who want to hack the library code itself, you will have to do it in Haxe. It also means the documentation is not quite what is being usually generated through tools such as ASDoc but that’s not really a problem…

The source code package for this tutorial already includes the 2.0.3 development .swc file but if you want to make sure you have the latest version, go to http://napephys.com/downloads.html and download the latest development build. Luca Deltodesco (the creator of Nape) recommends to always use the development version while developing and only use the release version for deployment (never use the debugging version unless you want to debug Nape itself).

To be able to use the nape-dev.swc (or nape-release.swc) file, it needs to be to linked to your project. It has already been done for you in the provided package. However, if you ever need to do it for another project,  just read my post titled Linking .swc files in your ActionScript Editor for all details.

2. Setup the Nape space

At this stage, you must follow along with the provided source code. The more obvious code has not been repeated in this tutorial for brevity’s sake.

Everything in the Nape world happens in one single object called the Space object. Let’s start by creating it :

space = new Space(new Vec2(0, 5000));

The Space object requires as a first parameter a Vec2 object which expresses the desired gravity. The Vec2 is simply a vector with 2 entries : the movement on the x axis and the y axis. If you don’t want any gravity (such as in space), you can use Vec2(0, 0). In the example, gravity pulls down on the y axis. If you wanted gravity to pull up, you could use a negative number.

3. Add a first physical body : the floor

Now, we need to add bodies into our world. Let’s first create a Body object to represent the floor upon which our smiley balls will bounce:

floorPhysicsBody = new Body(BodyType.STATIC);

As you can see, we need to specify the body type as a parameter. It can be STATIC, DYNAMIC or KINEMATIC. Since our floor will not move or change, we’ll define it as Body.STATIC.

Obviously, we now need to define our body’s shape. Actually, bodies can contain one or many shapes. You can manually add shapes or use tools that will allow you to draw complex shapes such as Physics Editor :

Physics Editor

Physics Editor allows you to export your shapes as ready-to-use Nape-compatible AS3 classes. In our case, we will simple use one of the basic shapes, the Polygon :

var p:Polygon = new Polygon (
    Polygon.rect(
        0, 			// x position
        stage.stageHeight, 	// y position
        stage.stageWidth, 	// width
        100			// height
    )
);

Then, we simply need to add our shape to the previously created body :

floorPhysicsBody.shapes.add(p);

As you can imagine, a single body can be created by compounding various shapes to create complex arrangements. The next step is to add our newly created floor body to the Nape space:

space.bodies.add(floorPhysicsBody)

By the way, you can achieve the exact same thing by assigning Nape’s space to the body’s space property :

floorPhysicsBody.space = space;

4. Add more bodies : the beach balls

The way the example works is that when you click, it generates a new ball, which then falls to the ground. I’m going to skip the obvious suff and go directly to the creation of the beach balls after the user has clicked :

var ballPhysicsBody:Body = new Body(BodyType.DYNAMIC, new Vec2(stage.mouseX, stage.mouseY));
var material:Material = new Material(1.5);
ballPhysicsBody.shapes.add(new Circle(s.width / 2, null, material));
space.bodies.add(ballPhysicsBody)

This time, the body type is DYNAMIC since the ball will be moving. It is positionned where the mouse is clicked. Instead of a Polygon, we now use a circle. In order to control the “bounciness” of the ball, we create a new material and use it to create the shape. Materials can have properties such as elasticity, density, friction, etc.

5. The Nape Space vs Flash’s Display List

Nape’s physics simulation is not meant to be directly seen. In order for us to see the behaviour and movements of the bodies in the Nape space, we need to link them to something we can actually see : DisplayObjects. The recommended way to do that is to assign a Sprite object (such as our s sprite) to the userData property of the body. Because it is dynamic, we can create all sorts of member variables inside the userData property. By convention, graphic is used (this is how it was named in the previous implementation) :

ballPhysicsBody.userData.graphic = s;

What this does is store a reference to the body’s visual representation which we will use later on. As of now, the visual will not move.

6. Get things moving

To make things move, we will have to constantly update our world to reflect its current state. You may have seen that an event listener has been added to the ENTER_FRAME event. This listener fires the loop() function which updates the Nape space via this line :

space.step(1 / stage.frameRate);
space.liveBodies.foreach(updateGraphics)

In our example, the frame rate is 60fps. Therefore, the physics simulation is being updated every 1/60th of a second. Once it has been updated, we need to sync our graphics to match the simulation. To do that, we can use the BodyList class’ very convenient foreach() function. Basically, it goes through all bodies in space.liveBodies and calls the updateGraphics() function on each of them. This allows us to update the visual for each body according to the simulation.

The code that follows in the loop() function simply removes balls that are no longer visible in order to preserve memory.

As you may have guessed, we now have to create the updateGraphics() function. This function receives a reference to the body it is being called on as a parameter:

private function updateGraphics(b:Body):void {
    var graphic:DisplayObject = b.userData.graphic;
    graphic.x = b.position.x; 
    graphic.y = b.position.y;
    graphic.rotation = (b.rotation * 180 / Math.PI) % 360;
}

The first line retrieves a reference to the DisplayObject that we stored earlier in the graphic property. With that in hand, we simply update the position and rotation of the DisplayObject to match that of the physics body.

Sidenote : Nape uses radians to express rotation while ActionScript uses degrees. This is why a little conversion is needed between the two. Also, the modulo operator (%360) is used because AS3 does not like big numbers for rotation.

Final notes

At this stage you might be wondering about the DEBUG constant that I used in the downloadable source code of this tutorial. When DEBUG is set to true, a ShapeDebug object is being created. This is optionnal and strictly for debugging purpose. The ShapeDebug object is a DisplayObject inside which Nape draws outlines of the bodies in its physics world. This means that you can visualize the behaviour of bodies even if no visuals have been assigned to them.

If you want to see only the output of ShapeDebug, simply comment out this line and recompile :

space.liveBodies.foreach(updateGraphics);

That’s it! Your questions and comments are, as usual, welcome. Hope this helps.

Comments

  1. I keep getting an error with Nape. When I try to create a circle, it tells me that it expects no more than 0 parameters. Even weirder, this only seems to happen when I use a document class. If I use the same code on the timeline, it works fine.
    After a while of getting this error, I straight up copied and pasted your code into my .as file, and I still get the same error.
    Any ideas? I think it probably has something to do with my .fla.

    1. Luke,

      Are you sure Nape is giving you the error and not some other library which also happens to have a Circle object ? Were you able to run my tutorial file directly (instead of copying and pasting the code into some other file) ? Which version of Nape are you using ? Is it the development version ?

      1. Yes, I’m sure it’s Nape. When I type it, some code hints come up that mention nape.shape. And yes, running your tutorial works just fine. I’ve downloaded the most recent development version of Nape, which is 2.0.3.

        1. Hum… that’s odd. I’ve seen corrupted .fla files. It’s quite rare but it does happen. Did you try to recreate your .fla file ?

          Otherwise, something else in your code must be interfering. I’m afraid the only thing I can suggest at this stage is to strip as much as you can from the code until the problem goes away. This way, you will know what was giving you issues.

          Let me know if you ever find a solution.

          1. Just figured it out.
            I was thinking it was a corrupted .fla, but after I recreated my .fla about 3 times, I ruled that out.
            Then I realized that the only other difference between your, working program, and my non-working program, was the folders I had them saved into.
            I moved your .fla and .as file into the same folder that my program was saved into, and it didn’t work. Moved them back out and they worked again.
            So I just moved my glitchy program into a different folder, and magic, now they work.

          2. Wait, what ?! The folder was giving you trouble ?! This is the first time I hear of such a problem. Was the folder deeply nested (meaning it might have reached the maximum path length) ? Perhaps the folder name had weird characters in it ? In any case, thanks for sharing. I’ll have to add this to my troubleshooting kit…

          3. Yeah, weird, huh?
            I have a folder called Flash Creations, where I saved my glitchy .fla. The nape_dev.swc was also saved into Flash Creations. I had your sample .fla and .as files in my Downloads folder. I just moved the glitchy .fla from Flash Creations to downloads, and it started working.

  2. You might expect the next step to be to add the body to our space. However, it works the other way around. I think this is a bit counter-intuitive but you need to tell the body which space it belongs to :

    You don’t ‘have’ to write: body.space = space; you can if you wish, write space.bodies.add(body) and the same applies to most parts of the API, you can do shape.body = body; or body.shapes.add(shape) (similarly body.space = null is roughly the same as space.bodies.remove(body))

    1. I had not realized that, thanks for pointing it out. I will reformulate this part of the tutorial to better reflect this option which feels a bit more natural to me. BTW, thanks for the great library!

  3. Now that it’s a beach ball, this tutorial makes a lot more sense. (It was a smiley before that…)

  4. nice example.
    wonder why the debug draws and the starling images are not in sync (positions) when the velocity large – but are in perfect sync when they are at rest or in slow velocity.
    I ran an example with 1 square body (with square starling image) moving -500 pixels along the x axis, here the debug draw moves faster than the image.

    Would this not be a problem if we have 100 very fast moving objects like bullets.

    1. Dimitri,

      I have not tried using Nape with Starling but many others did. I cannot see why Starling would be lagging behind. Do you have the same issue with a regular DisplayObject?

  5. It still says “smiley balls” above the sample and the polygon comments are not aligned to the code properly. Just wanted to let you know. Thank you for the awesome tutorial.

      1. The comments for polygon are correct, but the numbers don’t line up. Shouldn’t it be 0,100,stage.stageWidth,stage.stageHeight)?

        1. Nevermind I think i just realized why. The floor needs to be on the bottom obviously.

  6. How do you apply the PhysicsEditor shape to something rather than using a core shape like circle? I am having trouble applying .as files from PhysicsEditor as the shape for a body.

    1. I should add that I am using a pure AS3 project without Starling and trying to add custom shape from PhysicsEditor to a Nape body.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.