Qt + Box2D is easy!

Published Friday February 26th, 2010
20 Comments on Qt + Box2D is easy!
Posted in C++, Graphics View, KDE, Qt

Box2D is an Open Source rigid body 2D physics engine for C++. It’s currently (2.0.1) released under the MIT license, which is quite permissive. Box2D is used by, among other things, Gluon (http://gluon.tuxfamily.org/), which is a game library from KDE in-the-making.

Integrating Box2D into your Qt application is quite easy, and this blog shows you how to get started. First of all:

* Step 1: Download Box2D from Google Code: http://code.google.com/p/box2d/
* Step 2: Build it (I had to insert a few #include <cstring> to get it to build)
* Step 3: Build and try the test bed application: Box2D/Examples/TestBed/
* Step 4: Read the manual: http://www.box2d.org/manual.html
* Step 5: Continue reading this blog to hook up the two frameworks…

The library doesn’t seem to install, so I just compiled it in-source and used it directly.

What I found during my approx 2 hour study today was that Box2D manages a world with bodies, similar to how QGraphicsScene manages items. In short, you create a world object and populate it with elements. Some bodies are static, like the ground, and some dynamic, like a bouncing ball. You can define joints, masses, friction, and other parameters, define a gravity vector, and then start simulating. Box2D doesn’t require a graphics system – any scene graph with elements that you can move and rotate should do fine. Graphics View works quite well. ๐Ÿ™‚ I’ve based this code on the provided “Hello World” example that comes with Box2D.

The world object defines the bounds of the coordinate system and the gravity vector. It feels very similar to QGraphicsScene. The bounds are, according to the docs, not enforced, but I got many run-time aborts when items are outside these bounds so you better make the world large enough to cover all your items.

// Define world, gravity
b2AABB worldAABB;
worldAABB.lowerBound.Set(-200, -100);
worldAABB.upperBound.Set(200, 500);
b2World world = new b2World(worldAABB,
/* gravity = */ b2Vec2(0.0f, -10.0f),
/* doSleep = */ true);

Bodies in Box2D have a position and an angle, and you can assign a shape to it (convex polygon or circular). This feel similar to how QGraphicsItem has a position and a transform. In fact with 4.6 the rotation property fits perfectly with the angle in Box2D (except Box2D uses radians and rotates the opposite direction from QGraphicsItem). This example shows how to create a body, and then assign a rectangular shape:

b2BodyDef bodyDef;
bodyDef.position.Set(0.0f, -10);
b2Body *body = world->CreateBody(&bodyDef);

b2PolygonDef shapeDef;
shapeDef.SetAsBox(100.0f, 10.0f);
body->CreateShape(&shapeDef);

Bodies can either be static or dynamic. Static bodies simply don’t move. By default, bodies are static. To make a body dynamic, you assign a positive mass. The easiest way to do that is to ask Box2D to calculate mass and rotational inertia by looking at the shape of the body. So modifying the above slightly:

shapeDef.density = 1.0f;
shapeDef.friction = 0.5f;
body->CreateShape(&shapeDef);
body->SetMassFromShapes();

That’s really all there is to it. When you’re ready, advance the simulation step by step by calling b2World::Step like this:

world->Step(B2_TIMESTEP, B2_ITERATIONS);

After calling this function, Box2D will have adjusted positions and angles of all bodies. So if you have corresponding items in Graphics View, you can just update their positions and rotations like this:

void adjust()
{
// Update QGraphicsItem's position and rotation from body.
b2Vec2 position = _body->GetPosition();
float32 angle = _body->GetAngle();
setPos(position.x, -position.y);
setRotation(-(angle * 360.0) / (2 * PI));
}

Notice the negative Y (as Graphics View, like the rest of Qt, has a Y component that points downwards), and the negative rotation which is converted to degrees.

That’s really all there is. Create the world, add body elements, assign mass, and start the simulation. Use the angle and position to adjust your QGraphiscItems, and enjoy :-).

The above video shows my first Box2D + Graphics View application in action. You can find the full sources here: qgv-box2dtar.gz. I’ve tried to experiment a bit with how Box2D bindings for Qt could be done. For now I’ll leave it as an experiment.

Do you like this? Share it
Share on LinkedInGoogle+Share on FacebookTweet about this on Twitter

Posted in C++, Graphics View, KDE, Qt

20 comments

Adam Higerd says:

I’ve been using Box2D with QGraphicsView for a long time. It really does work great. I hacked up a little pinball/Peggle-esque game with it last year.

designker says:

Could this be used with QML to provide an easy way to make games?

bunjee says:

Hey Andreas,

I’m currently working integrating a few libraries with Qt to make it a “game factory power house”.

So far I’ve added the Ogre engine.
It’s a smart move because it grants you particles, lights etc… out of the box.

I think Box2D might be the next step (A Network game engine would be sweet too).

I pay attention to licenses, I’m trying to use LGPL or less, Box2D fall into that categorie.

Now I have two questions :
– Could we use this in QtScript using Qt ScriptGenerator (I happen to use this one quite a lot, it speeds up development greatly) ?
– A little off topic but, is there a way to integrate Ogre smartly with QGraphicsScene to make these two fits naturally ?

All in all, It seems obvious that tuned up nicely, Qt might become a strong alternative to flash for making games.

Benjamin Arnaud.

A while ago I did a similar thing with chipmunk and pyqt:

http://www.youtube.com/watch?v=5PuUhiqZTD4

Code here: http://chipscene.googlecode.com

spaceman says:

Are there any plans to integrate (something like) Box2D into the Qt-Framework itself?
QGraphicsView would be a natural candidate to have native physics support as all the basic infrastructure is already present.
It would be really amazing to just add some properties to a QGraphics(Physic)Item like setMass(qfloat m) and have a step() function on a QGraphics(Physic)Scene.

boulabiar says:

Hi,

The example works with very bad performance.
From where comes that problem ? Qt or from Box2d ?

Anyway, Andreas, can you edit the post and move the source link to up, just before the video because I have only see it after at least 1h from reading (didn’t expect links after a video !)

For those who want a modified Box2d lib without messing to add the “#include “, and with Andreas’s example, you can download it from here :
http://boulabiar.net/box2d/Box2Dm.7z

SABROG says:

boulabiar, can’t compile with MinGW/MSYS …

MSYS:
$ make
(cd Contrib/freeglut; make)
make[1]: Entering directory `/c/SABROG/Box2Dm/Contrib/freeglut’
gcc -g -O2 -DTARGET_HOST_UNIX_X11 -DHAVE_FCNTL_H -DHAVE_SYS_IOCTL_H -c -o freeglut_callbacks.o freeglut_callbacks.c
freeglut_callbacks.c:28:25: error: GL/freeglut.h: No such file or directory
In file included from freeglut_callbacks.c:29:
freeglut_internal.h:46:1: warning: “TARGET_HOST_UNIX_X11” redefined
: warning: this is the location of the previous definition

MinGW:
(cd Contrib/freeglut; make)
process_begin: CreateProcess(NULL, (cd Contrib/freeglut; make), …) failed.
make (e=2): โ•ั… ั”ั„ั€ั…ะ„ั‘ย  ัั€ั‰ะ„ัˆ ั”ัŠั€ั‡ั€ััโˆšั‰ ะ‡ั€ั‰ั‹.
mingw32-make: *** [all] Error 2

Few years ago i see Box2D example in dojo project, but he’s missing.

SABROG says:

Andreas, archive name is broken: qgv-box2dtar.gz instead qgv-box2d.tar.gz

boulabiar says:

I have only tested it on Linux,
TARGET_HOST_UNIX_X11

SABROG says:

Andreas, you forgot #include in main.cpp

How i compile box2d with MinGW. Open MSYS and go to Source subdirectory, call make. After compiling open windows console (not MSYS) and go to qgv-box2d project path. Then edit .pro file for qgv-box2d and set your path to box2d header and library. Open main.cpp and add #include .
Run qmake && mingw32-make release && releaseqgv-box2d.exe

This my result: http://img408.imageshack.us/img408/4402/box2d.gif (animated gif ~500Kb)

SABROG says:

I forget what this blog don’t support angle brackets. So you need include in main.cpp

SABROG says:

๐Ÿ™ time.h

My tips for everyone who wants to use Box2D in Qt apps:

1. You should have a look at my CMake patch for Box2D which is at http://code.google.com/p/box2d/issues/detail?id=83 – this makes it possible to `make install` everything and simply use find_package(Box2D) in one’s own application.
2. For a more sophisticated usage example of Box2D, have a look at svn://anonsvn.kde.org/home/kde/trunk/playground/games/kolf2/base

boulabiar says:

How to increase the speed of the simulation ?
it runs very bad in my Computer !

Have you tried other physics engines to work inside QGraphicsView ?
Chipmunk or others ?
http://www.youtube.com/watch?v=_yOeyExtY68

The speed is very bad to be used in any app.

Kevin Kofler says:

I wonder if multiple inheritance or some approximation to it could be used to make objects which are both QGraphicsView items and Box2D objects at the same time and automatically keep coordinates etc. in sync. Of course that would be very much un-MVC-like, but I suspect it’d make things simpler by eliminating redundancy and prevent inconsistencies beween graphics and physics.

Mark Harrison says:

Nifty!

Would you consider doing a similar project with Chipmunk? It’s derived from Box2D, and is currently very popular as it’s been ported to the iphone.

Andreas says:

The performance depends on the complexity of the graphics and which graphics system you are running. This is typical for any graphics app written in Qt. In this example each element is a triangle with an outline, with antialiasing enabled, and it runs at decent speed on anything but X11. If you run the app with “-graphicssystem opengl” or “-graphicssystem raster”, it performs well. Still, you can simplify the graphics by using simple sprites instead.

Thorbjรธrn Lindeijer says:

@designker (and others interested in combining this with QML): I’ve made a start on integrating Box2D in QML by using an extension plugin. The code can be found at http://gitorious.org/qmlarcade (it also has an extension plugin supporting tile maps made with Tiled, a tool I develop in my spare time). It should compile and run fine with the latest qt-4.7.

hp says:

I ppl

I use the CodeBlocks and open “Box2D_v2.0.1Box2D_v2.0.1Box2DBuildCodeBlocksBox2D.workspace”
next I Build and create 3 files:
libBox2D.a
libFreeGLUT.a
libGLUI.a

I put the 3 files in C:Qt2010.02.1mingwlib but when i try use the example, in the
b2World world = new b2World(worldAABB, b2Vec2(0.0f, -10.0f), true);
give-me a error:

:/qt/2010.02.1/mingw/bin/../lib/gcc/mingw32/4.4.0/../../../libbox2d.a(b2World.o): In function `ZNK7b2Joint7GetTypeEv’:

any help ?

tks

hp says:

Can you put all the steps ?

Commenting closed.

Get started today with Qt Download now