diff --git a/include/Nazara/Physics2D/RigidBody2D.hpp b/include/Nazara/Physics2D/RigidBody2D.hpp index 5d77d5429..e55edc88a 100644 --- a/include/Nazara/Physics2D/RigidBody2D.hpp +++ b/include/Nazara/Physics2D/RigidBody2D.hpp @@ -98,6 +98,8 @@ namespace Nz void SetVelocity(const Vector2f& velocity); void SetVelocityFunction(VelocityFunc velocityFunc); + void TeleportTo(const Vector2f& position, const RadianAnglef& rotation); + void UpdateVelocity(const Vector2f& gravity, float damping, float deltaTime); void Wakeup(); diff --git a/include/Nazara/Physics2D/Systems/Physics2DSystem.hpp b/include/Nazara/Physics2D/Systems/Physics2DSystem.hpp index acf296ae8..e9ef5ec46 100644 --- a/include/Nazara/Physics2D/Systems/Physics2DSystem.hpp +++ b/include/Nazara/Physics2D/Systems/Physics2DSystem.hpp @@ -38,9 +38,8 @@ namespace Nz Physics2DSystem& operator=(Physics2DSystem&&) = delete; private: - static void OnConstruct(entt::registry& registry, entt::entity entity); - entt::registry& m_registry; + entt::observer m_physicsConstructObserver; entt::scoped_connection m_constructConnection; PhysWorld2D m_physWorld; }; diff --git a/src/Nazara/Physics2D/RigidBody2D.cpp b/src/Nazara/Physics2D/RigidBody2D.cpp index 7f0f26bf6..b0c5d5d7d 100644 --- a/src/Nazara/Physics2D/RigidBody2D.cpp +++ b/src/Nazara/Physics2D/RigidBody2D.cpp @@ -135,12 +135,12 @@ namespace Nz cpBodySetTorque(m_handle, cpBodyGetTorque(m_handle) + torque.value); } - bool RigidBody2D::ClosestPointQuery(const Nz::Vector2f& position, Nz::Vector2f* closestPoint, float* closestDistance) const + bool RigidBody2D::ClosestPointQuery(const Vector2f& position, Vector2f* closestPoint, float* closestDistance) const { cpVect pos = cpv(cpFloat(position.x), cpFloat(position.y)); float minDistance = std::numeric_limits::infinity(); - Nz::Vector2f closest; + Vector2f closest; for (cpShape* shape : m_shapes) { cpPointQueryInfo result; @@ -179,7 +179,7 @@ namespace Nz } } - void RigidBody2D::ForEachArbiter(std::function callback) + void RigidBody2D::ForEachArbiter(std::function callback) { using CallbackType = decltype(callback); @@ -196,7 +196,7 @@ namespace Nz void RigidBody2D::ForceSleep() { - m_world->RegisterPostStep(this, [](Nz::RigidBody2D* body) + m_world->RegisterPostStep(this, [](RigidBody2D* body) { if (cpBodyGetType(body->GetHandle()) == CP_BODY_TYPE_DYNAMIC) cpBodySleep(body->GetHandle()); @@ -221,13 +221,13 @@ namespace Nz return float(cpBodyGetAngularVelocity(m_handle)); } - float Nz::RigidBody2D::GetElasticity(std::size_t shapeIndex) const + float RigidBody2D::GetElasticity(std::size_t shapeIndex) const { assert(shapeIndex < m_shapes.size()); return float(cpShapeGetElasticity(m_shapes[shapeIndex])); } - float Nz::RigidBody2D::GetFriction(std::size_t shapeIndex) const + float RigidBody2D::GetFriction(std::size_t shapeIndex) const { assert(shapeIndex < m_shapes.size()); return float(cpShapeGetFriction(m_shapes[shapeIndex])); @@ -290,7 +290,7 @@ namespace Nz return std::distance(m_shapes.begin(), it); } - Vector2f Nz::RigidBody2D::GetSurfaceVelocity(std::size_t shapeIndex) const + Vector2f RigidBody2D::GetSurfaceVelocity(std::size_t shapeIndex) const { assert(shapeIndex < m_shapes.size()); cpVect vel = cpShapeGetSurfaceVelocity(m_shapes[shapeIndex]); @@ -421,7 +421,7 @@ namespace Nz { if (mass > 0.f) { - m_world->RegisterPostStep(this, [mass, recomputeMoment](Nz::RigidBody2D* body) + m_world->RegisterPostStep(this, [mass, recomputeMoment](RigidBody2D* body) { cpBodySetMass(body->GetHandle(), mass); @@ -430,11 +430,11 @@ namespace Nz }); } else - m_world->RegisterPostStep(this, [](Nz::RigidBody2D* body) { cpBodySetType(body->GetHandle(), (body->IsStatic()) ? CP_BODY_TYPE_STATIC : CP_BODY_TYPE_KINEMATIC); } ); + m_world->RegisterPostStep(this, [](RigidBody2D* body) { cpBodySetType(body->GetHandle(), (body->IsStatic()) ? CP_BODY_TYPE_STATIC : CP_BODY_TYPE_KINEMATIC); } ); } else if (mass > 0.f) { - m_world->RegisterPostStep(this, [mass, recomputeMoment](Nz::RigidBody2D* body) + m_world->RegisterPostStep(this, [mass, recomputeMoment](RigidBody2D* body) { if (cpBodyGetType(body->GetHandle()) != CP_BODY_TYPE_DYNAMIC) { @@ -470,7 +470,7 @@ namespace Nz void RigidBody2D::SetMomentOfInertia(float moment) { // Even though Chipmunk allows us to change this anytime, we need to do it in a post-step to prevent other post-steps to override this - m_world->RegisterPostStep(this, [moment] (Nz::RigidBody2D* body) + m_world->RegisterPostStep(this, [moment] (RigidBody2D* body) { cpBodySetMoment(body->GetHandle(), moment); }); @@ -482,7 +482,7 @@ namespace Nz cpBodySetPosition(m_handle, cpvadd(cpv(position.x, position.y), cpTransformVect(m_handle->transform, cpv(m_positionOffset.x, m_positionOffset.y)))); if (m_isStatic) { - m_world->RegisterPostStep(this, [](Nz::RigidBody2D* body) + m_world->RegisterPostStep(this, [](RigidBody2D* body) { cpSpaceReindexShapesForBody(body->GetWorld()->GetHandle(), body->GetHandle()); }); @@ -491,7 +491,7 @@ namespace Nz void RigidBody2D::SetPositionOffset(const Vector2f& offset) { - Nz::Vector2f position = GetPosition(); + Vector2f position = GetPosition(); m_positionOffset = offset; SetPosition(position); } @@ -501,7 +501,7 @@ namespace Nz cpBodySetAngle(m_handle, rotation.value); if (m_isStatic) { - m_world->RegisterPostStep(this, [](Nz::RigidBody2D* body) + m_world->RegisterPostStep(this, [](RigidBody2D* body) { cpSpaceReindexShapesForBody(body->GetWorld()->GetHandle(), body->GetHandle()); }); @@ -524,7 +524,7 @@ namespace Nz void RigidBody2D::SetStatic(bool setStaticBody) { m_isStatic = setStaticBody; - m_world->RegisterPostStep(this, [](Nz::RigidBody2D* body) + m_world->RegisterPostStep(this, [](RigidBody2D* body) { if (body->IsStatic()) { @@ -560,21 +560,35 @@ namespace Nz const auto& callback = rigidBody->GetVelocityFunction(); assert(callback); - callback(*rigidBody, Nz::Vector2f(float(gravity.x), float(gravity.y)), float(damping), float(dt)); + callback(*rigidBody, Vector2f(float(gravity.x), float(gravity.y)), float(damping), float(dt)); }; } else m_handle->velocity_func = cpBodyUpdateVelocity; } - void RigidBody2D::UpdateVelocity(const Nz::Vector2f & gravity, float damping, float deltaTime) + void RigidBody2D::TeleportTo(const Vector2f& position, const RadianAnglef& rotation) + { + // Use cpTransformVect to rotate/scale the position offset + cpBodySetPosition(m_handle, cpvadd(cpv(position.x, position.y), cpTransformVect(m_handle->transform, cpv(m_positionOffset.x, m_positionOffset.y)))); + cpBodySetAngle(m_handle, rotation.value); + if (m_isStatic) + { + m_world->RegisterPostStep(this, [](RigidBody2D* body) + { + cpSpaceReindexShapesForBody(body->GetWorld()->GetHandle(), body->GetHandle()); + }); + } + } + + void RigidBody2D::UpdateVelocity(const Vector2f & gravity, float damping, float deltaTime) { cpBodyUpdateVelocity(m_handle, cpv(gravity.x, gravity.y), damping, deltaTime); } void RigidBody2D::Wakeup() { - m_world->RegisterPostStep(this, [](Nz::RigidBody2D* body) + m_world->RegisterPostStep(this, [](RigidBody2D* body) { if (cpBodyGetType(body->GetHandle()) != CP_BODY_TYPE_STATIC) cpBodyActivate(body->GetHandle()); diff --git a/src/Nazara/Physics2D/Systems/Physics2DSystem.cpp b/src/Nazara/Physics2D/Systems/Physics2DSystem.cpp index c4a0ef131..12d002c50 100644 --- a/src/Nazara/Physics2D/Systems/Physics2DSystem.cpp +++ b/src/Nazara/Physics2D/Systems/Physics2DSystem.cpp @@ -10,7 +10,7 @@ namespace Nz { namespace { - inline Nz::RadianAnglef AngleFromQuaternion(const Nz::Quaternionf& quat) + inline RadianAnglef AngleFromQuaternion(const Quaternionf& quat) { float siny_cosp = 2.f * (quat.w * quat.z + quat.x * quat.y); float cosy_cosp = 1.f - 2.f * (quat.y * quat.y + quat.z * quat.z); @@ -20,14 +20,16 @@ namespace Nz } Physics2DSystem::Physics2DSystem(entt::registry& registry) : - m_registry(registry) + m_registry(registry), + m_physicsConstructObserver(m_registry, entt::collector.group()) { - m_constructConnection = registry.on_construct().connect(); } Physics2DSystem::~Physics2DSystem() { - // Ensure every NewtonBody is destroyed before world is + m_physicsConstructObserver.disconnect(); + + // Ensure every body is destroyed before world is auto rigidBodyView = m_registry.view(); for (auto [entity, rigidBodyComponent] : rigidBodyView.each()) rigidBodyComponent.Destroy(); @@ -35,6 +37,15 @@ namespace Nz void Physics2DSystem::Update(Time elapsedTime) { + // Move newly-created physics entities to their node position/rotation + m_physicsConstructObserver.each([&](entt::entity entity) + { + RigidBody2DComponent& entityPhysics = m_registry.get(entity); + NodeComponent& entityNode = m_registry.get(entity); + + entityPhysics.TeleportTo(Vector2f(entityNode.GetPosition()), AngleFromQuaternion(entityNode.GetRotation())); + }); + m_physWorld.Step(elapsedTime); // Replicate rigid body position to their node components @@ -44,20 +55,7 @@ namespace Nz if (rigidBodyComponent.IsSleeping()) continue; - nodeComponent.SetPosition(rigidBodyComponent.GetPosition(), CoordSys::Global); - nodeComponent.SetRotation(rigidBodyComponent.GetRotation(), CoordSys::Global); - } - } - - void Physics2DSystem::OnConstruct(entt::registry& registry, entt::entity entity) - { - // If our entity already has a node component when adding a rigid body, initialize it with its position/rotation - NodeComponent* node = registry.try_get(entity); - if (node) - { - RigidBody2DComponent& rigidBody = registry.get(entity); - rigidBody.SetPosition(Vector2f(node->GetPosition())); - rigidBody.SetRotation(AngleFromQuaternion(node->GetRotation())); + nodeComponent.SetTransform(rigidBodyComponent.GetPosition(), rigidBodyComponent.GetRotation()); } } }