From 9ab9a393d5a3c246b61ccca7615fa9eb68aab48a Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 7 Jul 2014 15:24:24 -0300 Subject: [PATCH] Added Contact:getFixtures and Body:getContactList (see issue #905). The list of Contacts associated with bodies changes during World:update (potentially multiple times), so you might miss collisions if you don't use the World callbacks at all. --- src/modules/physics/box2d/Body.cpp | 24 ++++++++++++++++++++++ src/modules/physics/box2d/Body.h | 7 +++++++ src/modules/physics/box2d/Contact.cpp | 9 ++++++++ src/modules/physics/box2d/Contact.h | 5 +++++ src/modules/physics/box2d/World.cpp | 4 +--- src/modules/physics/box2d/wrap_Body.cpp | 10 +++++++++ src/modules/physics/box2d/wrap_Body.h | 1 + src/modules/physics/box2d/wrap_Contact.cpp | 16 +++++++++++++++ src/modules/physics/box2d/wrap_Contact.h | 1 + 9 files changed, 74 insertions(+), 3 deletions(-) diff --git a/src/modules/physics/box2d/Body.cpp b/src/modules/physics/box2d/Body.cpp index d43830d97..880e50b83 100644 --- a/src/modules/physics/box2d/Body.cpp +++ b/src/modules/physics/box2d/Body.cpp @@ -444,6 +444,30 @@ int Body::getFixtureList(lua_State *L) const return 1; } +int Body::getContactList(lua_State *L) const +{ + lua_newtable(L); + const b2ContactEdge *ce = body->GetContactList(); + int i = 1; + do + { + if (!ce) + break; + + Contact *contact = (Contact *) Memoizer::find(ce->contact); + if (!contact) + contact = new Contact(ce->contact); + else + contact->retain(); + + luax_pushtype(L, "Contact", PHYSICS_CONTACT_T, contact); + lua_rawseti(L, -2, i); + i++; + } + while ((ce = ce->next)); + return 1; +} + b2Vec2 Body::getVector(lua_State *L) { love::luax_assert_argc(L, 2, 2); diff --git a/src/modules/physics/box2d/Body.h b/src/modules/physics/box2d/Body.h index cd4faf11b..83dd0c6b1 100644 --- a/src/modules/physics/box2d/Body.h +++ b/src/modules/physics/box2d/Body.h @@ -393,6 +393,13 @@ public: **/ int getFixtureList(lua_State *L) const; + /** + * Get an array of all active Contacts attached to this Body. + * This list changes during World:update and you may miss some collisions + * if you don't use the collision callbacks. + **/ + int getContactList(lua_State *L) const; + /** * Destroy this body. **/ diff --git a/src/modules/physics/box2d/Contact.cpp b/src/modules/physics/box2d/Contact.cpp index 2142bb487..b3a480029 100644 --- a/src/modules/physics/box2d/Contact.cpp +++ b/src/modules/physics/box2d/Contact.cpp @@ -142,6 +142,15 @@ void Contact::getChildren(int &childA, int &childB) childB = contact->GetChildIndexB(); } +void Contact::getFixtures(Fixture *&fixtureA, Fixture *&fixtureB) +{ + fixtureA = (Fixture *) Memoizer::find(contact->GetFixtureA()); + fixtureB = (Fixture *) Memoizer::find(contact->GetFixtureB()); + + if (!fixtureA || !fixtureB) + throw love::Exception("A fixture has escaped Memoizer!"); +} + } // box2d } // physics } // love diff --git a/src/modules/physics/box2d/Contact.h b/src/modules/physics/box2d/Contact.h index 1222a3681..6068d3e6b 100644 --- a/src/modules/physics/box2d/Contact.h +++ b/src/modules/physics/box2d/Contact.h @@ -148,6 +148,11 @@ public: void getChildren(int &childA, int &childB); + /** + * Gets the Fixtures associated with this Contact. + **/ + void getFixtures(Fixture *&fixtureA, Fixture *&fixtureB); + private: // The Box2D contact. diff --git a/src/modules/physics/box2d/World.cpp b/src/modules/physics/box2d/World.cpp index 400772ffd..4f2177543 100644 --- a/src/modules/physics/box2d/World.cpp +++ b/src/modules/physics/box2d/World.cpp @@ -318,10 +318,8 @@ bool World::ShouldCollide(b2Fixture *fixtureA, b2Fixture *fixtureB) { // Fixtures should be memoized, if we created them Fixture *a = (Fixture *)Memoizer::find(fixtureA); - if (!a) - throw love::Exception("A fixture has escaped Memoizer!"); Fixture *b = (Fixture *)Memoizer::find(fixtureB); - if (!b) + if (!a || !b) throw love::Exception("A fixture has escaped Memoizer!"); return filter.process(a, b); } diff --git a/src/modules/physics/box2d/wrap_Body.cpp b/src/modules/physics/box2d/wrap_Body.cpp index 040438dc7..8e97138d0 100644 --- a/src/modules/physics/box2d/wrap_Body.cpp +++ b/src/modules/physics/box2d/wrap_Body.cpp @@ -540,6 +540,15 @@ int w_Body_getFixtureList(lua_State *L) return n; } +int w_Body_getContactList(lua_State *L) +{ + Body *t = luax_checkbody(L, 1); + lua_remove(L, 1); + int n = 0; + luax_catchexcept(L, [&](){ n = t->getContactList(L); }); + return n; +} + int w_Body_destroy(lua_State *L) { Body *t = luax_checkbody(L, 1); @@ -615,6 +624,7 @@ static const luaL_Reg functions[] = { "isFixedRotation", w_Body_isFixedRotation }, { "getWorld", w_Body_getWorld }, { "getFixtureList", w_Body_getFixtureList }, + { "getContactList", w_Body_getContactList }, { "destroy", w_Body_destroy }, { "setUserData", w_Body_setUserData }, { "getUserData", w_Body_getUserData }, diff --git a/src/modules/physics/box2d/wrap_Body.h b/src/modules/physics/box2d/wrap_Body.h index c702b5f56..f6e65f253 100644 --- a/src/modules/physics/box2d/wrap_Body.h +++ b/src/modules/physics/box2d/wrap_Body.h @@ -85,6 +85,7 @@ int w_Body_setFixedRotation(lua_State *L); int w_Body_isFixedRotation(lua_State *L); int w_Body_getWorld(lua_State *L); int w_Body_getFixtureList(lua_State *L); +int w_Body_getContactList(lua_State *L); int w_Body_destroy(lua_State *L); int w_Body_setUserData(lua_State *L); int w_Body_getUserData(lua_State *L); diff --git a/src/modules/physics/box2d/wrap_Contact.cpp b/src/modules/physics/box2d/wrap_Contact.cpp index f6856ddf1..7911c7ff2 100644 --- a/src/modules/physics/box2d/wrap_Contact.cpp +++ b/src/modules/physics/box2d/wrap_Contact.cpp @@ -19,6 +19,7 @@ **/ #include "wrap_Contact.h" +#include "Fixture.h" namespace love { @@ -138,6 +139,20 @@ int w_Contact_getChildren(lua_State *L) return 2; } +int w_Contact_getFixtures(lua_State *L) +{ + Contact *t = luax_checkcontact(L, 1); + Fixture *a = nullptr; + Fixture *b = nullptr; + luax_catchexcept(L, [&](){ t->getFixtures(a, b); }); + + a->retain(); + luax_pushtype(L, "Fixture", PHYSICS_FIXTURE_T, a); + b->retain(); + luax_pushtype(L, "Fixture", PHYSICS_FIXTURE_T, b); + return 2; +} + extern "C" int luaopen_contact(lua_State *L) { static const luaL_Reg functions[] = @@ -156,6 +171,7 @@ extern "C" int luaopen_contact(lua_State *L) { "setTangentSpeed", w_Contact_setTangentSpeed }, { "getTangentSpeed", w_Contact_getTangentSpeed }, { "getChildren", w_Contact_getChildren }, + { "getFixtures", w_Contact_getFixtures }, { 0, 0 } }; diff --git a/src/modules/physics/box2d/wrap_Contact.h b/src/modules/physics/box2d/wrap_Contact.h index c1c2e2e29..fd325c382 100644 --- a/src/modules/physics/box2d/wrap_Contact.h +++ b/src/modules/physics/box2d/wrap_Contact.h @@ -47,6 +47,7 @@ int w_Contact_resetRestitution(lua_State *L); int w_Contact_setTangentSpeed(lua_State *L); int w_Contact_getTangentSpeed(lua_State *L); int w_Contact_getChildren(lua_State *L); +int w_Contact_getFixtures(lua_State *L); extern "C" int luaopen_contact(lua_State *L); } // box2d