Skip to content

Commit

Permalink
Made simple Box2D rectangular bodies functional
Browse files Browse the repository at this point in the history
Defined the Body item, which can only be used as a child of a World
item. The standard x, y, width and height properties can be used to
define its position and size, and it will automatically determine its
mass.

The World item has been extended with properties to set the time step,
the number of iterations for each time step and the time between each
frame.
  • Loading branch information
bjorn committed Mar 4, 2010
1 parent a978be8 commit e076007
Show file tree
Hide file tree
Showing 7 changed files with 248 additions and 12 deletions.
4 changes: 0 additions & 4 deletions Box2D/box2d.pri
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,8 @@ HEADERS = \
$$PWD/Source/Common/Fixed.h \
$$PWD/Source/Common/jtypes.h \
$$PWD/Source/Collision/b2Collision.h \
$$PWD/Source/Collision/b2Distance.h \
$$PWD/Source/Collision/Shapes/b2Shape.h \
$$PWD/Source/Collision/Shapes/b2CircleShape.h \
$$PWD/Source/Collision/Shapes/b2PolygonShape.h \
$$PWD/Source/Collision/b2TimeOfImpact.h \
$$PWD/Source/Collision/b2PairManager.h \
$$PWD/Source/Collision/b2CollidePoly.h \
$$PWD/Source/Collision/b2CollideCircle.h \
$$PWD/Source/Collision/b2BroadPhase.h
6 changes: 4 additions & 2 deletions box2d.pro
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ MOC_DIR = .moc
OBJECTS_DIR = .obj

SOURCES += box2dplugin.cpp \
box2dworld.cpp
box2dworld.cpp \
box2dbody.cpp

HEADERS += \
box2dplugin.h \
box2dworld.h
box2dworld.h \
box2dbody.h
89 changes: 89 additions & 0 deletions box2dbody.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Box2D QML plugin
* Copyright (C) 2010 Nokia Corporation
*
* This file is part of the QmlArcade.
*
* QmlArcade is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* QmlArcade is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with QmlArcade. If not, see <http://www.gnu.org/licenses/>.
*/

#include "box2dbody.h"

#include "box2dworld.h"

#include <Box2D.h>
#include <cmath>

static const float scaleRatio = 32.0f; // 32 pixels in one meter

Box2DBody::Box2DBody(QDeclarativeItem *parent) :
QDeclarativeItem(parent),
mBody(0),
mFixed(false)
{
}

Box2DBody::~Box2DBody()
{
if (Box2DWorld *world = qobject_cast<Box2DWorld*>(parent()))
world->unregisterBody(this);
}

void Box2DBody::componentComplete()
{
if (Box2DWorld *world = qobject_cast<Box2DWorld*>(parent()))
world->registerBody(this);
else
qWarning() << "Warning: Body should have World as parent";
}

void Box2DBody::initialize(b2World *world)
{
b2BodyDef bodyDef;
bodyDef.position.Set((x() + width() / 2) / scaleRatio,
-(y() + height() / 2) / scaleRatio);
bodyDef.angle = -(rotation() * (2 * M_PI)) / 360.0;

mBody = world->CreateBody(&bodyDef);

// TODO: Create a shape for each child shape
b2PolygonDef shapeDef;
shapeDef.SetAsBox(width() / 2.0f / scaleRatio,
height() / 2.0f / scaleRatio);
shapeDef.density = 1.0f; // TODO: Make a property for it in Box2DShape
shapeDef.friction = 0.3f; // TODO: Make a property for it in Box2DShape
shapeDef.restitution = 0.5f;
mBody->CreateShape(&shapeDef);

if (!mFixed)
mBody->SetMassFromShapes(); // TODO: Make a property for it in Box2DBody
}

/**
* Synchronizes the state of this body with the internal Box2D state.
*/
void Box2DBody::synchronize()
{
Q_ASSERT(mBody);
const b2Vec2 position = mBody->GetPosition();
const float32 angle = mBody->GetAngle();
setPos(position.x * scaleRatio - width() / 2,
-position.y * scaleRatio - height() / 2);
setRotation(-(angle * 360.0) / (2 * M_PI));
}

void Box2DBody::cleanup(b2World *world)
{
world->DestroyBody(mBody);
}
60 changes: 60 additions & 0 deletions box2dbody.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Box2D QML plugin
* Copyright (C) 2010 Nokia Corporation
*
* This file is part of the QmlArcade.
*
* QmlArcade is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* QmlArcade is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with QmlArcade. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef BOX2DBODY_H
#define BOX2DBODY_H

#include <QDeclarativeItem>

class Box2DWorld;

class b2Body;
class b2World;

/**
* The Box2D body, build up from a list of shapes.
*/
class Box2DBody : public QDeclarativeItem
{
Q_OBJECT
Q_PROPERTY(bool fixed READ fixed WRITE setFixed)

public:
explicit Box2DBody(QDeclarativeItem *parent = 0);
~Box2DBody();

bool fixed() const
{ return mFixed; }

void setFixed(bool fixed)
{ mFixed = fixed; }

void componentComplete();

void initialize(b2World *world);
void synchronize();
void cleanup(b2World *world);

private:
bool mFixed;
b2Body *mBody;
};

#endif // BOX2DBODY_H
2 changes: 2 additions & 0 deletions box2dplugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "box2dplugin.h"

#include "box2dworld.h"
#include "box2dbody.h"

Box2DPlugin::Box2DPlugin(QObject *parent) :
QDeclarativeExtensionPlugin(parent)
Expand All @@ -30,6 +31,7 @@ Box2DPlugin::Box2DPlugin(QObject *parent) :
void Box2DPlugin::registerTypes(const char *uri)
{
qmlRegisterType<Box2DWorld>(uri, 2, 0, "World");
qmlRegisterType<Box2DBody>(uri, 2, 0, "Body");
}

Q_EXPORT_PLUGIN2(Box2DPlugin, Box2DPlugin)
54 changes: 51 additions & 3 deletions box2dworld.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,31 @@

#include "box2dworld.h"

#include "box2dbody.h"

#include <QTimerEvent>

#include <Box2D.h>

Box2DWorld::Box2DWorld(QDeclarativeItem *parent) :
QDeclarativeItem(parent)
QDeclarativeItem(parent),
mWorld(0),
mTimeStep(1.0f / 60.0f),
mIterations(10),
mFrameTime(1000 / 60),
mTimerId(0)
{
}

Box2DWorld::~Box2DWorld()
{
delete mWorld;
}

void Box2DWorld::componentComplete()
{
// Define the world boundaries and its gravity
// TODO: Make properties for setting the boundaries
b2AABB bounds;
bounds.lowerBound.Set(-100.0f, -100.0f);
bounds.upperBound.Set(100.0f, 100.0f);
Expand All @@ -34,9 +53,38 @@ Box2DWorld::Box2DWorld(QDeclarativeItem *parent) :
bool doSleep = true;

mWorld = new b2World(bounds, gravity, doSleep);

foreach (Box2DBody *body, mBodies)
body->initialize(mWorld);

mTimerId = startTimer(mFrameTime);
}

Box2DWorld::~Box2DWorld()
/**
* Registers a Box2D body with this world. When the world component is
* complete, it will initialize the body.
*/
void Box2DWorld::registerBody(Box2DBody *body)
{
delete mWorld;
mBodies.append(body);
}

/**
* Unregisters a Box2D body from this world. It will be asked to clean up after
* itself.
*/
void Box2DWorld::unregisterBody(Box2DBody *body)
{
mBodies.removeOne(body);
body->cleanup(mWorld);
}

void Box2DWorld::timerEvent(QTimerEvent *event)
{
if (event->timerId() == mTimerId) {
mWorld->Step(mTimeStep, mIterations);
foreach (Box2DBody *body, mBodies)
body->synchronize();
}
QDeclarativeItem::timerEvent(event);
}
45 changes: 42 additions & 3 deletions box2dworld.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@
* along with QmlArcade. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef BOX2DENGINE_H
#define BOX2DENGINE_H
#ifndef BOX2DWORLD_H
#define BOX2DWORLD_H

#include <QDeclarativeItem>
#include <QList>

class Box2DBody;

class b2World;

Expand All @@ -31,15 +34,51 @@ class b2World;
class Box2DWorld : public QDeclarativeItem
{
Q_OBJECT
Q_PROPERTY(float timeStep READ timeStep WRITE setTimeStep)
Q_PROPERTY(int iterations READ iterations WRITE setIterations)
Q_PROPERTY(int frameTime READ frameTime WRITE setFrameTime)

public:
explicit Box2DWorld(QDeclarativeItem *parent = 0);
~Box2DWorld();

/**
* The amount of time to step through each frame in seconds.
* By default it is 1 / 60.
*/
float timeStep() const { return mTimeStep; }
void setTimeStep(float timeStep) { mTimeStep = timeStep; }

/**
* The number of iterations used to process one step. 10 by default.
*/
int iterations() const { return mIterations; }
void setIterations(int iterations) { mIterations = iterations; }

/**
* The amount of time each frame takes in milliseconds.
* By default it is 1000 / 60.
*/
int frameTime() const { return mFrameTime; }
void setFrameTime(int frameTime) { mFrameTime = frameTime; }

void componentComplete();

void registerBody(Box2DBody *body);
void unregisterBody(Box2DBody *body);

protected:
void timerEvent(QTimerEvent *);

private:
b2World *mWorld;
float mTimeStep;
int mIterations;
int mFrameTime;
int mTimerId;
QList<Box2DBody*> mBodies;
};

QML_DECLARE_TYPE(Box2DWorld)

#endif // BOX2DENGINE_H
#endif // BOX2DWORLD_H

0 comments on commit e076007

Please sign in to comment.