Though it is possible to run any of these libraries without a visual representation, that isn’t much fun, so we will set up a small environment to see the results as the simulation runs. I’ll use Three.js and its CanvasRenderer for this due to its popularity and how simple it is to use. Besides showing how the objects are interacting, this will also demonstrate how to extract scene information from each library. The scene will consist of two ramps leading down to a floor; balls will drop down onto the ramps from random locations above the scene, roll down the ramps, and land onto the floor.
Our base scene that will be used in each example has two ramps which lead down to the ground. Balls will be dropped from random points above the ramps, rolling down to and then off of the ground plane. This simple scene will highlight the similarities and differences between the four libraries.
box2dweb is a port of the C++ box2d project and is unique on our list of libraries in that it is designed to only simulate two-dimensional scenes. All of its classes are namespaced which can make the code a little hard to read, so it is recommended that you create your own local variables for any objects you commonly use. Don’t be fooled into thinking box2dweb is a weak library because it only performs 2D simulations; within its simple API is a ton of power. box2dweb has a full constraint system (which it calls joints), continuous collision detection for more accurate fast-moving bodies, and lots of configuration options both for the whole scene and for individual objects.
Collision detection with box2dweb is easy to do by using the
b2ContactListener object. You can have separate event handlers for each of the four collision states:
PostSolve. You can also detect collisions by iterating over the world’s contact list after each step.
1 2 3 4 5 6
Joints are used to constrain objects in different manners, making objects act as though they are on hinges, slide in only one direction, move like they’re attached via a rope, and many other configurations. It can take a bit of testing to get a joint working like you want it, but after a while you start to get the hang of them and adding joints becomes much a much quicker process. As an example let’s create a Revolute Joint – or in normal terms, a hinge. All joints in box2dweb take two bodies and a world position, except for the friction joint which only needs one body; for more details on the available joints and the various configuration options they have check out the Box2D manual or one of the many online Box2D joint tutorials.
1 2 3 4 5 6 7 8 9 10
Finally a last piece of information before we see the box2dweb demo: how to update your scene after a step in the simulation, such as updating the graphics in a game. The
world object has a method named
GetBodyList which will return the first body in the scene. You can then iterate over the remaining bodies in the scene by continually calling
body.GetNext() until the
GetNext method returns null. As you encounter each body you can update the associated graphics object or anything else which needs to be maintained. Custom information can be attached to each body when you create them by using the body definition’s
userData property. This
userData usually includes a reference to the geometry object which makes updating that geometry’s position and rotation simple.
- Performance: I have never seen a box2dweb scene run slowly unless it was set up poorly. Instead, game logic and the actual graphics rendering usually have the biggest impact on FPS.
- Features: Box2D was never meant to do 3D, so most of the “missing” features aren’t actually missing, they just don’t work in 2D environments. If you only need two dimensions this library should have everything you need.
- Usability: Very simple API, although it can be somewhat hard to find objects in the different parts of the namespace. The Box2D manual isn’t too thorough so you may end up looking at the flash port’s documentation and search for specific topics online.
- Overall: This is a very powerful engine that isn’t hard to set up, and there is no steep learning curve. If all you need is two-dimensional physics you won’t have to look any further than box2dweb
- Browser Support: Chrome, FireFox, IE9, Safari, Opera
In order to update the scene’s visual representation you need to keep track of any objects added to the world – Ammo.js won’t do that for you. Each time the scene is rendered you can iterate over those objects and update their positions and rotations. The way to create the physics objects in Ammo.js can seem a big dragged out and complex, but this also allows a much more fine-tuning on a per object basis. A lot of times it will be very helpful to create a function which builds the objects for you to avoid duplicating that code. Also unlike box2dweb, Ammo.js does not support collision events. In order to find and handle collisions you need to get a list of the world’s contact manifolds and loop over them. Each manifold will tell you what objects collided and at what point.
Adding object constraints can be a little difficult until you get the hang of how they are defined. Most of the constraints can bind one object to a position in the world or constrain two objects relative to each other. For example, you could add a hinge constraint to a single object, making it rotate around a single point in the world, but specifying a second object means that same constraint will act like a hinge between the two objects – such as a door attached to a wall. Each type of constraint has its own settings to limit movement or specify how an object acts when it reaches those limits.
1 2 3 4 5 6 7 8 9 10
- Usability: The API can be confusing at times, and the auto-generated documentation isn’t much help. There have been times I have had to dig through Bullet’s codebase to discover how a function parameter is used and even that one had been deprecated. A lot of time can be spent tweaking settings in order to understand what impact they have and finding the right setup for your game environment.
- Overall: If you’re looking for a fully-featured physics library then Ammo.js will get the job done. After taking some time to become familiar with the stranger parts of the library you can quickly develop complex scenes with rich interactions.
- Browser Support: Chrome, Firefox, Safari, Opera
Overall the API is consistent and it easy to find things, but there are a couple of places where it’s easy to trip up. For example, almost all of the methods take spatial and rotational arguments in the X,Y,Z order – as you would expect. However, when defining a new box shape the order of the box’s dimensions is X,Z,Y. The documentation clearly states this as the order but it can be easy to overlook if you go too fast. Another difference between JigLibJS and the other libraries is how you include them on the page. With Ammo.js and box2dweb there is only one script to include, but when using JigLibJS you must include each class file individually. This can help you keep the page’s memory usage lower by not loading unused pieces of the library, but it is a bit of a hassle to include everything separately. One other detail to pay attention to is the method names – some are simple_separated_by_underscores while others follow theCamelCaseStyle, which style a certain method follows is seemingly random, but my guess is that it is related to the original port from C++.
What surprised me the most and presented the biggest challenge with JigLibJS was getting the object rotations right. In fact the official build contains an error in the radians-to-degrees conversion calculation. It is a very simple fix but its presence is more than a bit unsettling. One other thing to look out for with object rotations: you need to set any moving object’s rotational damping to a much more reasonable value. Simply put, damping is an effect that reduces the amount of linear and rotational velocities. By default, the rotational damping is set at
[.5, .5, .5, 0] which severely limits the amount of rotation. A more realistic amount is
[.95, .95, .95, 0], which matches the default linear damping. Updating the graphics with JigLibJS is closer to box2dweb than it is to Ammo.js – you can get a list of all of the physics bodies by calling
world.get_bodies() and loop over them. Object positions can be found with a simple call to
get_positions() but rotations must be extracted as matrices and then converted into your graphic engine’s format (Euler rotation, quaternion, etc).
Constraints are almost missing in JigLibJS, as it only includes three of the basics: Point (joining two objects), WorldPoint (fix an object to the a position in the world), and MaxDistance (limit the distance between two objects). While limiting, these three should be enough to achieve most tasks.
1 2 3 4 5 6 7 8 9 10 11 12
- Features: While lacking some of the more obscure and less common features that Ammo.js has, JigLibJS still has enough to cover almost everything you’ll ever want to do. However, I really wish it included more constraints.
- Usability: Having to include each piece of JigLibJS individually and the seemingly random differences in the API take away from how developer-friendly this library could be. At times development can feel a bit clunky and more complex than it needs to be, but overall it is structured well and, once you learn it and set up an environment, easy to use.
- Overall: As the popularity of physics-enabled games on the web continues to grow so will the demand for a powerful-yet-quick physics library. I believe JigLibJS is able to fit most developer’s needs without requiring users to have more powerful computers. Unfortunately the workarounds required to get functioning rotations and the lack of some more basic physics concepts limits the library quite a bit.
- Browser Support: Chrome, Firefox, IE9, Safari, Opera
- Browser Support: Chrome, Firefox, Safari, Opera