]> git.tdb.fi Git - libs/game.git/commitdiff
Add components for defining joints between rigid bodies
authorMikko Rasa <tdb@tdb.fi>
Tue, 15 Apr 2025 21:54:13 +0000 (00:54 +0300)
committerMikko Rasa <tdb@tdb.fi>
Tue, 15 Apr 2025 21:58:38 +0000 (00:58 +0300)
source/game/joint.h [new file with mode: 0644]
source/game/physicssystem.cpp
source/game/physicssystem.h
source/game/weld.h [new file with mode: 0644]

diff --git a/source/game/joint.h b/source/game/joint.h
new file mode 100644 (file)
index 0000000..61eb120
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef MSP_GAME_JOINT_H_
+#define MSP_GAME_JOINT_H_
+
+#include "component.h"
+#include "mspgame_api.h"
+
+namespace Msp::Game {
+
+class RigidBody;
+
+class MSPGAME_API Joint: public Component
+{
+protected:
+       Handle<RigidBody> target;
+
+       Joint(Handle<Entity> e, Handle<RigidBody> t): Component(e), target(t) { }
+
+public:
+       Handle<RigidBody> get_target() const { return target; }
+};
+
+} // namespace Msp::Game
+
+#endif
index 49d8a703462fd8a56c9b6c98244b5369dc094c3e..be670371a342b875846bf7fe81103d9b95db291f 100644 (file)
@@ -1,10 +1,13 @@
 #include "physicssystem.h"
+#include <msp/physics/fixedconstraint.h>
 #include "entity.h"
+#include "joint.h"
 #include "motion.h"
 #include "rigidbody.h"
 #include "shape.h"
 #include "transform.h"
 #include "transformpropagator.h"
+#include "weld.h"
 
 using namespace std;
 
@@ -35,6 +38,7 @@ PhysicsSystem::PhysicsSystem(Stage &s):
        declare_dependency<RigidBody>(READ_FRESH);
 
        monitor.set_changed_callback([this](auto &b){ simulated_rigid_body_changed(b); });
+       event_observer.observe<Events::ComponentCreated>([this](auto &e){ component_created(e); });
 
        world.set_contact_callback([this](const auto &... a){ on_collision(a...); });
 }
@@ -55,7 +59,7 @@ void PhysicsSystem::simulated_rigid_body_changed(SimulatedRigidBody &body)
 {
        if(body.body && body.shape && !body.physics_body && !body.pending_create)
        {
-               pending.push_back(body.entity);
+               pending_bodies.push_back(body.entity);
                body.pending_create = true;
        }
        else if(body.physics_body && !body.body)
@@ -66,10 +70,29 @@ void PhysicsSystem::simulated_rigid_body_changed(SimulatedRigidBody &body)
        }
 }
 
+void PhysicsSystem::component_created(const Events::ComponentCreated &event)
+{
+       if(Handle<Joint> joint = dynamic_handle_cast<Joint>(event.component))
+       {
+               auto i = lower_bound_member(joints, joint, &SimulatedJoint::joint);
+               joints.emplace(i, joint);
+               pending_joints.push_back(joint);
+       }
+}
+
+void PhysicsSystem::component_destroyed(const Events::ComponentDestroyed &event)
+{
+       if(Handle<Joint> joint = dynamic_handle_cast<Joint>(event.component))
+       {
+               auto i = lower_bound_member(joints, joint, &SimulatedJoint::joint);
+               if(i!=joints.end() && i->joint==joint)
+                       joints.erase(i);
+       }
+}
 
 void PhysicsSystem::early_tick()
 {
-       for(Handle<Entity> e: pending)
+       for(Handle<Entity> e: pending_bodies)
                if(SimulatedRigidBody *srb = lookup_member(rigid_bodies, e, &SimulatedRigidBody::entity))
                {
                        if(srb->body && srb->shape && !srb->physics_body)
@@ -95,7 +118,18 @@ void PhysicsSystem::early_tick()
 
                        srb->pending_create = false;
                }
-       pending.clear();
+       pending_bodies.clear();
+
+       for(Handle<Joint> j: pending_joints)
+               if(SimulatedJoint *sj = lookup_member(joints, j, &SimulatedJoint::joint))
+                       if(!sj->constraint)
+                       {
+                               if(SimulatedRigidBody *srb1 = lookup_member(rigid_bodies, sj->joint->get_entity(), &SimulatedRigidBody::entity))
+                                       if(SimulatedRigidBody *srb2 = lookup_member(rigid_bodies, sj->joint->get_target()->get_entity(), &SimulatedRigidBody::entity))
+                                               if(Handle<Weld> weld = dynamic_handle_cast<Weld>(sj->joint))
+                                                       sj->constraint = make_unique<Physics::FixedConstraint>(world, *srb1->physics_body, *srb2->physics_body);
+                       }
+       pending_joints.clear();
 }
 
 void PhysicsSystem::tick(Time::TimeDelta dt)
index 1826e97668a93a5942041ba2d3c58a9c9eb6cb8b..c9156625c5a21b864fffa2d4ccfbc78f0dd0d14a 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef MSP_GAME_PHYSICSSYSTEM_H_
 #define MSP_GAME_PHYSICSSYSTEM_H_
 
+#include <msp/physics/constraint.h>
 #include <msp/physics/rigidbody.h>
 #include <msp/physics/world.h>
 #include "archetype.h"
@@ -10,6 +11,7 @@
 namespace Msp::Game {
 
 class Entity;
+class Joint;
 class Motion;
 class RigidBody;
 class Shape;
@@ -46,6 +48,12 @@ private:
                SimulatedRigidBody(Handle<Entity> e): entity(e) { }
        };
 
+       struct SimulatedJoint
+       {
+               Handle<Joint> joint;
+               std::unique_ptr<Physics::Constraint> constraint;
+       };
+
        struct Collider
        {
                const Physics::RigidBody *physics_body = nullptr;
@@ -58,9 +66,12 @@ private:
 
        std::vector<SimulatedRigidBody> rigid_bodies;
        std::vector<Collider> collider_lookup;
-       std::vector<Handle<Entity>> pending;
+       std::vector<Handle<Entity>> pending_bodies;
        ArchetypeMonitor<SimulatedRigidBody> monitor;
 
+       std::vector<SimulatedJoint> joints;
+       std::vector<Handle<Joint>> pending_joints;
+
        std::vector<Events::Collision> collision_queue;
        Mutex collision_mutex;
 
@@ -71,6 +82,8 @@ public:
 
 private:
        void simulated_rigid_body_changed(SimulatedRigidBody &);
+       void component_created(const Events::ComponentCreated &);
+       void component_destroyed(const Events::ComponentDestroyed &);
 
 public:
        void early_tick() override;
diff --git a/source/game/weld.h b/source/game/weld.h
new file mode 100644 (file)
index 0000000..6d2beab
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef MSP_GAME_WELD_H_
+#define MSP_GAME_WELD_H_
+
+#include "joint.h"
+#include "mspgame_api.h"
+
+namespace Msp::Game {
+
+class MSPGAME_API Weld: public Joint
+{
+public:
+       Weld(Handle<Entity> e, Handle<RigidBody> b): Joint(e, b) { }
+};
+
+} // namespace Msp::Game
+
+#endif