diff --git a/include/Nazara/Physics2D/PhysWorld2D.hpp b/include/Nazara/Physics2D/PhysWorld2D.hpp index 3f4c3e696..c3858dc1a 100644 --- a/include/Nazara/Physics2D/PhysWorld2D.hpp +++ b/include/Nazara/Physics2D/PhysWorld2D.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -19,10 +20,10 @@ struct cpSpace; namespace Nz { - class RigidBody2D; - class NAZARA_PHYSICS2D_API PhysWorld2D { + friend RigidBody2D; + 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); @@ -90,7 +91,23 @@ namespace Nz private: void InitCallbacks(cpCollisionHandler* handler, const Callback& callbacks); + using PostStep = std::function; + + void OnRigidBodyMoved(RigidBody2D* oldPointer, RigidBody2D* newPointer); + void OnRigidBodyRelease(RigidBody2D* rigidBody); + + void RegisterPostStep(RigidBody2D* rigidBody, PostStep&& func); + + struct PostStepContainer + { + NazaraSlot(RigidBody2D, OnRigidBody2DMove, onMovedSlot); + NazaraSlot(RigidBody2D, OnRigidBody2DRelease, onReleaseSlot); + + std::vector funcs; + }; + std::unordered_map> m_callbacks; + std::unordered_map m_rigidPostSteps; cpSpace* m_handle; float m_stepSize; float m_timestepAccumulator; diff --git a/src/Nazara/Physics2D/PhysWorld2D.cpp b/src/Nazara/Physics2D/PhysWorld2D.cpp index 6b18dbdd8..f3dcba77d 100644 --- a/src/Nazara/Physics2D/PhysWorld2D.cpp +++ b/src/Nazara/Physics2D/PhysWorld2D.cpp @@ -164,6 +164,16 @@ namespace Nz cpSpaceStep(m_handle, m_stepSize); OnPhysWorld2DPostStep(this); + if (!m_rigidPostSteps.empty()) + { + for (const auto& pair : m_rigidPostSteps) + { + for (const auto& step : pair.second.funcs) + step(); + } + + m_rigidPostSteps.clear(); + } m_timestepAccumulator -= m_stepSize; } @@ -263,4 +273,41 @@ namespace Nz }; } } + + void PhysWorld2D::OnRigidBodyMoved(RigidBody2D* oldPointer, RigidBody2D* newPointer) + { + auto it = m_rigidPostSteps.find(oldPointer); + if (it == m_rigidPostSteps.end()) + return; //< Shouldn't happen + + m_rigidPostSteps.emplace(std::make_pair(newPointer, std::move(it->second))); + m_rigidPostSteps.erase(oldPointer); + } + + void PhysWorld2D::OnRigidBodyRelease(RigidBody2D* rigidBody) + { + m_rigidPostSteps.erase(rigidBody); + } + + void PhysWorld2D::RegisterPostStep(RigidBody2D* rigidBody, PostStep&& func) + { + // If space isn't locked, no need to wait + if (!cpSpaceIsLocked(m_handle)) + { + func(); + return; + } + + auto it = m_rigidPostSteps.find(rigidBody); + if (it == m_rigidPostSteps.end()) + { + PostStepContainer postStep; + postStep.onMovedSlot.Connect(rigidBody->OnRigidBody2DMove, this, &PhysWorld2D::OnRigidBodyMoved); + postStep.onReleaseSlot.Connect(rigidBody->OnRigidBody2DRelease, this, &PhysWorld2D::OnRigidBodyRelease); + + it = m_rigidPostSteps.insert(std::make_pair(rigidBody, std::move(postStep))).first; + } + + it->second.funcs.emplace_back(std::move(func)); + } } diff --git a/src/Nazara/Physics2D/RigidBody2D.cpp b/src/Nazara/Physics2D/RigidBody2D.cpp index d96ba3eb1..aef36d0ad 100644 --- a/src/Nazara/Physics2D/RigidBody2D.cpp +++ b/src/Nazara/Physics2D/RigidBody2D.cpp @@ -249,15 +249,18 @@ namespace Nz cpBodySetMoment(m_handle, m_geom->ComputeInertialMatrix(m_mass)); } else - cpBodySetType(m_handle, CP_BODY_TYPE_STATIC); + m_world->RegisterPostStep(this, [this]() { cpBodySetType(m_handle, CP_BODY_TYPE_STATIC); } ); } else if (mass > 0.f) { if (cpBodyGetType(m_handle) == CP_BODY_TYPE_STATIC) { - cpBodySetType(m_handle, CP_BODY_TYPE_DYNAMIC); - cpBodySetMass(m_handle, mass); - cpBodySetMoment(m_handle, m_geom->ComputeInertialMatrix(m_mass)); + m_world->RegisterPostStep(this, [this, mass]() + { + cpBodySetType(m_handle, CP_BODY_TYPE_DYNAMIC); + cpBodySetMass(m_handle, mass); + cpBodySetMoment(m_handle, m_geom->ComputeInertialMatrix(m_mass)); + }); } }