Using Box2D with Pixelwave
From Pixelwave
Contents |
With the addition of PixelKit in v 0.9.1 of Pixelwave, using the Box2D physics engine in your project couldn't be easier. PixelKit provides the complete source package for the Box2D framework along with utilities for rendering and interacting with Box2D with ease
1 A quick overview of Box2D
Box2D is one of the most popular 2D physics engines today. The engine was initially released as a proof-of-concept for Erin Catto's 2006 GDC physics tutorial and has since been developed into the leading open-source physics engine for 2D games. You can learn a lot more on the project's home page.
The original Box2D is written in C++, but has been ported to numerous other languages. Since Pixelwave is built with Objective-C (which supports C/C++ as well) we were able to include the original version of the engine (this makes staying on top of new releases a breeze).
Box2D is licensed under the open source zlib license (the same one used by Pixelwave), which essentially means you can use it however you want.
2 Prerequisites
This tutorial will show you how to quickly start a Box2D project, but it won't attempt to teach you how to use the Box2D framework, as that topic could encompass a manual of its own. In fact, Erin Catto (the author of Box2D) already wrote one: The Box2D manual.
3 Including Box2D in your project
The first step to using Box2D is including it in your project. You could do it the long way: by grabbing the source from the framework's site, adding it to your project, and tweaking compiler settings to make it all work. But as you probably already guessed, we wouldn't have made it sound so laborious if we didn't offer an easier way ;)
3.1 The easy way
To use Box2D all you need to do is include the PixelKit framework in your project. PixelKit, among other things, contains the unmodified Box2D framework and utilities to make working with it simpler. The easiest way to include PixelKit is checking the "Include PixelKit for game developers" box when creating a new Pixelwave project in Xcode:
Once you've done that, including Box2D simply means writing this at the top of your source files:
#include "Box2D.h"
And you can start coding away. The section setting up a Box2D simulation below will step you through what it takes to set up a Box2D world and add a debug rendering layer. But if you're too lazy to code that up yourself, or just want to run a quick experiment, you can use the "Box2D Project" Xcode template. Read on.
3.2 The easier way
Sometimes you just want to start coding cool simulations, without worrying about linking external frameworks, creating a b2World object, or setting up a rendering layer. In those cases you can just use the "Box2D Project" Xcode template:
This template will do the setup steps mentioned above automatically. It will also set up the code to make a basic Box2D simulation that you can start using immediately.
To modify the default scene that the template creates (a ball dropping on the floor) you can edit the createScene method in the {PROJECT NAME}Root class.
- (void) createScene
{
// Build the Box2D world here
}
- Additional utilities
The Xcode includes some utilities to make setting up Box2D simpler. The Box2DListeners.mm file contains an implementation of the Box2D listener interfaces that allow you to respond to:
- A collision between two bodies (b2ContactListener)
- Implicit destruction of fixtures or joints (b2DestructionListener)
- AABB and raycasting queries
After you've set up your project you can also start using the Box2DUtils class. It includes methods for quickly creating Box2D bodies, and common shapes such as a bounding border for the world.
4 Mixing Objective-C and C++
Box2D is written in C++, which is stored in .cpp files. Objective-C code is stored in .m files. Unfortuntaely, Xcode doesn't recognize C++ code in regular .m files by default. To be able to write both Objective-C and C++ code in the same source file it needs to have the .mm extension (instead of the default .m). You can read more about this right here.
5 Setting up a Box2D simulation
This section steps through what you'd need to do to create a basic Box2D simulation once you've set up a PixelKit project. In essence it details how to do manually what the "Box2D Project" Xcode templates does automatically.
5.1 The Simulation World
I know, I know, I said I won't teach you how to use Box2D, but I had to include some code snippets that will show you how to get started:
- Creating a world
The entirety of the simulation in controlled by the b2World class. It's where bodies and joints get added and what's responsible for making them move. Here's a quick code snippet for setting up a Box2D world:
// Define the force of gravity (in meters / second ^ 2) b2Vec2 gravity(0.0f, 9.8f); physicsWorld = new b2World(gravity, true);
- Populating the world
This is the fun part, so we're leaving it up to you. Explaining how Box2D operates is outside the scope of this article, but there are TONS of tutorials out there, you just need to ask.
- Working with Box2D units
The unit system used by Box2D is different from the unit system we use to render objects on the screen. In Pixelwave, a value of 1 for position or size means 1 pixel. In Box2D, a value of 1 means 1 meter. The Box2D manual also talks about this in section 1.7 (units):
Caution: Box2D is tuned for MKS units. Keep the size of moving objects roughly between 0.1 and 10 meters. You'll need to use some scaling system when you render your environment and actors.
So that means a box-like crate that's 100px X 100px on the screen will be represented in Box2D as 100 meters X 100 meters in size (that's about the height of a 30 story building!). Naturally, this huge box won't behave the same way you'd expect a crate to, especially when gravity is set to 9.8 m/s^2 (Earth's gravity).
What you should do then is decide on a scaling factor, representing how many pixels on the screen are equivalent to 1 meter in Box2D. Let's call this value pixelsPerMeter (or PPM). If we were to use a PPM value of 50, our 100 pixels wide crate will now become just 2 meter2 wide, which is much more reasonable.
The "Box2D Project" Xcode template provides a pixels->meters conversion utility you can use (in the Box2DUtils class). It defines a default PPM value of 64.0 and exposes the PixelsToMeters macro which lets you define the size and position of your objects in pixels, and supply Box2D with the corresponding values in meters.
PixelKit's Box2DRenderingLayer also follows this convention and lets you easily set a scaling factor, which it uses to draw the Box2D world to the screen.
- Running the world
To make the simulation run we're required to update it every frame. Here's how we'd do that:
[self addEventListenerOFType:PXEvent_EnterFrame listener:(onFrame)];
//...
- (void)onFrame
{
// How much we time want the simulation to move forward every frame (in seconds).
float timeStep = 1/30.0f;
// How accurately we want Box2D to resolve collisions:
int velocityIterations = 10;
// How accurately we want Box2D to resolve visual intersections:
int positionIterations = 10;
// Move the simulation forward in time
physicsWorld->Step(timeStep, velocityIterations, positionIterations);
}
5.2 Connecting it with Pixelwave
Now that we have a b2World created we want the user to be able to see it and interact with it. That's where Pixelwave comes in:
- Rendering the world
the best way to visualize Box2D is probably drawing it to the screen. You could have Box2D print out all sort of positional information to the console instead, but that's not nearly as fun.
Luckily, PixelKit contains a custom display object that knows how to communicate with Box2D and render its contents: Box2DDebugLayer. Just tell this display object where the world object is and it'll take care of the rest:
PKBox2DDebugLayer *layer = [PKBox2DDebugLayer box2DDebugLayerWithPhysicsWorld:physicsWorld]; layer.scale = pixelsPerMeter; [self addChild:layer];
You may have noticed the word Debug in there. That's because this rendering utility is meant to be used for debugging purposes. We strongly discourage you from using it in a finished project. It's not particularly fast, or pretty, but it's extremely useful when you need to see exactly what Box2D is doing with pixel-perfect accuracy. So don't forget to turn it off when you're done testing ;)
- Interacting with the world
Every game or physics-based application usually creates its own unique way of interacting with its physics engine. Some let the user control gravity by tilting the device, some let the user touch the screen to fling helpless birds at evil pigs, and some try to create an experience that nobody's seen before.
But sometimes you just need to be able to pull on things and see how they react. So, for debugging purposes, the Box2DDebugLayer class lets you do just that with one line of code:
layer.touchPicking = YES;
Now you'll be able to press any physics body and drag it around like it's nobody's business, even with multiple fingers. If you find it hard to grab the smaller objects you can do this:
layer.precisePicking = NO;
6 Conclusion
Hopefully by now you know everything you need in order to start using Box2D with Pixelwave. Now go make some awesome physics-based apps.
- This page was last modified on 12 August 2011, at 05:45.