--- /dev/null
+#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
#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;
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...); });
}
{
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)
}
}
+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)
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)
#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"
namespace Msp::Game {
class Entity;
+class Joint;
class Motion;
class RigidBody;
class Shape;
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;
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;
private:
void simulated_rigid_body_changed(SimulatedRigidBody &);
+ void component_created(const Events::ComponentCreated &);
+ void component_destroyed(const Events::ComponentDestroyed &);
public:
void early_tick() override;