Browse Source

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
Bart van Strien 13 years ago
parent
commit
c1f68e058d
34 changed files with 340 additions and 118 deletions
  1. 26 7
      src/modules/physics/box2d/Body.cpp
  2. 2 1
      src/modules/physics/box2d/Body.h
  3. 0 2
      src/modules/physics/box2d/DistanceJoint.cpp
  4. 33 11
      src/modules/physics/box2d/Fixture.cpp
  5. 11 1
      src/modules/physics/box2d/Fixture.h
  6. 0 2
      src/modules/physics/box2d/FrictionJoint.cpp
  7. 0 2
      src/modules/physics/box2d/GearJoint.cpp
  8. 26 11
      src/modules/physics/box2d/Joint.cpp
  9. 15 7
      src/modules/physics/box2d/Joint.h
  10. 0 2
      src/modules/physics/box2d/MouseJoint.cpp
  11. 0 2
      src/modules/physics/box2d/PrismaticJoint.cpp
  12. 0 2
      src/modules/physics/box2d/PulleyJoint.cpp
  13. 0 2
      src/modules/physics/box2d/RevoluteJoint.cpp
  14. 0 2
      src/modules/physics/box2d/RopeJoint.cpp
  15. 0 2
      src/modules/physics/box2d/WeldJoint.cpp
  16. 0 2
      src/modules/physics/box2d/WheelJoint.cpp
  17. 108 24
      src/modules/physics/box2d/World.cpp
  18. 17 4
      src/modules/physics/box2d/World.h
  19. 13 7
      src/modules/physics/box2d/wrap_Body.cpp
  20. 4 1
      src/modules/physics/box2d/wrap_DistanceJoint.cpp
  21. 13 6
      src/modules/physics/box2d/wrap_Fixture.cpp
  22. 4 1
      src/modules/physics/box2d/wrap_FrictionJoint.cpp
  23. 4 1
      src/modules/physics/box2d/wrap_GearJoint.cpp
  24. 13 7
      src/modules/physics/box2d/wrap_Joint.cpp
  25. 4 1
      src/modules/physics/box2d/wrap_MouseJoint.cpp
  26. 1 1
      src/modules/physics/box2d/wrap_Physics.cpp
  27. 4 1
      src/modules/physics/box2d/wrap_PrismaticJoint.cpp
  28. 4 1
      src/modules/physics/box2d/wrap_PulleyJoint.cpp
  29. 4 1
      src/modules/physics/box2d/wrap_RevoluteJoint.cpp
  30. 4 1
      src/modules/physics/box2d/wrap_RopeJoint.cpp
  31. 4 1
      src/modules/physics/box2d/wrap_WeldJoint.cpp
  32. 4 1
      src/modules/physics/box2d/wrap_WheelJoint.cpp
  33. 20 1
      src/modules/physics/box2d/wrap_World.cpp
  34. 2 0
      src/modules/physics/box2d/wrap_World.h

+ 26 - 7
src/modules/physics/box2d/Body.cpp

@@ -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
src/modules/physics/box2d/Body.h

@@ -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();
 
 

+ 0 - 2
src/modules/physics/box2d/DistanceJoint.cpp

@@ -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
src/modules/physics/box2d/Fixture.cpp

@@ -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());
-		else body->retain();
+		if (!body)
+			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)
-			body->body->DestroyFixture(fixture);
-		fixture = 0;
-
-		body->release();
+		fixture = NULL;
 	}
 	}
 
 
 	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
src/modules/physics/box2d/Fixture.h

@@ -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

+ 0 - 2
src/modules/physics/box2d/FrictionJoint.cpp

@@ -45,8 +45,6 @@ namespace box2d
 
 
 	FrictionJoint::~FrictionJoint()
 	FrictionJoint::~FrictionJoint()
 	{
 	{
-		destroyJoint(joint);
-		joint = 0;
 	}
 	}
 
 
 	void FrictionJoint::setMaxForce(float force)
 	void FrictionJoint::setMaxForce(float force)

+ 0 - 2
src/modules/physics/box2d/GearJoint.cpp

@@ -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
src/modules/physics/box2d/Joint.cpp

@@ -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
src/modules/physics/box2d/Joint.h

@@ -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

+ 0 - 2
src/modules/physics/box2d/MouseJoint.cpp

@@ -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)

+ 0 - 2
src/modules/physics/box2d/PrismaticJoint.cpp

@@ -47,8 +47,6 @@ namespace box2d
 
 
 	PrismaticJoint::~PrismaticJoint()
 	PrismaticJoint::~PrismaticJoint()
 	{
 	{
-		destroyJoint(joint);
-		joint = 0;
 	}
 	}
 
 
 	float PrismaticJoint::getJointTranslation() const
 	float PrismaticJoint::getJointTranslation() const

+ 0 - 2
src/modules/physics/box2d/PulleyJoint.cpp

@@ -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)

+ 0 - 2
src/modules/physics/box2d/RevoluteJoint.cpp

@@ -44,8 +44,6 @@ namespace box2d
 
 
 	RevoluteJoint::~RevoluteJoint()
 	RevoluteJoint::~RevoluteJoint()
 	{
 	{
-		destroyJoint(joint);
-		joint = 0;
 	}
 	}
 
 
 	float RevoluteJoint::getJointAngle() const
 	float RevoluteJoint::getJointAngle() const

+ 0 - 2
src/modules/physics/box2d/RopeJoint.cpp

@@ -46,8 +46,6 @@ namespace box2d
 
 
 	RopeJoint::~RopeJoint()
 	RopeJoint::~RopeJoint()
 	{
 	{
-		destroyJoint(joint);
-		joint = 0;
 	}
 	}
 
 
 	float RopeJoint::getMaxLength() const
 	float RopeJoint::getMaxLength() const

+ 0 - 2
src/modules/physics/box2d/WeldJoint.cpp

@@ -45,8 +45,6 @@ namespace box2d
 
 
 	WeldJoint::~WeldJoint()
 	WeldJoint::~WeldJoint()
 	{
 	{
-		destroyJoint(joint);
-		joint = 0;
 	}
 	}
 
 
 	void WeldJoint::setFrequency(float hz)
 	void WeldJoint::setFrequency(float hz)

+ 0 - 2
src/modules/physics/box2d/WheelJoint.cpp

@@ -44,8 +44,6 @@ namespace box2d
 
 
 	WheelJoint::~WheelJoint()
 	WheelJoint::~WheelJoint()
 	{
 	{
-		destroyJoint(joint);
-		joint = 0;
 	}
 	}
 
 
 	float WheelJoint::getJointTranslation() const
 	float WheelJoint::getJointTranslation() const

+ 108 - 24
src/modules/physics/box2d/World.cpp

@@ -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 == groundBody) continue;
+			if (!b)
+				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
src/modules/physics/box2d/World.h

@@ -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.
-		* To be called from Body
+		* Destroy this world.
 		**/
 		**/
-		void destroyBody(Body * b);
+		void destroy();
 
 
 	};
 	};
 
 

+ 13 - 7
src/modules/physics/box2d/wrap_Body.cpp

@@ -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);
-		p->own = false;
-
-		Body * t = (Body *)p->data;
-		t->destroy();
-
+		Body * t = luax_checkbody(L, 1);
+		try
+		{
+			t->destroy();
+		}
+		catch (love::Exception & e)
+		{
+			luaL_error(L, "%s", e.what());
+		}
 		return 0;
 		return 0;
 	}
 	}
 
 

+ 4 - 1
src/modules/physics/box2d/wrap_DistanceJoint.cpp

@@ -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
src/modules/physics/box2d/wrap_Fixture.cpp

@@ -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);
-		p->own = false;
-
-		Fixture * t = (Fixture *)p->data;
-		t->release();
+		Fixture * t = luax_checkfixture(L, 1);
+		try
+		{
+			t->destroy();
+		}
+		catch (love::Exception & e)
+		{
+			luaL_error(L, "%s", e.what());
+		}
 		return 0;
 		return 0;
 	}
 	}
 
 

+ 4 - 1
src/modules/physics/box2d/wrap_FrictionJoint.cpp

@@ -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
src/modules/physics/box2d/wrap_GearJoint.cpp

@@ -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
src/modules/physics/box2d/wrap_Joint.cpp

@@ -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);
-		p->own = false;
-
-		Joint * t = (Joint *)p->data;
-		t->release();
-
+		Joint * t = luax_checkjoint(L, 1);
+		try
+		{
+			t->destroyJoint();
+		}
+		catch (love::Exception & e)
+		{
+			luaL_error(L, "%s", e.what());
+		}
 		return 0;
 		return 0;
 	}
 	}
 
 

+ 4 - 1
src/modules/physics/box2d/wrap_MouseJoint.cpp

@@ -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
src/modules/physics/box2d/wrap_Physics.cpp

@@ -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());
 		}
 		}

+ 4 - 1
src/modules/physics/box2d/wrap_PrismaticJoint.cpp

@@ -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)

+ 4 - 1
src/modules/physics/box2d/wrap_PulleyJoint.cpp

@@ -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)

+ 4 - 1
src/modules/physics/box2d/wrap_RevoluteJoint.cpp

@@ -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
src/modules/physics/box2d/wrap_RopeJoint.cpp

@@ -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
src/modules/physics/box2d/wrap_WeldJoint.cpp

@@ -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)

+ 4 - 1
src/modules/physics/box2d/wrap_WheelJoint.cpp

@@ -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
src/modules/physics/box2d/wrap_World.cpp

@@ -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 - 0
src/modules/physics/box2d/wrap_World.h

@@ -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