diff --git a/SDK/include/NDK/Components/PhysicsComponent3D.hpp b/SDK/include/NDK/Components/PhysicsComponent3D.hpp index fe5e2f28a..e7985ca3d 100644 --- a/SDK/include/NDK/Components/PhysicsComponent3D.hpp +++ b/SDK/include/NDK/Components/PhysicsComponent3D.hpp @@ -60,7 +60,10 @@ namespace Ndk static ComponentIndex componentIndex; private: + void ApplyPhysicsState(Nz::RigidBody3D& rigidBody) const; + void CopyPhysicsState(const Nz::RigidBody3D& rigidBody); Nz::RigidBody3D& GetRigidBody(); + const Nz::RigidBody3D& GetRigidBody() const; void OnAttached() override; void OnComponentAttached(BaseComponent& component) override; @@ -70,7 +73,19 @@ namespace Ndk void OnEntityDisabled() override; void OnEntityEnabled() override; + struct PendingPhysObjectStates + { + Nz::Vector3f angularDamping; + Nz::Vector3f massCenter; + bool autoSleep; + bool valid = false; + float gravityFactor; + float linearDamping; + float mass; + }; + std::unique_ptr m_object; + PendingPhysObjectStates m_pendingStates; bool m_nodeSynchronizationEnabled; }; } diff --git a/SDK/include/NDK/Components/PhysicsComponent3D.inl b/SDK/include/NDK/Components/PhysicsComponent3D.inl index 319bb88dd..4fceefdff 100644 --- a/SDK/include/NDK/Components/PhysicsComponent3D.inl +++ b/SDK/include/NDK/Components/PhysicsComponent3D.inl @@ -20,8 +20,8 @@ namespace Ndk inline PhysicsComponent3D::PhysicsComponent3D(const PhysicsComponent3D& physics) : m_nodeSynchronizationEnabled(physics.m_nodeSynchronizationEnabled) { - // No copy of physical object (because we only create it when attached to an entity) - NazaraUnused(physics); + // We can't make a copy of the RigidBody3D, as we are not attached yet (and will possibly be attached to another world) + CopyPhysicsState(physics.GetRigidBody()); } /*! @@ -383,7 +383,8 @@ namespace Ndk inline void PhysicsComponent3D::SetMass(float mass) { NazaraAssert(m_object, "Invalid physics object"); - NazaraAssert(mass > 0.f, "Mass should be positive"); + NazaraAssert(mass >= 0.f, "Mass must be positive and finite"); + NazaraAssert(std::isfinite(mass), "Mass must be positive and finite"); m_object->SetMass(mass); } @@ -433,13 +434,44 @@ namespace Ndk m_object->SetRotation(rotation); } + inline void PhysicsComponent3D::ApplyPhysicsState(Nz::RigidBody3D& rigidBody) const + { + assert(m_pendingStates.valid); + + rigidBody.EnableAutoSleep(m_pendingStates.autoSleep); + rigidBody.SetAngularDamping(m_pendingStates.angularDamping); + rigidBody.SetGravityFactor(m_pendingStates.gravityFactor); + rigidBody.SetLinearDamping(m_pendingStates.linearDamping); + rigidBody.SetMass(m_pendingStates.mass); + rigidBody.SetMassCenter(m_pendingStates.massCenter); + } + + inline void PhysicsComponent3D::CopyPhysicsState(const Nz::RigidBody3D& rigidBody) + { + m_pendingStates.autoSleep = rigidBody.IsAutoSleepEnabled(); + m_pendingStates.angularDamping = rigidBody.GetAngularDamping(); + m_pendingStates.gravityFactor = rigidBody.GetGravityFactor(); + m_pendingStates.linearDamping = rigidBody.GetLinearDamping(); + m_pendingStates.mass = rigidBody.GetMass(); + m_pendingStates.massCenter = rigidBody.GetMassCenter(Nz::CoordSys_Local); + m_pendingStates.valid = true; + } + /*! * \brief Gets the underlying physics object * \return A reference to the physics object */ - inline Nz::RigidBody3D& PhysicsComponent3D::GetRigidBody() { return *m_object.get(); } + + /*! + * \brief Gets the underlying physics object + * \return A reference to the physics object + */ + inline const Nz::RigidBody3D& PhysicsComponent3D::GetRigidBody() const + { + return *m_object.get(); + } } diff --git a/SDK/src/NDK/Components/PhysicsComponent3D.cpp b/SDK/src/NDK/Components/PhysicsComponent3D.cpp index be7ea9f86..b93068fa7 100644 --- a/SDK/src/NDK/Components/PhysicsComponent3D.cpp +++ b/SDK/src/NDK/Components/PhysicsComponent3D.cpp @@ -41,7 +41,11 @@ namespace Ndk matrix.MakeIdentity(); m_object = std::make_unique(&world, geom, matrix); - m_object->SetMass(1.f); + + if (m_pendingStates.valid) + ApplyPhysicsState(*m_object); + else + m_object->SetMass(1.f); } /*! @@ -57,6 +61,7 @@ namespace Ndk if (IsComponent(component)) { NazaraAssert(m_object, "Invalid object"); + m_object->SetGeom(static_cast(component).GetGeom()); } } @@ -74,6 +79,7 @@ namespace Ndk if (IsComponent(component)) { NazaraAssert(m_object, "Invalid object"); + m_object->SetGeom(Nz::NullCollider3D::New()); } } @@ -84,7 +90,11 @@ namespace Ndk void PhysicsComponent3D::OnDetached() { - m_object.reset(); + if (m_object) + { + CopyPhysicsState(*m_object); + m_object.reset(); + } } void PhysicsComponent3D::OnEntityDestruction() diff --git a/src/Nazara/Physics3D/RigidBody3D.cpp b/src/Nazara/Physics3D/RigidBody3D.cpp index 60db49240..2718f93f8 100644 --- a/src/Nazara/Physics3D/RigidBody3D.cpp +++ b/src/Nazara/Physics3D/RigidBody3D.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include namespace Nz @@ -31,6 +32,7 @@ namespace Nz m_body = NewtonCreateDynamicBody(m_world->GetHandle(), m_geom->GetHandle(m_world), m_matrix); NewtonBodySetUserData(m_body, this); + NewtonBodySetTransformCallback(m_body, &TransformCallback); } RigidBody3D::RigidBody3D(const RigidBody3D& object) : @@ -47,6 +49,7 @@ namespace Nz m_body = NewtonCreateDynamicBody(m_world->GetHandle(), m_geom->GetHandle(m_world), m_matrix); NewtonBodySetUserData(m_body, this); + NewtonBodySetTransformCallback(m_body, &TransformCallback); SetMass(object.m_mass); SetAngularDamping(object.GetAngularDamping()); @@ -293,16 +296,27 @@ namespace Nz void RigidBody3D::SetMass(float mass) { + NazaraAssert(mass >= 0.f, "Mass must be positive and finite"); + NazaraAssert(std::isfinite(mass), "Mass must be positive and finite"); + if (m_mass > 0.f) { - // If we already have a mass, we already have an inertial matrix as well, just rescale it - float Ix, Iy, Iz; - NewtonBodyGetMassMatrix(m_body, &m_mass, &Ix, &Iy, &Iz); + if (mass > 0.f) + { + // If we already have a mass, we already have an inertial matrix as well, just rescale it + float Ix, Iy, Iz; + NewtonBodyGetMassMatrix(m_body, &m_mass, &Ix, &Iy, &Iz); - float scale = mass/m_mass; - NewtonBodySetMassMatrix(m_body, mass, Ix*scale, Iy*scale, Iz*scale); + float scale = mass / m_mass; + NewtonBodySetMassMatrix(m_body, mass, Ix*scale, Iy*scale, Iz*scale); + } + else + { + NewtonBodySetMassMatrix(m_body, 0.f, 0.f, 0.f, 0.f); + NewtonBodySetForceAndTorqueCallback(m_body, nullptr); + } } - else if (mass > 0.f) + else { Vector3f inertia, origin; m_geom->ComputeInertialMatrix(&inertia, &origin); @@ -310,7 +324,6 @@ namespace Nz NewtonBodySetCentreOfMass(m_body, &origin.x); NewtonBodySetMassMatrix(m_body, mass, inertia.x*mass, inertia.y*mass, inertia.z*mass); NewtonBodySetForceAndTorqueCallback(m_body, &ForceAndTorqueCallback); - NewtonBodySetTransformCallback(m_body, &TransformCallback); } m_mass = mass;