From 662ccbd5d00bc0b3ce28e8fa56535299109ddf61 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 19 Jan 2019 02:31:29 +0100 Subject: [PATCH] Physics2D/RigidBody2D: Add possibility to setup a custom velocity function --- ChangeLog.md | 1 + .../NDK/Components/PhysicsComponent2D.hpp | 8 +++ .../NDK/Components/PhysicsComponent2D.inl | 59 ++++++++++++++++++- include/Nazara/Physics2D/RigidBody2D.hpp | 11 ++++ src/Nazara/Physics2D/RigidBody2D.cpp | 35 +++++++++++ 5 files changed, 113 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 7ad72fb66..ba7748cda 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -159,6 +159,7 @@ Nazara Engine: - Fixed LuaCoroutine movement assignation operator - Added Arbiter2D::GetBodies - Added RigidBody2D::ForEachArbiter +- Added possibility to change the RigidBody2D velocity function called by the physics engine Nazara Development Kit: - Added ImageWidget (#139) diff --git a/SDK/include/NDK/Components/PhysicsComponent2D.hpp b/SDK/include/NDK/Components/PhysicsComponent2D.hpp index 38a8c0608..63abb6c40 100644 --- a/SDK/include/NDK/Components/PhysicsComponent2D.hpp +++ b/SDK/include/NDK/Components/PhysicsComponent2D.hpp @@ -24,6 +24,8 @@ namespace Ndk friend class ConstraintComponent2D; public: + using VelocityFunc = Nz::RigidBody2D::VelocityFunc; + PhysicsComponent2D(); PhysicsComponent2D(const PhysicsComponent2D& physics); ~PhysicsComponent2D() = default; @@ -55,10 +57,13 @@ namespace Ndk inline Nz::Vector2f GetSurfaceVelocity(std::size_t shapeIndex = 0) const; inline std::size_t GetShapeCount() const; inline Nz::Vector2f GetVelocity() const; + const VelocityFunc& GetVelocityFunction() const; inline bool IsNodeSynchronizationEnabled() const; inline bool IsSleeping() const; + inline void ResetVelocityFunction(); + inline void SetAngularDamping(float angularDamping); inline void SetAngularVelocity(const Nz::RadianAnglef& angularVelocity); inline void SetElasticity(float elasticity); @@ -73,6 +78,9 @@ namespace Ndk inline void SetSurfaceVelocity(const Nz::Vector2f& velocity); inline void SetSurfaceVelocity(std::size_t shapeIndex, const Nz::Vector2f& velocity); inline void SetVelocity(const Nz::Vector2f& velocity); + inline void SetVelocityFunction(VelocityFunc velocityFunc); + + inline void UpdateVelocity(const Nz::Vector2f& gravity, float damping, float deltaTime); static ComponentIndex componentIndex; diff --git a/SDK/include/NDK/Components/PhysicsComponent2D.inl b/SDK/include/NDK/Components/PhysicsComponent2D.inl index 74de89e65..6a4ae478a 100644 --- a/SDK/include/NDK/Components/PhysicsComponent2D.inl +++ b/SDK/include/NDK/Components/PhysicsComponent2D.inl @@ -338,7 +338,6 @@ namespace Ndk * * \remark Produces a NazaraAssert if the physics object is invalid */ - inline Nz::Vector2f PhysicsComponent2D::GetVelocity() const { NazaraAssert(m_object, "Invalid physics object"); @@ -346,6 +345,19 @@ namespace Ndk return m_object->GetVelocity(); } + /*! + * \brief Gets the custom velocity function of the physics object + * \return Velocity function of the object (may be empty if default function is used) + * + * \remark Produces a NazaraAssert if the physics object is invalid + */ + inline auto PhysicsComponent2D::GetVelocityFunction() const -> const VelocityFunc& + { + NazaraAssert(m_object, "Invalid physics object"); + + return m_object->GetVelocityFunction(); + } + /*! * \brief Checks if position & rotation are synchronized with NodeComponent * \return true If synchronization is enabled @@ -370,6 +382,18 @@ namespace Ndk return m_object->IsSleeping(); } + /*! + * \brief Reset velocity function to default one + * + * \remark Produces a NazaraAssert if the physics object is invalid + */ + inline void PhysicsComponent2D::ResetVelocityFunction() + { + NazaraAssert(m_object, "Invalid physics object"); + + return m_object->ResetVelocityFunction(); + } + /*! * \brief Sets the angular damping or moment of inertia of the physics object * @@ -580,6 +604,39 @@ namespace Ndk m_object->SetVelocity(velocity); } + /*! + * \brief Sets a custom velocity function for the physics object + * + * A velocity function is called (for non-kinematic and non-static objects) at every physics update to compute the new velocity of the object. + * You may call UpdateVelocity (the default velocity function) to let the physics engine compute that itself and then adjust it using GetVelocity/SetVelocity as you need. + * + * \param velocityFunc New custom velocity function + * + * \remark Passing an empty VelocityFunc has the same effect as calling ResetVelocityFunction + * \see ResetVelocityFunction + * \see UpdateVelocity + */ + inline void PhysicsComponent2D::SetVelocityFunction(VelocityFunc velocityFunc) + { + NazaraAssert(m_object, "Invalid physics object"); + + m_object->SetVelocityFunction(std::move(velocityFunc)); + } + + /*! + * \brief Calls the physics engine default velocity function + * + * \param gravity Physics system gravity + * \param damping Physics system damping (adjusted to deltaTime) + * \param deltaTime Elapsed time since last physics update + */ + inline void PhysicsComponent2D::UpdateVelocity(const Nz::Vector2f& gravity, float damping, float deltaTime) + { + NazaraAssert(m_object, "Invalid physics object"); + + m_object->UpdateVelocity(gravity, damping, deltaTime); + } + /*! * \brief Gets the underlying physics object * \return A reference to the physics object diff --git a/include/Nazara/Physics2D/RigidBody2D.hpp b/include/Nazara/Physics2D/RigidBody2D.hpp index da5646fb0..aa5664978 100644 --- a/include/Nazara/Physics2D/RigidBody2D.hpp +++ b/include/Nazara/Physics2D/RigidBody2D.hpp @@ -14,17 +14,21 @@ #include #include #include +#include #include struct cpBody; namespace Nz { + class Arbiter2D; class PhysWorld2D; class NAZARA_PHYSICS2D_API RigidBody2D { public: + using VelocityFunc = std::function; + RigidBody2D(PhysWorld2D* world, float mass); RigidBody2D(PhysWorld2D* world, float mass, Collider2DRef geom); RigidBody2D(const RigidBody2D& object); @@ -62,6 +66,7 @@ namespace Nz Vector2f GetSurfaceVelocity(std::size_t shapeIndex = 0) const; void* GetUserdata() const; Vector2f GetVelocity() const; + const VelocityFunc& GetVelocityFunction() const; PhysWorld2D* GetWorld() const; bool IsKinematic() const; @@ -69,6 +74,8 @@ namespace Nz bool IsSleeping() const; bool IsStatic() const; + void ResetVelocityFunction(); + inline void SetAngularDamping(float angularDamping); void SetAngularVelocity(const RadianAnglef& angularVelocity); void SetElasticity(float elasticity); @@ -86,6 +93,9 @@ namespace Nz void SetStatic(bool setStaticBody = true); void SetUserdata(void* ud); void SetVelocity(const Vector2f& velocity); + void SetVelocityFunction(VelocityFunc velocityFunc); + + void UpdateVelocity(const Nz::Vector2f& gravity, float damping, float deltaTime); RigidBody2D& operator=(const RigidBody2D& object); RigidBody2D& operator=(RigidBody2D&& object); @@ -104,6 +114,7 @@ namespace Nz static void CopyBodyData(cpBody* from, cpBody* to); static void CopyShapeData(cpShape* from, cpShape* to); + VelocityFunc m_velocityFunc; std::vector m_shapes; Collider2DRef m_geom; cpBody* m_handle; diff --git a/src/Nazara/Physics2D/RigidBody2D.cpp b/src/Nazara/Physics2D/RigidBody2D.cpp index 1f4ca07a4..88fd792f8 100644 --- a/src/Nazara/Physics2D/RigidBody2D.cpp +++ b/src/Nazara/Physics2D/RigidBody2D.cpp @@ -296,6 +296,11 @@ namespace Nz return Vector2f(static_cast(vel.x), static_cast(vel.y)); } + const RigidBody2D::VelocityFunc& RigidBody2D::GetVelocityFunction() const + { + return m_velocityFunc; + } + PhysWorld2D* RigidBody2D::GetWorld() const { return m_world; @@ -321,6 +326,11 @@ namespace Nz return m_isStatic; } + void RigidBody2D::ResetVelocityFunction() + { + m_handle->velocity_func = cpBodyUpdateVelocity; + } + void RigidBody2D::SetAngularVelocity(const RadianAnglef& angularVelocity) { cpBodySetAngularVelocity(m_handle, angularVelocity.value); @@ -516,6 +526,30 @@ namespace Nz cpBodySetVelocity(m_handle, cpv(velocity.x, velocity.y)); } + void RigidBody2D::SetVelocityFunction(VelocityFunc velocityFunc) + { + m_velocityFunc = std::move(velocityFunc); + + if (m_velocityFunc) + { + m_handle->velocity_func = [](cpBody* body, cpVect gravity, cpFloat damping, cpFloat dt) + { + RigidBody2D* rigidBody = static_cast(cpBodyGetUserData(body)); + const auto& callback = rigidBody->GetVelocityFunction(); + assert(callback); + + callback(*rigidBody, Nz::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) + { + cpBodyUpdateVelocity(m_handle, cpv(gravity.x, gravity.y), damping, deltaTime); + } + RigidBody2D& RigidBody2D::operator=(const RigidBody2D& object) { RigidBody2D physObj(object); @@ -538,6 +572,7 @@ namespace Nz m_mass = object.m_mass; m_shapes = std::move(object.m_shapes); m_userData = object.m_userData; + m_velocityFunc = std::move(object.m_velocityFunc); m_world = object.m_world; cpBodySetUserData(m_handle, this);