PhysicsSystem::PhysicsSystem(Stage &s):
System(s),
+ event_source(stage.get_event_bus()),
event_observer(stage.get_event_bus()),
world(stage.get_threads()),
monitor(event_observer, rigid_bodies)
declare_dependency<RigidBody>(READ_FRESH);
monitor.set_changed_callback([this](auto &b){ simulated_rigid_body_changed(b); });
+
+ world.set_contact_callback([this](const auto &... a){ on_collision(a...); });
}
RaycastHit PhysicsSystem::cast_ray(const Geometry::Ray<float, 3> &ray)
Handle<Transform> transform = srb->entity->get_transform();
Physics::MotionType motion = (srb->motion ? Physics::DYNAMIC : Physics::STATIC);
srb->physics_body = make_unique<Physics::RigidBody>(world, srb->shape->get_shape(), transform->get_position(), transform->get_rotation(), motion);
+ srb->physics_body->set_report_contacts(srb->body->reports_collisions());
unsigned layer = (motion==Physics::STATIC ? CollisionLayer::STATIC : CollisionLayer::MOVING);
uint32_t collision_mask = (1<<CollisionLayer::STATIC) | (1<<CollisionLayer::MOVING);
collision_mask |= 1<<CollisionLayer::RAYCAST;
srb->physics_body->set_collisions(layer, collision_mask);
- if(srb->shape->is_raycast_target())
+ if(srb->body->reports_collisions() || srb->shape->is_raycast_target())
{
auto j = lower_bound_member(collider_lookup, srb->physics_body.get(), &Collider::physics_body);
collider_lookup.emplace(j, srb->physics_body.get(), srb->shape);
b.motion_generation = b.motion->get_write_generation();
}
}
+
+ for(const Events::Collision &c: collision_queue)
+ event_source.emit<Events::Collision>(c);
+ collision_queue.clear();
+}
+
+void PhysicsSystem::on_collision(const Physics::RigidBody &body1, const Physics::RigidBody &body2, const LinAl::Vector<float, 3> &pos)
+{
+ if(Collider *c1 = lookup_member(collider_lookup, &body1, &Collider::physics_body))
+ if(Collider *c2 = lookup_member(collider_lookup, &body2, &Collider::physics_body))
+ {
+ MutexLock lock(collision_mutex);
+ collision_queue.emplace_back(c1->shape, c2->shape, pos);
+ }
}
} // namespace Msp::Game
class MSPGAME_API PhysicsSystem: public System
{
+public:
+ using EventSource = Game::EventSource<Events::Collision>;
+
private:
struct SimulatedRigidBody
{
struct Collider
{
- Physics::RigidBody *physics_body = nullptr;
+ const Physics::RigidBody *physics_body = nullptr;
Handle<Shape> shape;
};
+ EventSource event_source;
EventObserver event_observer;
Physics::World world;
+
std::vector<SimulatedRigidBody> rigid_bodies;
std::vector<Collider> collider_lookup;
std::vector<Handle<Entity>> pending;
ArchetypeMonitor<SimulatedRigidBody> monitor;
+ std::vector<Events::Collision> collision_queue;
+ Mutex collision_mutex;
+
public:
PhysicsSystem(Stage &);
public:
void early_tick() override;
void tick(Time::TimeDelta) override;
+
+private:
+ void on_collision(const Physics::RigidBody &, const Physics::RigidBody &, const LinAl::Vector<float, 3> &);
};
} // namespace Msp::Game
#ifndef MSP_GAME_RIGIDBODY_H_
#define MSP_GAME_RIGIDBODY_H_
+#include <msp/game/setups.h>
#include "component.h"
#include "mspgame_api.h"
class MSPGAME_API RigidBody: public BufferedComponent<RigidBodyData>
{
public:
- RigidBody(Handle<Entity> e): BufferedComponent(e) { }
+ using Setup = RigidBodySetup;
+
+private:
+ const Setup &setup;
+
+public:
+ RigidBody(Handle<Entity> e, const Setup &s): BufferedComponent(e), setup(s) { }
void set_kinematic(bool);
bool is_kinematic() const { return read().kinematic; }
+ bool reports_collisions() const { return setup.report_collisions; }
};
} // namespace Msp::Game