Qt + Box2D is easy!
February 26, 2010 by Andreas Aardal Hanssen | Comments
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.
Blog Topics:
Comments
Subscribe to our newsletter
Subscribe Newsletter
Try Qt 6.8 Now!
Download the latest release here: www.qt.io/download.
Qt 6.8 release focuses on technology trends like spatial computing & XR, complex data visualization in 2D & 3D, and ARM-based development for desktop.
We're Hiring
Check out all our open positions here and follow us on Instagram to see what it's like to be #QtPeople.
My tips for everyone who wants to use Box2D in Qt apps:
make install
everything and simply use find_package(Box2D) in one's own application.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/watc...
The speed is very bad to be used in any app.
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.
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.
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.
@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.
I ppl
I use the CodeBlocks and open "Box2Dv2.0.1Box2Dv2.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
Can you put all the steps ?
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.
Could this be used with QML to provide an easy way to make games?
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/watc...
Code here: http://chipscene.googlecode...
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.
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/...
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 -DTARGETHOSTUNIXX11 -DHAVEFCNTLH -DHAVESYSIOCTLH -c -o freeglutcallbacks.o freeglutcallbacks.c
freeglutcallbacks.c:28:25: error: GL/freeglut.h: No such file or directory
In file included from freeglutcallbacks.c:29:
freeglutinternal.h:46:1: warning: "TARGETHOSTUNIXX11" 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.
Andreas, archive name is broken: qgv-box2dtar.gz instead qgv-box2d.tar.gz
I have only tested it on Linux,
TARGETHOSTUNIX_X11
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... (animated gif ~500Kb)
I forget what this blog don't support angle brackets. So you need include in main.cpp
:( time.h