This is part 2 of an ongoing series that details our team’s journey to creating disasteroids.com for NodeKnockout 2012, a 48 hour coding competition that showcases projects built on node.js. You can find part one here.
When we set out to create Disasteroids, we knew that how we model gravitation would be an integral part of what defines the experience when playing the game. We envisioned insane, well calculated trick shots that looped around the gravitational pull of multiple asteroids. We sat down and started to discuss the specifics of how mass, gravity, and velocity would all be handled and we were quickly faced with the decision of rolling our own simple physics engine or investing the time to familiarize ourselves with an existing open source alternative.
Box2D allows you to setup a “world” of arbitrary size and populate it with any number of objects that they individually refer to as a “body.” Each body has a set of properties such as “restitution” (bounciness), friction, and density. Primed with this knowledge, we created a world and threw up circular bodies as asteroids and rectangles as player and missiles. This was easy enough, but we quickly realized that Box2D is a physics engine and is only meant to simulate a virtual world. It was entirely up to us to translate the data that Box2D provided into a visual scene. How we achieved this will be detailed in a later post, but for now, we will talk about Box2D’s awesome debug draw feature.
http://code.google.com/p/box2dweb/ has a great in browser example of what this looks like. The Box2D documentation made it very clear that this is to be used to debug purposes only, but it proved to be invaluable in quickly testing how our code made bodies interact without having to immediately worry about how to translate Box2D’s simulation into sprites and images on canvas. This allowed for us to independently start work on modeling Disasteroid’s physics even before any of the design assets were finalized and ready for us to use.
“Radial Gravity,” is the term that we learned was used to refer to gravitational simulations that involved planetary bodies in space. It turned out that simulating this kind of environment is not too uncommon and we were able to pull some blog posts and tutorials detailing just how to go about implementing it using Box2D. This was an amazing find for us considering we only had 48 hours. Here’s a post by Emanuele Feronato that saved us tons of time and effort. The tutorial was written in ActionScript 3, but he provided an extensive line by line breakdown of the code, which made porting most of the core concepts effortless.
Box2D doesn’t have a built in way of applying gravity onto an arbitrary object in the simulated world. As a result, we had to custom build this feature by applying a force to all objects towards the asteroids on every tick of the physics simulation. The basic algorithm for applying radial gravity worked as follows:
1. Get the distance of the player/missile to all nearby asteroids.
2. Apply a force on the player/missile towards the asteroids.
3. Make sure the force is proportional to the radius of the asteroid
4. Make sure the force applied is lowered as the object’s distance from the asteroid increases.
That’s it! It sounds complicated, but the implementation was extremely simple.
The main challenge using Box2D for Disasteroids was the fact that it was a multiplayer game where the node.js server would serve as the authoritative source of what was going on in the world. This would mean that the Box2D simulation needed to be run on the node.js server. We threw out the idea of running predictive simulations on the client side solely based on the fact that we only had 48 hours. This posed a few challenges:
Challenge #1: The physics simulation on node.js had to run FAST in order to properly relay the world state to all connected players.
To circumvent this issue, we had to lower the FPS of the game to 30 from 60 and also optimized/rewrote the main loop that processed the Box2D world simulation at least 4 times throughout the span of the 48 hour coding event.
Challenge #2: There was no way for us to use the debug draw class on node.js to get a picture of what was going on. Node.js isn’t a browser and doesn’t have a canvas object that we can easily hook into in realtime.
We knew of projects such as LearnBoost’s node-canvas (https://github.com/LearnBoost/node-canvas), but we didn’t really have to time to look into it and had to come up with quick tests that ensured we were translating the positional data from the node.js server to correct visual representations on the browser. This certainly created some frustrating moments where things were off center, oriented in the wrong direction, or not showing up entirely, but we somehow managed to get through all the issues in the end. There were instances, however, where we weren’t able to pinpoint issues quickly because it was unclear if things were showing up incorrectly as a result of a bug in the physics simulation on node.js or the rendering on the browser.
In the end, Box2D was an awesome choice that made Disasteroids what it is today. We were only able to scratch the surface of what it has to offer. It has already been rolled into popular HTML5 game engines such as Impact.js and Cocos2D and we hope to bring it some more exposure as it definitely helped us save the time and trouble of implementing a physics engine.
Part 3: Making It Feel Real: Math And Fabric.js
If you enjoyed disasteroids.com or this post, please consider throwing us a vote on our team’s page. It requires Facebook authentication to ensure that there isn’t rampant cheating, but the awesome NodeKnockout organizers @visnup and @gerad would never use your information in a malicious way. They’ve been crazy enough to organize this event for the 3rd year now despite the operational headaches of putting together such a massive event.