From 7b47a6ad2e08be302e78b1d607c34e5e43953623 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 21 Feb 2017 15:58:31 +0100 Subject: [PATCH] Physics2D: Add support for trigger and callbacks --- include/Nazara/Physics2D/Collider2D.hpp | 13 +++ include/Nazara/Physics2D/Collider2D.inl | 21 +++++ include/Nazara/Physics2D/PhysWorld2D.hpp | 28 +++++- src/Nazara/Physics2D/Collider2D.cpp | 12 +++ src/Nazara/Physics2D/PhysWorld2D.cpp | 105 +++++++++++++++++++++++ src/Nazara/Physics2D/RigidBody2D.cpp | 2 +- 6 files changed, 179 insertions(+), 2 deletions(-) diff --git a/include/Nazara/Physics2D/Collider2D.hpp b/include/Nazara/Physics2D/Collider2D.hpp index 610d1a00f..7238237af 100644 --- a/include/Nazara/Physics2D/Collider2D.hpp +++ b/include/Nazara/Physics2D/Collider2D.hpp @@ -42,8 +42,15 @@ namespace Nz virtual float ComputeInertialMatrix(float mass) const = 0; + inline unsigned int GetCollisionId() const; + virtual ColliderType2D GetType() const = 0; + inline bool IsTrigger() const; + + inline void SetCollisionId(unsigned long typeId); + inline void SetTrigger(bool trigger); + Collider2D& operator=(const Collider2D&) = delete; Collider2D& operator=(Collider2D&&) = delete; @@ -53,6 +60,12 @@ namespace Nz protected: virtual std::vector CreateShapes(RigidBody2D* body) const = 0; + bool m_trigger; + unsigned int m_collisionId; + + private: + virtual std::vector GenerateShapes(RigidBody2D* body) const; + static Collider2DLibrary::LibraryMap s_library; }; diff --git a/include/Nazara/Physics2D/Collider2D.inl b/include/Nazara/Physics2D/Collider2D.inl index f5b222875..bf4902a81 100644 --- a/include/Nazara/Physics2D/Collider2D.inl +++ b/include/Nazara/Physics2D/Collider2D.inl @@ -7,6 +7,26 @@ namespace Nz { + inline unsigned int Collider2D::GetCollisionId() const + { + return m_collisionId; + } + + inline bool Collider2D::IsTrigger() const + { + return m_trigger; + } + + inline void Collider2D::SetCollisionId(unsigned long typeId) + { + m_collisionId = typeId; + } + + inline void Collider2D::SetTrigger(bool trigger) + { + m_trigger = trigger; + } + inline const Rectf& BoxCollider2D::GetRect() const { return m_rect; @@ -82,3 +102,4 @@ namespace Nz } #include +#include "Collider2D.hpp" diff --git a/include/Nazara/Physics2D/PhysWorld2D.hpp b/include/Nazara/Physics2D/PhysWorld2D.hpp index c2ffb437c..760773c7d 100644 --- a/include/Nazara/Physics2D/PhysWorld2D.hpp +++ b/include/Nazara/Physics2D/PhysWorld2D.hpp @@ -10,14 +10,26 @@ #include #include #include +#include +#include +struct cpCollisionHandler; struct cpSpace; namespace Nz { + class RigidBody2D; + class NAZARA_PHYSICS2D_API PhysWorld2D { + using ContactEndCallback = void(*)(PhysWorld2D& world, RigidBody2D& bodyA, RigidBody2D& bodyB, void* userdata); + using ContactPreSolveCallback = bool(*)(PhysWorld2D& world, RigidBody2D& bodyA, RigidBody2D& bodyB, void* userdata); + using ContactPostSolveCallback = void(*)(PhysWorld2D& world, RigidBody2D& bodyA, RigidBody2D& bodyB, void* userdata); + using ContactStartCallback = bool(*)(PhysWorld2D& world, RigidBody2D& bodyA, RigidBody2D& bodyB, void* userdata); + public: + struct Callback; + PhysWorld2D(); PhysWorld2D(const PhysWorld2D&) = delete; PhysWorld2D(PhysWorld2D&&) = delete; ///TODO @@ -27,8 +39,10 @@ namespace Nz cpSpace* GetHandle() const; float GetStepSize() const; + void RegisterCallbacks(unsigned int collisionId, const Callback& callbacks); + void RegisterCallbacks(unsigned int collisionIdA, unsigned int collisionIdB, const Callback& callbacks); + void SetGravity(const Vector2f& gravity); - void SetSolverModel(unsigned int model); void SetStepSize(float stepSize); void Step(float timestep); @@ -36,7 +50,19 @@ namespace Nz PhysWorld2D& operator=(const PhysWorld2D&) = delete; PhysWorld2D& operator=(PhysWorld2D&&) = delete; ///TODO + struct Callback + { + ContactEndCallback endCallback; + ContactPreSolveCallback preSolveCallback; + ContactPostSolveCallback postSolveCallback; + ContactStartCallback startCallback; + void* userdata; + }; + private: + void InitCallbacks(cpCollisionHandler* handler, const Callback& callbacks); + + std::unordered_map> m_callbacks; cpSpace* m_handle; float m_stepSize; float m_timestepAccumulator; diff --git a/src/Nazara/Physics2D/Collider2D.cpp b/src/Nazara/Physics2D/Collider2D.cpp index 928ea3974..cce3301aa 100644 --- a/src/Nazara/Physics2D/Collider2D.cpp +++ b/src/Nazara/Physics2D/Collider2D.cpp @@ -11,6 +11,18 @@ namespace Nz { Collider2D::~Collider2D() = default; + std::vector Collider2D::GenerateShapes(RigidBody2D* body) const + { + std::vector shapes = CreateShapes(body); + for (cpShape* shape : shapes) + { + cpShapeSetCollisionType(shape, m_collisionId); + cpShapeSetSensor(shape, (m_trigger) ? cpTrue : cpFalse); + } + + return shapes; + } + /******************************** BoxCollider2D *********************************/ BoxCollider2D::BoxCollider2D(const Vector2f& size, float radius) : diff --git a/src/Nazara/Physics2D/PhysWorld2D.cpp b/src/Nazara/Physics2D/PhysWorld2D.cpp index 62d194e9b..16ead3332 100644 --- a/src/Nazara/Physics2D/PhysWorld2D.cpp +++ b/src/Nazara/Physics2D/PhysWorld2D.cpp @@ -37,6 +37,16 @@ namespace Nz return m_stepSize; } + void PhysWorld2D::RegisterCallbacks(unsigned int collisionId, const Callback& callbacks) + { + InitCallbacks(cpSpaceAddWildcardHandler(m_handle, collisionId), callbacks); + } + + void PhysWorld2D::RegisterCallbacks(unsigned int collisionIdA, unsigned int collisionIdB, const Callback& callbacks) + { + InitCallbacks(cpSpaceAddCollisionHandler(m_handle, collisionIdA, collisionIdB), callbacks); + } + void PhysWorld2D::SetGravity(const Vector2f& gravity) { cpSpaceSetGravity(m_handle, cpv(gravity.x, gravity.y)); @@ -57,4 +67,99 @@ namespace Nz m_timestepAccumulator -= m_stepSize; } } + + void PhysWorld2D::InitCallbacks(cpCollisionHandler* handler, const Callback& callbacks) + { + auto it = m_callbacks.emplace(handler, std::make_unique(callbacks)).first; + + handler->userData = &it->second; + + if (callbacks.startCallback) + { + handler->beginFunc = [](cpArbiter* arb, cpSpace* space, void *data) -> cpBool + { + cpBody* firstBody; + cpBody* secondBody; + cpArbiterGetBodies(arb, &firstBody, &secondBody); + + PhysWorld2D* world = static_cast(cpSpaceGetUserData(space)); + RigidBody2D* firstRigidBody = static_cast(cpBodyGetUserData(firstBody)); + RigidBody2D* secondRigidBody = static_cast(cpBodyGetUserData(secondBody)); + + const Callback* customCallbacks = static_cast(data); + if (customCallbacks->startCallback(*world, *firstRigidBody, *secondRigidBody, customCallbacks->userdata)) + { + cpBool retA = cpArbiterCallWildcardBeginA(arb, space); + cpBool retB = cpArbiterCallWildcardBeginB(arb, space); + return retA && retB; + } + else + return cpFalse; + }; + } + + if (callbacks.endCallback) + { + handler->separateFunc = [](cpArbiter* arb, cpSpace* space, void *data) + { + cpBody* firstBody; + cpBody* secondBody; + cpArbiterGetBodies(arb, &firstBody, &secondBody); + + PhysWorld2D* world = static_cast(cpSpaceGetUserData(space)); + RigidBody2D* firstRigidBody = static_cast(cpBodyGetUserData(firstBody)); + RigidBody2D* secondRigidBody = static_cast(cpBodyGetUserData(secondBody)); + + const Callback* customCallbacks = static_cast(data); + customCallbacks->endCallback(*world, *firstRigidBody, *secondRigidBody, customCallbacks->userdata); + + cpArbiterCallWildcardSeparateA(arb, space); + cpArbiterCallWildcardSeparateB(arb, space); + }; + } + + if (callbacks.preSolveCallback) + { + handler->preSolveFunc = [](cpArbiter* arb, cpSpace* space, void *data) -> cpBool + { + cpBody* firstBody; + cpBody* secondBody; + cpArbiterGetBodies(arb, &firstBody, &secondBody); + + PhysWorld2D* world = static_cast(cpSpaceGetUserData(space)); + RigidBody2D* firstRigidBody = static_cast(cpBodyGetUserData(firstBody)); + RigidBody2D* secondRigidBody = static_cast(cpBodyGetUserData(secondBody)); + + const Callback* customCallbacks = static_cast(data); + if (customCallbacks->preSolveCallback(*world, *firstRigidBody, *secondRigidBody, customCallbacks->userdata)) + { + cpBool retA = cpArbiterCallWildcardPreSolveA(arb, space); + cpBool retB = cpArbiterCallWildcardPreSolveB(arb, space); + return retA && retB; + } + else + return cpFalse; + }; + } + + if (callbacks.postSolveCallback) + { + handler->postSolveFunc = [](cpArbiter* arb, cpSpace* space, void *data) + { + cpBody* firstBody; + cpBody* secondBody; + cpArbiterGetBodies(arb, &firstBody, &secondBody); + + PhysWorld2D* world = static_cast(cpSpaceGetUserData(space)); + RigidBody2D* firstRigidBody = static_cast(cpBodyGetUserData(firstBody)); + RigidBody2D* secondRigidBody = static_cast(cpBodyGetUserData(secondBody)); + + const Callback* customCallbacks = static_cast(data); + customCallbacks->postSolveCallback(*world, *firstRigidBody, *secondRigidBody, customCallbacks->userdata); + + cpArbiterCallWildcardPostSolveA(arb, space); + cpArbiterCallWildcardPostSolveB(arb, space); + }; + } + } } diff --git a/src/Nazara/Physics2D/RigidBody2D.cpp b/src/Nazara/Physics2D/RigidBody2D.cpp index 9078749b3..82c3a34ce 100644 --- a/src/Nazara/Physics2D/RigidBody2D.cpp +++ b/src/Nazara/Physics2D/RigidBody2D.cpp @@ -190,7 +190,7 @@ namespace Nz else m_geom = NullCollider2D::New(); - m_shapes = m_geom->CreateShapes(this); + m_shapes = m_geom->GenerateShapes(this); cpSpace* space = m_world->GetHandle(); for (cpShape* shape : m_shapes)