Use Box2D's callbacks for destruction of physics objects and wait until the end of the timestep before destroying them.

Merge of box2d-id2 from love-experiments
This commit is contained in:
Bart van Strien
2012-01-08 13:16:50 +01:00
parent 9629e5b233
commit c1f68e058d
34 changed files with 340 additions and 118 deletions
+26 -7
View File
@@ -41,6 +41,8 @@ namespace box2d
b2BodyDef def; b2BodyDef def;
def.position = Physics::scaleDown(p); def.position = Physics::scaleDown(p);
body = world->world->CreateBody(&def); body = world->world->CreateBody(&def);
// Box2D body holds a reference to the love Body.
this->retain();
this->setType(type); this->setType(type);
Memoizer::add(body, this); Memoizer::add(body, this);
} }
@@ -50,13 +52,13 @@ namespace box2d
{ {
world = (World *)Memoizer::find(b->GetWorld()); world = (World *)Memoizer::find(b->GetWorld());
world->retain(); world->retain();
// Box2D body holds a reference to the love Body.
this->retain();
Memoizer::add(body, this); Memoizer::add(body, this);
} }
Body::~Body() Body::~Body()
{ {
Memoizer::remove(body);
world->world->DestroyBody(body);
world->release(); world->release();
body = 0; body = 0;
} }
@@ -148,7 +150,8 @@ namespace box2d
Body::Type Body::getType() const Body::Type Body::getType() const
{ {
switch (body->GetType()) { switch (body->GetType())
{
case b2_staticBody: case b2_staticBody:
return BODY_STATIC; return BODY_STATIC;
break; break;
@@ -266,7 +269,8 @@ namespace box2d
void Body::setType(Body::Type type) void Body::setType(Body::Type type)
{ {
switch (type) { switch (type)
{
case Body::BODY_STATIC: case Body::BODY_STATIC:
body->SetType(b2_staticBody); body->SetType(b2_staticBody);
break; break;
@@ -403,9 +407,11 @@ namespace box2d
b2Fixture * f = body->GetFixtureList(); b2Fixture * f = body->GetFixtureList();
int i = 1; int i = 1;
do { do {
if (!f) break; if (!f)
break;
Fixture * fixture = (Fixture *)Memoizer::find(f); Fixture * fixture = (Fixture *)Memoizer::find(f);
if (!fixture) throw love::Exception("A fixture has escaped Memoizer!"); if (!fixture)
throw love::Exception("A fixture has escaped Memoizer!");
fixture->retain(); fixture->retain();
luax_newtype(L, "Fixture", PHYSICS_FIXTURE_T, (void*)fixture); luax_newtype(L, "Fixture", PHYSICS_FIXTURE_T, (void*)fixture);
lua_rawseti(L, -2, i); lua_rawseti(L, -2, i);
@@ -431,7 +437,20 @@ namespace box2d
void Body::destroy() void Body::destroy()
{ {
world->destroyBody(this); if (world->world->IsLocked())
{
// Called during time step. Save reference for destruction afterwards.
this->retain();
world->destructBodies.push_back(this);
return;
}
world->world->DestroyBody(body);
Memoizer::remove(body);
body = NULL;
// Box2D body destroyed. Release its reference to the love Body.
this->release();
} }
} // box2d } // box2d
+2 -1
View File
@@ -56,6 +56,7 @@ namespace box2d
friend class CircleShape; friend class CircleShape;
friend class PolygonShape; friend class PolygonShape;
friend class Shape; friend class Shape;
friend class Fixture;
private: private:
@@ -386,7 +387,7 @@ namespace box2d
int getFixtureList(lua_State * L) const; int getFixtureList(lua_State * L) const;
/** /**
* Mark the body for destruction * Destroy this body.
**/ **/
void destroy(); void destroy();
@@ -42,8 +42,6 @@ namespace box2d
DistanceJoint::~DistanceJoint() DistanceJoint::~DistanceJoint()
{ {
destroyJoint(joint);
joint = 0;
} }
void DistanceJoint::setLength(float length) void DistanceJoint::setLength(float length)
+33 -11
View File
@@ -39,7 +39,6 @@ namespace box2d
Fixture::Fixture(Body * body, Shape * shape, float density) Fixture::Fixture(Body * body, Shape * shape, float density)
: body(body), fixture(NULL) : body(body), fixture(NULL)
{ {
body->retain();
data = new fixtureudata(); data = new fixtureudata();
data->ref = 0; data->ref = 0;
b2FixtureDef def; b2FixtureDef def;
@@ -47,6 +46,7 @@ namespace box2d
def.userData = (void *)data; def.userData = (void *)data;
def.density = density; def.density = density;
fixture = body->body->CreateFixture(&def); fixture = body->body->CreateFixture(&def);
this->retain();
Memoizer::add(fixture, this); Memoizer::add(fixture, this);
} }
@@ -55,8 +55,9 @@ namespace box2d
{ {
data = (fixtureudata *)f->GetUserData(); data = (fixtureudata *)f->GetUserData();
body = (Body *)Memoizer::find(f->GetBody()); body = (Body *)Memoizer::find(f->GetBody());
if (!body) body = new Body(f->GetBody()); if (!body)
else body->retain(); body = new Body(f->GetBody());
this->retain();
Memoizer::add(fixture, this); Memoizer::add(fixture, this);
} }
@@ -66,13 +67,9 @@ namespace box2d
delete data->ref; delete data->ref;
delete data; delete data;
data = 0; data = NULL;
if (fixture) fixture = NULL;
body->body->DestroyFixture(fixture);
fixture = 0;
body->release();
} }
Shape::Type Fixture::getType() const Shape::Type Fixture::getType() const
@@ -127,12 +124,19 @@ namespace box2d
Shape * Fixture::getShape() const Shape * Fixture::getShape() const
{ {
if (!fixture->GetShape()) return NULL; if (!fixture->GetShape())
return NULL;
Shape * s = (Shape *)Memoizer::find(fixture->GetShape()); Shape * s = (Shape *)Memoizer::find(fixture->GetShape());
if (!s) s = new Shape(fixture->GetShape()); if (!s)
s = new Shape(fixture->GetShape());
return s; return s;
} }
bool Fixture::isValid() const
{
return fixture != 0;
}
void Fixture::setFilterData(int * v) void Fixture::setFilterData(int * v)
{ {
b2Filter f; b2Filter f;
@@ -300,6 +304,24 @@ namespace box2d
return 4; return 4;
} }
void Fixture::destroy(bool implicit)
{
if (body->world->world->IsLocked())
{
// Called during time step. Save reference for destruction afterwards.
this->retain();
body->world->destructFixtures.push_back(this);
return;
}
if (!implicit && fixture != 0)
body->body->DestroyFixture(fixture);
Memoizer::remove(fixture);
fixture = NULL;
// Box2D fixture destroyed. Release its reference to the love Fixture.
this->release();
}
} // box2d } // box2d
} // physics } // physics
+11 -1
View File
@@ -62,8 +62,8 @@ namespace box2d
protected: protected:
Body * body; Body * body;
b2Fixture * fixture;
fixtureudata * data; fixtureudata * data;
b2Fixture * fixture;
public: public:
@@ -90,6 +90,11 @@ namespace box2d
**/ **/
Shape * getShape() const; Shape * getShape() const;
/**
* Returns true if the fixture is active in a Box2D world.
**/
bool isValid() const;
/** /**
* Checks whether this Fixture acts as a sensor. * Checks whether this Fixture acts as a sensor.
* @return True if sensor, false otherwise. * @return True if sensor, false otherwise.
@@ -206,6 +211,11 @@ namespace box2d
* This operation may be expensive. * This operation may be expensive.
**/ **/
int getMassData(lua_State * L) const; int getMassData(lua_State * L) const;
/**
* Destroys this fixture.
**/
void destroy(bool implicit = false);
}; };
} // box2d } // box2d
@@ -45,8 +45,6 @@ namespace box2d
FrictionJoint::~FrictionJoint() FrictionJoint::~FrictionJoint()
{ {
destroyJoint(joint);
joint = 0;
} }
void FrictionJoint::setMaxForce(float force) void FrictionJoint::setMaxForce(float force)
-2
View File
@@ -46,8 +46,6 @@ namespace box2d
GearJoint::~GearJoint() GearJoint::~GearJoint()
{ {
destroyJoint(joint);
joint = 0;
} }
void GearJoint::setRatio(float ratio) void GearJoint::setRatio(float ratio)
+26 -11
View File
@@ -23,11 +23,15 @@
// STD // STD
#include <bitset> #include <bitset>
// LOVE
#include <common/Memoizer.h>
// Module // Module
#include "Body.h" #include "Body.h"
#include "World.h" #include "World.h"
#include "Physics.h" #include "Physics.h"
namespace love namespace love
{ {
namespace physics namespace physics
@@ -37,24 +41,15 @@ namespace box2d
Joint::Joint(Body * body1) Joint::Joint(Body * body1)
: body1(body1), body2(0), world(body1->world) : body1(body1), body2(0), world(body1->world)
{ {
body1->retain();
} }
Joint::Joint(Body * body1, Body * body2) Joint::Joint(Body * body1, Body * body2)
: body1(body1), body2(body2), world(body1->world) : body1(body1), body2(body2), world(body1->world)
{ {
body1->retain();
body2->retain();
} }
Joint::~Joint() Joint::~Joint()
{ {
if (body1 != 0)
body1->release();
if (body2 != 0)
body2->release();
joint = 0;
} }
Joint::Type Joint::getType() const Joint::Type Joint::getType() const
@@ -86,6 +81,11 @@ namespace box2d
} }
} }
bool Joint::isValid() const
{
return joint != 0;
}
int Joint::getAnchors(lua_State * L) int Joint::getAnchors(lua_State * L)
{ {
lua_pushnumber(L, Physics::scaleUp(joint->GetAnchorA().x)); lua_pushnumber(L, Physics::scaleUp(joint->GetAnchorA().x));
@@ -112,13 +112,28 @@ namespace box2d
b2Joint * Joint::createJoint(b2JointDef * def) b2Joint * Joint::createJoint(b2JointDef * def)
{ {
joint = world->world->CreateJoint(def); joint = world->world->CreateJoint(def);
Memoizer::add(joint, this);
// Box2D joint has a reference to this love Joint.
this->retain();
return joint; return joint;
} }
void Joint::destroyJoint(b2Joint * joint) void Joint::destroyJoint(bool implicit)
{ {
if (joint != NULL) if (world->world->IsLocked())
{
// Called during time step. Save reference for destruction afterwards.
this->retain();
world->destructJoints.push_back(this);
return;
}
if (!implicit && joint != 0)
world->world->DestroyJoint(joint); world->world->DestroyJoint(joint);
Memoizer::remove(joint);
joint = NULL;
// Release the reference of the Box2D joint.
this->release();
} }
bool Joint::isActive() const bool Joint::isActive() const
+15 -7
View File
@@ -78,6 +78,12 @@ namespace box2d
virtual ~Joint(); virtual ~Joint();
/**
* Returns true if the joint is active in a Box2D world.
**/
bool isValid() const;
/** /**
* Gets the type of joint. * Gets the type of joint.
**/ **/
@@ -103,25 +109,27 @@ namespace box2d
bool getCollideConnected() const; bool getCollideConnected() const;
protected:
/** /**
* Joints require pointers to a Box2D joint objects at * Joints require pointers to a Box2D joint objects at
* different polymorphic levels, which is why these function * different polymorphic levels, which is why these function
* were created. * were created.
**/ **/
/**
* Destroys the joint. This function was created just to
* get some cinsistency.
**/
void destroyJoint(bool implicit = false);
protected:
/** /**
* Creates a Joint, and ensures that the parent class * Creates a Joint, and ensures that the parent class
* gets a copy of the pointer. * gets a copy of the pointer.
**/ **/
b2Joint * createJoint(b2JointDef * def); b2Joint * createJoint(b2JointDef * def);
/**
* Destroys the joint. This function was created just to
* get some cinsistency.
**/
void destroyJoint(b2Joint * joint);
}; };
} // box2d } // box2d
-2
View File
@@ -45,8 +45,6 @@ namespace box2d
MouseJoint::~MouseJoint() MouseJoint::~MouseJoint()
{ {
destroyJoint(joint);
joint = 0;
} }
void MouseJoint::setTarget(float x, float y) void MouseJoint::setTarget(float x, float y)
@@ -47,8 +47,6 @@ namespace box2d
PrismaticJoint::~PrismaticJoint() PrismaticJoint::~PrismaticJoint()
{ {
destroyJoint(joint);
joint = 0;
} }
float PrismaticJoint::getJointTranslation() const float PrismaticJoint::getJointTranslation() const
@@ -44,8 +44,6 @@ namespace box2d
PulleyJoint::~PulleyJoint() PulleyJoint::~PulleyJoint()
{ {
destroyJoint(joint);
joint = 0;
} }
int PulleyJoint::getGroundAnchors(lua_State * L) int PulleyJoint::getGroundAnchors(lua_State * L)
@@ -44,8 +44,6 @@ namespace box2d
RevoluteJoint::~RevoluteJoint() RevoluteJoint::~RevoluteJoint()
{ {
destroyJoint(joint);
joint = 0;
} }
float RevoluteJoint::getJointAngle() const float RevoluteJoint::getJointAngle() const
-2
View File
@@ -46,8 +46,6 @@ namespace box2d
RopeJoint::~RopeJoint() RopeJoint::~RopeJoint()
{ {
destroyJoint(joint);
joint = 0;
} }
float RopeJoint::getMaxLength() const float RopeJoint::getMaxLength() const
-2
View File
@@ -45,8 +45,6 @@ namespace box2d
WeldJoint::~WeldJoint() WeldJoint::~WeldJoint()
{ {
destroyJoint(joint);
joint = 0;
} }
void WeldJoint::setFrequency(float hz) void WeldJoint::setFrequency(float hz)
-2
View File
@@ -44,8 +44,6 @@ namespace box2d
WheelJoint::~WheelJoint() WheelJoint::~WheelJoint()
{ {
destroyJoint(joint);
joint = 0;
} }
float WheelJoint::getJointTranslation() const float WheelJoint::getJointTranslation() const
+108 -24
View File
@@ -79,7 +79,7 @@ namespace box2d
Contact * c = new Contact(contact); Contact * c = new Contact(contact);
luax_newtype(L, "Contact", (PHYSICS_CONTACT_T), (void*)c, true); luax_newtype(L, "Contact", (PHYSICS_CONTACT_T), (void*)c);
int args = 3; int args = 3;
if (impulse) if (impulse)
@@ -97,7 +97,7 @@ namespace box2d
} }
World::ContactFilter::ContactFilter() World::ContactFilter::ContactFilter()
: ref(0) : ref(0)
{ {
} }
@@ -122,7 +122,7 @@ namespace box2d
} }
World::QueryCallback::QueryCallback() World::QueryCallback::QueryCallback()
: ref(0) : ref(0)
{ {
} }
@@ -139,7 +139,8 @@ namespace box2d
lua_State * L = ref->getL(); lua_State * L = ref->getL();
ref->push(); ref->push();
Fixture * f = (Fixture *)Memoizer::find(fixture); Fixture * f = (Fixture *)Memoizer::find(fixture);
if (!f) throw love::Exception("A fixture has escaped Memoizer!"); if (!f)
throw love::Exception("A fixture has escaped Memoizer!");
f->retain(); f->retain();
luax_newtype(L, "Fixture", PHYSICS_FIXTURE_T, (void*)f); luax_newtype(L, "Fixture", PHYSICS_FIXTURE_T, (void*)f);
lua_call(L, 1, 1); lua_call(L, 1, 1);
@@ -166,7 +167,8 @@ namespace box2d
lua_State * L = ref->getL(); lua_State * L = ref->getL();
ref->push(); ref->push();
Fixture * f = (Fixture *)Memoizer::find(fixture); Fixture * f = (Fixture *)Memoizer::find(fixture);
if (!f) throw love::Exception("A fixture has escaped Memoizer!"); if (!f)
throw love::Exception("A fixture has escaped Memoizer!");
f->retain(); f->retain();
luax_newtype(L, "Fixture", PHYSICS_FIXTURE_T, (void*)f); luax_newtype(L, "Fixture", PHYSICS_FIXTURE_T, (void*)f);
b2Vec2 scaledPoint = Physics::scaleUp(point); b2Vec2 scaledPoint = Physics::scaleUp(point);
@@ -182,23 +184,42 @@ namespace box2d
return 0; return 0;
} }
void World::SayGoodbye(b2Fixture* fixture)
{
Fixture * f = (Fixture *)Memoizer::find(fixture);
// Hint implicit destruction with true.
if (f) f->destroy(true);
}
void World::SayGoodbye(b2Joint* joint)
{
Joint * j = (Joint *)Memoizer::find(joint);
// Hint implicit destruction with true.
if (j) j->destroyJoint(true);
}
World::World() World::World()
: world(NULL) : world(NULL), destructWorld(false)
{ {
world = new b2World(b2Vec2(0,0)); world = new b2World(b2Vec2(0,0));
this->retain(); // The Box2D world holds a reference to this World.
world->SetAllowSleeping(true); world->SetAllowSleeping(true);
world->SetContactListener(this); world->SetContactListener(this);
world->SetDestructionListener(this);
b2BodyDef def; b2BodyDef def;
groundBody = world->CreateBody(&def); groundBody = world->CreateBody(&def);
Memoizer::add(world, this); Memoizer::add(world, this);
} }
World::World(b2Vec2 gravity, bool sleep) World::World(b2Vec2 gravity, bool sleep)
: world(NULL) : world(NULL), destructWorld(false)
{ {
world = new b2World(Physics::scaleDown(gravity)); world = new b2World(Physics::scaleDown(gravity));
// The Box2D world holds a reference to this World.
this->retain();
world->SetAllowSleeping(sleep); world->SetAllowSleeping(sleep);
world->SetContactListener(this); world->SetContactListener(this);
world->SetDestructionListener(this);
b2BodyDef def; b2BodyDef def;
groundBody = world->CreateBody(&def); groundBody = world->CreateBody(&def);
Memoizer::add(world, this); Memoizer::add(world, this);
@@ -206,22 +227,43 @@ namespace box2d
World::~World() World::~World()
{ {
world->DestroyBody(groundBody);
Memoizer::remove(world);
delete world;
} }
void World::update(float dt) void World::update(float dt)
{ {
world->Step(dt, 8, 6); world->Step(dt, 8, 6);
// Really destroy all marked bodies. // Destroy all objects marked during the time step.
if (destructWorld)
{
destroy();
return;
}
for (std::vector<Body*>::iterator i = destructBodies.begin(); i < destructBodies.end(); i++) for (std::vector<Body*>::iterator i = destructBodies.begin(); i < destructBodies.end(); i++)
{ {
Body * b = *i; Body * b = *i;
if (b->body != 0) b->destroy();
// Release for reference in vector.
b->release(); b->release();
} }
for (std::vector<Fixture*>::iterator i = destructFixtures.begin(); i < destructFixtures.end(); i++)
{
Fixture * f = *i;
if (f->isValid()) f->destroy();
// Release for reference in vector.
f->release();
}
for (std::vector<Joint*>::iterator i = destructJoints.begin(); i < destructJoints.end(); i++)
{
Joint * j = *i;
if (j->isValid()) j->destroyJoint();
// Release for reference in vector.
j->release();
}
destructBodies.clear(); destructBodies.clear();
destructFixtures.clear();
destructJoints.clear();
} }
void World::BeginContact(b2Contact* contact) void World::BeginContact(b2Contact* contact)
@@ -249,14 +291,21 @@ namespace box2d
{ {
// Fixtures should be memoized, if we created them // Fixtures should be memoized, if we created them
Fixture * a = (Fixture *)Memoizer::find(fixtureA); Fixture * a = (Fixture *)Memoizer::find(fixtureA);
if (!a) throw love::Exception("A fixture has escaped Memoizer!"); if (!a)
throw love::Exception("A fixture has escaped Memoizer!");
a->retain(); a->retain();
Fixture * b = (Fixture *)Memoizer::find(fixtureB); Fixture * b = (Fixture *)Memoizer::find(fixtureB);
if (!b) throw love::Exception("A fixture has escaped Memoizer!"); if (!b)
throw love::Exception("A fixture has escaped Memoizer!");
b->retain(); b->retain();
return filter.process(a, b); return filter.process(a, b);
} }
bool World::isValid() const
{
return world != 0;
}
int World::setCallbacks(lua_State * L) int World::setCallbacks(lua_State * L)
{ {
int n = lua_gettop(L); int n = lua_gettop(L);
@@ -265,16 +314,20 @@ namespace box2d
switch(n) switch(n)
{ {
case 4: case 4:
if (postsolve.ref) delete postsolve.ref; if (postsolve.ref)
delete postsolve.ref;
postsolve.ref = luax_refif(L, LUA_TFUNCTION); postsolve.ref = luax_refif(L, LUA_TFUNCTION);
case 3: case 3:
if (presolve.ref) delete presolve.ref; if (presolve.ref)
delete presolve.ref;
presolve.ref = luax_refif(L, LUA_TFUNCTION); presolve.ref = luax_refif(L, LUA_TFUNCTION);
case 2: case 2:
if (end.ref) delete end.ref; if (end.ref)
delete end.ref;
end.ref = luax_refif(L, LUA_TFUNCTION); end.ref = luax_refif(L, LUA_TFUNCTION);
case 1: case 1:
if (begin.ref) delete begin.ref; if (begin.ref)
delete begin.ref;
begin.ref = luax_refif(L, LUA_TFUNCTION); begin.ref = luax_refif(L, LUA_TFUNCTION);
} }
@@ -293,7 +346,8 @@ namespace box2d
int World::setContactFilter(lua_State * L) int World::setContactFilter(lua_State * L)
{ {
luax_assert_argc(L, 1); luax_assert_argc(L, 1);
if (filter.ref) delete filter.ref; if (filter.ref)
delete filter.ref;
filter.ref = luax_refif(L, LUA_TFUNCTION); filter.ref = luax_refif(L, LUA_TFUNCTION);
return 0; return 0;
} }
@@ -353,10 +407,13 @@ namespace box2d
b2Body * b = world->GetBodyList(); b2Body * b = world->GetBodyList();
int i = 1; int i = 1;
do { do {
if (!b) break; if (!b)
if (b == groundBody) continue; break;
if (b == groundBody)
continue;
Body * body = (Body *)Memoizer::find(b); Body * body = (Body *)Memoizer::find(b);
if (!body) throw love::Exception("A body has escaped Memoizer!"); if (!body)
throw love::Exception("A body has escaped Memoizer!");
body->retain(); body->retain();
luax_newtype(L, "Body", PHYSICS_BODY_T, (void*)body); luax_newtype(L, "Body", PHYSICS_BODY_T, (void*)body);
lua_rawseti(L, -2, i); lua_rawseti(L, -2, i);
@@ -429,15 +486,42 @@ namespace box2d
float y2 = (float)luaL_checknumber(L, 4); float y2 = (float)luaL_checknumber(L, 4);
b2Vec2 v1 = Physics::scaleDown(b2Vec2(x1, y1)); b2Vec2 v1 = Physics::scaleDown(b2Vec2(x1, y1));
b2Vec2 v2 = Physics::scaleDown(b2Vec2(x2, y2)); b2Vec2 v2 = Physics::scaleDown(b2Vec2(x2, y2));
if (raycast.ref) delete raycast.ref; if (raycast.ref)
delete raycast.ref;
raycast.ref = luax_refif(L, LUA_TFUNCTION); raycast.ref = luax_refif(L, LUA_TFUNCTION);
world->RayCast(&raycast, v1, v2); world->RayCast(&raycast, v1, v2);
return 0; return 0;
} }
void World::destroyBody(Body * b) void World::destroy()
{ {
destructBodies.push_back(b); if (world->IsLocked())
{
destructWorld = true;
return;
}
// Cleaning up the world.
b2Body * b = world->GetBodyList();
while (b)
{
b2Body * t = b;
b = b->GetNext();
if (t == groundBody)
continue;
Body * body = (Body *)Memoizer::find(t);
if (!body)
throw love::Exception("A body has escaped Memoizer!");
body->destroy();
}
world->DestroyBody(groundBody);
Memoizer::remove(world);
delete world;
world = 0;
// Box2D world destroyed. Release its reference.
this->release();
} }
} // box2d } // box2d
+17 -4
View File
@@ -42,6 +42,7 @@ namespace box2d
class Contact; class Contact;
class Body; class Body;
class Fixture; class Fixture;
class Joint;
/** /**
* The World is the "God" container class, * The World is the "God" container class,
@@ -54,13 +55,14 @@ namespace box2d
* The world also controls global parameters, like * The world also controls global parameters, like
* gravity. * gravity.
**/ **/
class World : public Object, public b2ContactListener, public b2ContactFilter class World : public Object, public b2ContactListener, public b2ContactFilter, public b2DestructionListener
{ {
// Friends. // Friends.
friend class Joint; friend class Joint;
friend class DistanceJoint; friend class DistanceJoint;
friend class MouseJoint; friend class MouseJoint;
friend class Body; friend class Body;
friend class Fixture;
public: public:
@@ -110,6 +112,9 @@ namespace box2d
// The list of to be destructed bodies. // The list of to be destructed bodies.
std::vector<Body*> destructBodies; std::vector<Body*> destructBodies;
std::vector<Fixture*> destructFixtures;
std::vector<Joint*> destructJoints;
bool destructWorld;
// Contact callbacks. // Contact callbacks.
ContactCallback begin, end, presolve, postsolve; ContactCallback begin, end, presolve, postsolve;
@@ -152,6 +157,15 @@ namespace box2d
// From b2ContactFilter // From b2ContactFilter
bool ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB); bool ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB);
// From b2DestructionListener
void SayGoodbye(b2Fixture* fixture);
void SayGoodbye(b2Joint* joint);
/**
* Returns true if the Box2D world is alive.
**/
bool isValid() const;
/** /**
* Receives up to four Lua functions as arguments. Each function is * Receives up to four Lua functions as arguments. Each function is
* collision callback for the four events (in order): begin, end, * collision callback for the four events (in order): begin, end,
@@ -261,10 +275,9 @@ namespace box2d
int rayCast(lua_State * L); int rayCast(lua_State * L);
/** /**
* Mark a body for destruction. * Destroy this world.
* To be called from Body
**/ **/
void destroyBody(Body * b); void destroy();
}; };
+13 -7
View File
@@ -28,7 +28,10 @@ namespace box2d
{ {
Body * luax_checkbody(lua_State * L, int idx) Body * luax_checkbody(lua_State * L, int idx)
{ {
return luax_checktype<Body>(L, idx, "Body", PHYSICS_BODY_T); Body * b = luax_checktype<Body>(L, idx, "Body", PHYSICS_BODY_T);
if (b->body == 0)
luaL_error(L, "Attempt to use destroyed body.");
return b;
} }
int w_Body_getX(lua_State * L) int w_Body_getX(lua_State * L)
@@ -509,12 +512,15 @@ namespace box2d
int w_Body_destroy(lua_State * L) int w_Body_destroy(lua_State * L)
{ {
Proxy * p = (Proxy *)lua_touserdata(L, 1); Body * t = luax_checkbody(L, 1);
p->own = false; try
{
Body * t = (Body *)p->data; t->destroy();
t->destroy(); }
catch (love::Exception & e)
{
luaL_error(L, "%s", e.what());
}
return 0; return 0;
} }
@@ -28,7 +28,10 @@ namespace box2d
{ {
DistanceJoint * luax_checkdistancejoint(lua_State * L, int idx) DistanceJoint * luax_checkdistancejoint(lua_State * L, int idx)
{ {
return luax_checktype<DistanceJoint>(L, idx, "DistanceJoint", PHYSICS_DISTANCE_JOINT_T); DistanceJoint * j = luax_checktype<DistanceJoint>(L, idx, "DistanceJoint", PHYSICS_DISTANCE_JOINT_T);
if (!j->isValid())
luaL_error(L, "Attempt to use destroyed joint.");
return j;
} }
int w_DistanceJoint_setLength(lua_State * L) int w_DistanceJoint_setLength(lua_State * L)
+13 -6
View File
@@ -29,7 +29,10 @@ namespace box2d
{ {
Fixture * luax_checkfixture(lua_State * L, int idx) Fixture * luax_checkfixture(lua_State * L, int idx)
{ {
return luax_checktype<Fixture>(L, idx, "Fixture", PHYSICS_FIXTURE_T); Fixture * f = luax_checktype<Fixture>(L, idx, "Fixture", PHYSICS_FIXTURE_T);
if (!f->isValid())
luaL_error(L, "Attempt to use destroyed fixture.");
return f;
} }
int w_Fixture_getType(lua_State * L) int w_Fixture_getType(lua_State * L)
@@ -251,11 +254,15 @@ namespace box2d
int w_Fixture_destroy(lua_State * L) int w_Fixture_destroy(lua_State * L)
{ {
Proxy * p = (Proxy *)lua_touserdata(L, 1); Fixture * t = luax_checkfixture(L, 1);
p->own = false; try
{
Fixture * t = (Fixture *)p->data; t->destroy();
t->release(); }
catch (love::Exception & e)
{
luaL_error(L, "%s", e.what());
}
return 0; return 0;
} }
@@ -28,7 +28,10 @@ namespace box2d
{ {
FrictionJoint * luax_checkfrictionjoint(lua_State * L, int idx) FrictionJoint * luax_checkfrictionjoint(lua_State * L, int idx)
{ {
return luax_checktype<FrictionJoint>(L, idx, "FrictionJoint", PHYSICS_FRICTION_JOINT_T); FrictionJoint * j = luax_checktype<FrictionJoint>(L, idx, "FrictionJoint", PHYSICS_FRICTION_JOINT_T);
if (!j->isValid())
luaL_error(L, "Attempt to use destroyed joint.");
return j;
} }
int w_FrictionJoint_setMaxForce(lua_State * L) int w_FrictionJoint_setMaxForce(lua_State * L)
+4 -1
View File
@@ -28,7 +28,10 @@ namespace box2d
{ {
GearJoint * luax_checkgearjoint(lua_State * L, int idx) GearJoint * luax_checkgearjoint(lua_State * L, int idx)
{ {
return luax_checktype<GearJoint>(L, idx, "GearJoint", PHYSICS_GEAR_JOINT_T); GearJoint * j = luax_checktype<GearJoint>(L, idx, "GearJoint", PHYSICS_GEAR_JOINT_T);
if (!j->isValid())
luaL_error(L, "Attempt to use destroyed joint.");
return j;
} }
int w_GearJoint_setRatio(lua_State * L) int w_GearJoint_setRatio(lua_State * L)
+13 -7
View File
@@ -30,7 +30,10 @@ namespace box2d
{ {
Joint * luax_checkjoint(lua_State * L, int idx) Joint * luax_checkjoint(lua_State * L, int idx)
{ {
return luax_checktype<Joint>(L, idx, "Joint", PHYSICS_JOINT_T); Joint * t = luax_checktype<Joint>(L, idx, "Joint", PHYSICS_JOINT_T);
if (!t->isValid())
luaL_error(L, "Attempt to use destroyed joint.");
return t;
} }
int w_Joint_getType(lua_State * L) int w_Joint_getType(lua_State * L)
@@ -73,12 +76,15 @@ namespace box2d
int w_Joint_destroy(lua_State * L) int w_Joint_destroy(lua_State * L)
{ {
Proxy * p = (Proxy *)lua_touserdata(L, 1); Joint * t = luax_checkjoint(L, 1);
p->own = false; try
{
Joint * t = (Joint *)p->data; t->destroyJoint();
t->release(); }
catch (love::Exception & e)
{
luaL_error(L, "%s", e.what());
}
return 0; return 0;
} }
@@ -28,7 +28,10 @@ namespace box2d
{ {
MouseJoint * luax_checkmousejoint(lua_State * L, int idx) MouseJoint * luax_checkmousejoint(lua_State * L, int idx)
{ {
return luax_checktype<MouseJoint>(L, idx, "MouseJoint", PHYSICS_MOUSE_JOINT_T); MouseJoint * j = luax_checktype<MouseJoint>(L, idx, "MouseJoint", PHYSICS_MOUSE_JOINT_T);
if (!j->isValid())
luaL_error(L, "Attempt to use destroyed joint.");
return j;
} }
int w_MouseJoint_setTarget(lua_State * L) int w_MouseJoint_setTarget(lua_State * L)
+1 -1
View File
@@ -378,7 +378,7 @@ namespace box2d
{ {
Physics::setMeter(arg1); Physics::setMeter(arg1);
} }
catch (love::Exception e) catch (love::Exception & e)
{ {
return luaL_error(L, e.what()); return luaL_error(L, e.what());
} }
@@ -28,7 +28,10 @@ namespace box2d
{ {
PrismaticJoint * luax_checkprismaticjoint(lua_State * L, int idx) PrismaticJoint * luax_checkprismaticjoint(lua_State * L, int idx)
{ {
return luax_checktype<PrismaticJoint>(L, idx, "PrismaticJoint", PHYSICS_PRISMATIC_JOINT_T); PrismaticJoint * j = luax_checktype<PrismaticJoint>(L, idx, "PrismaticJoint", PHYSICS_PRISMATIC_JOINT_T);
if (!j->isValid())
luaL_error(L, "Attempt to use destroyed joint.");
return j;
} }
int w_PrismaticJoint_getJointTranslation(lua_State * L) int w_PrismaticJoint_getJointTranslation(lua_State * L)
@@ -28,7 +28,10 @@ namespace box2d
{ {
PulleyJoint * luax_checkpulleyjoint(lua_State * L, int idx) PulleyJoint * luax_checkpulleyjoint(lua_State * L, int idx)
{ {
return luax_checktype<PulleyJoint>(L, idx, "PulleyJoint", PHYSICS_PULLEY_JOINT_T); PulleyJoint * j = luax_checktype<PulleyJoint>(L, idx, "PulleyJoint", PHYSICS_PULLEY_JOINT_T);
if (!j->isValid())
luaL_error(L, "Attempt to use destroyed joint.");
return j;
} }
int w_PulleyJoint_getGroundAnchors(lua_State * L) int w_PulleyJoint_getGroundAnchors(lua_State * L)
@@ -28,7 +28,10 @@ namespace box2d
{ {
RevoluteJoint * luax_checkrevolutejoint(lua_State * L, int idx) RevoluteJoint * luax_checkrevolutejoint(lua_State * L, int idx)
{ {
return luax_checktype<RevoluteJoint>(L, idx, "RevoluteJoint", PHYSICS_REVOLUTE_JOINT_T); RevoluteJoint * j = luax_checktype<RevoluteJoint>(L, idx, "RevoluteJoint", PHYSICS_REVOLUTE_JOINT_T);
if (!j->isValid())
luaL_error(L, "Attempt to use destroyed joint.");
return j;
} }
int w_RevoluteJoint_getJointAngle(lua_State * L) int w_RevoluteJoint_getJointAngle(lua_State * L)
+4 -1
View File
@@ -28,7 +28,10 @@ namespace box2d
{ {
RopeJoint * luax_checkropejoint(lua_State * L, int idx) RopeJoint * luax_checkropejoint(lua_State * L, int idx)
{ {
return luax_checktype<RopeJoint>(L, idx, "RopeJoint", PHYSICS_ROPE_JOINT_T); RopeJoint * j = luax_checktype<RopeJoint>(L, idx, "RopeJoint", PHYSICS_ROPE_JOINT_T);
if (!j->isValid())
luaL_error(L, "Attempt to use destroyed joint.");
return j;
} }
int w_RopeJoint_getMaxLength(lua_State * L) int w_RopeJoint_getMaxLength(lua_State * L)
+4 -1
View File
@@ -28,7 +28,10 @@ namespace box2d
{ {
WeldJoint * luax_checkweldjoint(lua_State * L, int idx) WeldJoint * luax_checkweldjoint(lua_State * L, int idx)
{ {
return luax_checktype<WeldJoint>(L, idx, "WeldJoint", PHYSICS_WELD_JOINT_T); WeldJoint * j = luax_checktype<WeldJoint>(L, idx, "WeldJoint", PHYSICS_WELD_JOINT_T);
if (!j->isValid())
luaL_error(L, "Attempt to use destroyed joint.");
return j;
} }
int w_WeldJoint_setFrequency(lua_State * L) int w_WeldJoint_setFrequency(lua_State * L)
@@ -28,7 +28,10 @@ namespace box2d
{ {
WheelJoint * luax_checkwheeljoint(lua_State * L, int idx) WheelJoint * luax_checkwheeljoint(lua_State * L, int idx)
{ {
return luax_checktype<WheelJoint>(L, idx, "WheelJoint", PHYSICS_WHEEL_JOINT_T); WheelJoint * j = luax_checktype<WheelJoint>(L, idx, "WheelJoint", PHYSICS_WHEEL_JOINT_T);
if (!j->isValid())
luaL_error(L, "Attempt to use destroyed joint.");
return j;
} }
int w_WheelJoint_getJointTranslation(lua_State * L) int w_WheelJoint_getJointTranslation(lua_State * L)
+20 -1
View File
@@ -29,7 +29,10 @@ namespace box2d
World * luax_checkworld(lua_State * L, int idx) World * luax_checkworld(lua_State * L, int idx)
{ {
return luax_checktype<World>(L, idx, "World", PHYSICS_WORLD_T); World * w = luax_checktype<World>(L, idx, "World", PHYSICS_WORLD_T);
if (!w->isValid())
luaL_error(L, "Attempt to use destroyed world.");
return w;
} }
int w_World_update(lua_State * L) int w_World_update(lua_State * L)
@@ -162,6 +165,21 @@ namespace box2d
ASSERT_GUARD(return t->rayCast(L);) ASSERT_GUARD(return t->rayCast(L);)
} }
int w_World_destroy(lua_State * L)
{
World * t = luax_checkworld(L, 1);
try
{
t->destroy();
}
catch (love::Exception & e)
{
luaL_error(L, "%s", e.what());
}
return 0;
}
static const luaL_Reg functions[] = { static const luaL_Reg functions[] = {
{ "update", w_World_update }, { "update", w_World_update },
{ "setCallbacks", w_World_setCallbacks }, { "setCallbacks", w_World_setCallbacks },
@@ -181,6 +199,7 @@ namespace box2d
{ "getContactList", w_World_getContactList }, { "getContactList", w_World_getContactList },
{ "queryBoundingBox", w_World_queryBoundingBox }, { "queryBoundingBox", w_World_queryBoundingBox },
{ "rayCast", w_World_rayCast }, { "rayCast", w_World_rayCast },
{ "destroy", w_World_destroy },
{ 0, 0 } { 0, 0 }
}; };
+2
View File
@@ -23,6 +23,7 @@
// LOVE // LOVE
#include <common/runtime.h> #include <common/runtime.h>
#include <common/Exception.h>
#include "World.h" #include "World.h"
#include "wrap_Physics.h" #include "wrap_Physics.h"
@@ -51,6 +52,7 @@ namespace box2d
int w_World_getContactList(lua_State * L); int w_World_getContactList(lua_State * L);
int w_World_queryBoundingBox(lua_State * L); int w_World_queryBoundingBox(lua_State * L);
int w_World_rayCast(lua_State * L); int w_World_rayCast(lua_State * L);
int w_World_destroy(lua_State * L);
extern "C" int luaopen_world(lua_State * L); extern "C" int luaopen_world(lua_State * L);
} // box2d } // box2d