diff --git a/ChangeLog.md b/ChangeLog.md index 8be3f7553..2909afceb 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -169,6 +169,8 @@ Nazara Engine: - Fixed TileMap not rendering the right materials if it had no tile using some materials in-between - Added Vector[2|3|4](u)i64 typedefs - Fixed missing static Vector4::DotProduct implementation +- ⚠ **By default, Nazara computes the mass center of all 2D physics object when calling SetGeom** +- ⚠ Added Collider2D::ComputeCenterOfMass Nazara Development Kit: - Added ImageWidget (#139) diff --git a/include/Nazara/Physics2D/Collider2D.hpp b/include/Nazara/Physics2D/Collider2D.hpp index 8b69bd780..cc2f62eac 100644 --- a/include/Nazara/Physics2D/Collider2D.hpp +++ b/include/Nazara/Physics2D/Collider2D.hpp @@ -41,6 +41,7 @@ namespace Nz Collider2D(Collider2D&&) = delete; virtual ~Collider2D(); + virtual Nz::Vector2f ComputeCenterOfMass() const = 0; virtual float ComputeMomentOfInertia(float mass) const = 0; inline UInt32 GetCategoryMask() const; @@ -99,6 +100,7 @@ namespace Nz BoxCollider2D(const Vector2f& size, float radius = 0.f); BoxCollider2D(const Rectf& rect, float radius = 0.f); + Nz::Vector2f ComputeCenterOfMass() const override; float ComputeMomentOfInertia(float mass) const override; inline float GetRadius() const; @@ -125,6 +127,7 @@ namespace Nz public: CircleCollider2D(float radius, const Vector2f& offset = Vector2f::Zero()); + Nz::Vector2f ComputeCenterOfMass() const override; float ComputeMomentOfInertia(float mass) const override; inline const Vector2f& GetOffset() const; @@ -150,6 +153,7 @@ namespace Nz public: CompoundCollider2D(std::vector geoms); + Nz::Vector2f ComputeCenterOfMass() const override; float ComputeMomentOfInertia(float mass) const override; inline bool DoesOverrideCollisionProperties() const; @@ -179,6 +183,7 @@ namespace Nz public: ConvexCollider2D(SparsePtr vertices, std::size_t vertexCount, float radius = 0.f); + Nz::Vector2f ComputeCenterOfMass() const override; float ComputeMomentOfInertia(float mass) const override; ColliderType2D GetType() const override; @@ -203,6 +208,7 @@ namespace Nz public: NullCollider2D() = default; + Nz::Vector2f ComputeCenterOfMass() const override; float ComputeMomentOfInertia(float mass) const override; ColliderType2D GetType() const override; @@ -223,6 +229,7 @@ namespace Nz public: inline SegmentCollider2D(const Vector2f& first, const Vector2f& second, float thickness = 1.f); + Nz::Vector2f ComputeCenterOfMass() const override; float ComputeMomentOfInertia(float mass) const override; inline const Vector2f& GetFirstPoint() const; diff --git a/include/Nazara/Physics2D/RigidBody2D.hpp b/include/Nazara/Physics2D/RigidBody2D.hpp index aa5664978..be90acc92 100644 --- a/include/Nazara/Physics2D/RigidBody2D.hpp +++ b/include/Nazara/Physics2D/RigidBody2D.hpp @@ -82,7 +82,7 @@ namespace Nz void SetElasticity(std::size_t shapeIndex, float elasticity); void SetFriction(float friction); void SetFriction(std::size_t shapeIndex, float friction); - void SetGeom(Collider2DRef geom, bool recomputeMoment = true); + void SetGeom(Collider2DRef geom, bool recomputeMoment = true, bool recomputeMassCenter = true); void SetMass(float mass, bool recomputeMoment = true); void SetMassCenter(const Vector2f& center, CoordSys coordSys = CoordSys_Local); void SetMomentOfInertia(float moment); diff --git a/src/Nazara/Physics2D/Collider2D.cpp b/src/Nazara/Physics2D/Collider2D.cpp index 0be746838..75f5fe332 100644 --- a/src/Nazara/Physics2D/Collider2D.cpp +++ b/src/Nazara/Physics2D/Collider2D.cpp @@ -20,7 +20,7 @@ namespace Nz { cpShape* shape = (*shapes)[i]; - cpShapeSetCollisionType(shape, cpFloat(m_collisionId)); + cpShapeSetCollisionType(shape, m_collisionId); cpShapeSetElasticity(shape, cpFloat(m_elasticity)); cpShapeSetFilter(shape, filter); cpShapeSetFriction(shape, cpFloat(m_friction)); @@ -44,6 +44,11 @@ namespace Nz { } + Nz::Vector2f BoxCollider2D::ComputeCenterOfMass() const + { + return m_rect.GetCenter(); + } + float BoxCollider2D::ComputeMomentOfInertia(float mass) const { return static_cast(cpMomentForBox2(mass, cpBBNew(m_rect.x, m_rect.y, m_rect.x + m_rect.width, m_rect.y + m_rect.height))); @@ -68,6 +73,11 @@ namespace Nz { } + Nz::Vector2f CircleCollider2D::ComputeCenterOfMass() const + { + return m_offset + Nz::Vector2f(m_radius, m_radius); + } + float CircleCollider2D::ComputeMomentOfInertia(float mass) const { return static_cast(cpMomentForCircle(mass, 0.f, m_radius, cpv(m_offset.x, m_offset.y))); @@ -92,6 +102,15 @@ namespace Nz { } + Nz::Vector2f CompoundCollider2D::ComputeCenterOfMass() const + { + Nz::Vector2f centerOfMass = Nz::Vector2f::Zero(); + for (const auto& geom : m_geoms) + centerOfMass += geom->ComputeCenterOfMass(); + + return centerOfMass / float(m_geoms.size()); + } + float CompoundCollider2D::ComputeMomentOfInertia(float mass) const { ///TODO: Correctly compute moment using parallel axis theorem: @@ -144,6 +163,15 @@ namespace Nz m_vertices[i].Set(*vertices++); } + Nz::Vector2f ConvexCollider2D::ComputeCenterOfMass() const + { + static_assert(sizeof(cpVect) == sizeof(Vector2d), "Chipmunk vector is not equivalent to Vector2d"); + + cpVect center = cpCentroidForPoly(int(m_vertices.size()), reinterpret_cast(m_vertices.data())); + + return Nz::Vector2f(float(center.x), float(center.y)); + } + float ConvexCollider2D::ComputeMomentOfInertia(float mass) const { static_assert(sizeof(cpVect) == sizeof(Vector2d), "Chipmunk vector is not equivalent to Vector2d"); @@ -169,6 +197,11 @@ namespace Nz return ColliderType2D_Null; } + Nz::Vector2f NullCollider2D::ComputeCenterOfMass() const + { + return Nz::Vector2f::Zero(); + } + float NullCollider2D::ComputeMomentOfInertia(float mass) const { return (mass > 0.f) ? 1.f : 0.f; //< Null inertia is only possible for static/kinematic objects @@ -181,6 +214,11 @@ namespace Nz /******************************** SegmentCollider2D *********************************/ + Nz::Vector2f SegmentCollider2D::ComputeCenterOfMass() const + { + return (m_first + m_second) / 2.f; + } + float SegmentCollider2D::ComputeMomentOfInertia(float mass) const { return static_cast(cpMomentForSegment(mass, cpv(m_first.x, m_first.y), cpv(m_second.x, m_second.y), m_thickness)); diff --git a/src/Nazara/Physics2D/RigidBody2D.cpp b/src/Nazara/Physics2D/RigidBody2D.cpp index 88fd792f8..cc181930f 100644 --- a/src/Nazara/Physics2D/RigidBody2D.cpp +++ b/src/Nazara/Physics2D/RigidBody2D.cpp @@ -48,7 +48,7 @@ namespace Nz NazaraAssert(m_geom, "Invalid geometry"); m_handle = Create(m_mass, object.GetMomentOfInertia()); - SetGeom(object.GetGeom(), false); + SetGeom(object.GetGeom(), false, false); CopyBodyData(object.GetHandle(), m_handle); @@ -362,7 +362,7 @@ namespace Nz cpShapeSetFriction(m_shapes[shapeIndex], cpFloat(friction)); } - void RigidBody2D::SetGeom(Collider2DRef geom, bool recomputeMoment) + void RigidBody2D::SetGeom(Collider2DRef geom, bool recomputeMoment, bool recomputeMassCenter) { // We have no public way of getting rid of an existing geom without removing the whole body // So let's save some attributes of the body, destroy it and rebuild it @@ -399,6 +399,9 @@ namespace Nz if (!IsStatic() && !IsKinematic()) cpBodySetMoment(m_handle, m_geom->ComputeMomentOfInertia(m_mass)); } + + if (recomputeMassCenter) + SetMassCenter(m_geom->ComputeCenterOfMass()); } void RigidBody2D::SetMass(float mass, bool recomputeMoment)