{
source "source/game";
require "mspnet";
+ require "mspphysics";
install true;
install_map
{
Stage &Director::create_stage(const string &n)
{
- Stage &stage = *stages.emplace_back(std::make_unique<Stage>(n, reflector, resources));
+ Stage &stage = *stages.emplace_back(std::make_unique<Stage>(n, thread_pool, reflector, resources));
stage.add_system<TransformPropagator>();
event_source.emit<Events::StageCreated>(stage);
return stage;
#include <memory>
#include <optional>
#include <vector>
+#include <msp/core/threadpool.h>
#include <msp/datafile/collection.h>
#include <msp/io/eventdispatcher.h>
#include <msp/time/timedelta.h>
std::optional<AccessGuard> access_guard;
Reflection::Reflector reflector;
DataFile::Collection &resources;
+ ThreadPool thread_pool;
IO::EventDispatcher io_dispatcher;
EventBus event_bus;
EventSource event_source;
--- /dev/null
+#include "motion.h"
+
+namespace Msp::Game {
+
+void Motion::set_values(const MotionValues &v)
+{
+ write() = v;
+}
+
+void Motion::set_linear_velocity(const LinAl::Vector<float, 3> &v)
+{
+ write().linear_velocity = v;
+}
+
+void Motion::set_angular_velocity(const LinAl::Vector<float, 3> &v)
+{
+ write().angular_velocity = v;
+}
+
+} // namespace Msp::Game
--- /dev/null
+#ifndef MSP_GAME_MOTION_H_
+#define MSP_GAME_MOTION_H_
+
+#include <msp/linal/vector.h>
+#include "component.h"
+
+namespace Msp::Game {
+
+struct MSPGAME_API MotionValues
+{
+ LinAl::Vector<float, 3> linear_velocity;
+ LinAl::Vector<float, 3> angular_velocity;
+};
+
+class MSPGAME_API Motion: public BufferedComponent<MotionValues>
+{
+public:
+ Motion(Handle<Entity> e): BufferedComponent(e) { }
+
+ void set_values(const MotionValues &);
+ void set_linear_velocity(const LinAl::Vector<float, 3> &);
+ void set_angular_velocity(const LinAl::Vector<float, 3> &);
+ const MotionValues &get_values() const { return read(); }
+ const LinAl::Vector<float, 3> &get_linear_velocity() const { return read().linear_velocity; }
+ const LinAl::Vector<float, 3> &get_angular_velocity() const { return read().angular_velocity; }
+};
+
+} // namespace Msp::Game
+
+#endif
--- /dev/null
+#include "physicssystem.h"
+#include "entity.h"
+#include "motion.h"
+#include "rigidbody.h"
+#include "shape.h"
+#include "transform.h"
+#include "transformpropagator.h"
+
+using namespace std;
+
+namespace Msp::Game {
+
+PhysicsSystem::PhysicsSystem(Stage &s):
+ System(s),
+ event_observer(stage.get_event_bus()),
+ world(stage.get_threads()),
+ monitor(event_observer, rigid_bodies)
+{
+ declare_dependency<Transform>(CHAINED_UPDATE);
+ declare_dependency<Motion>(CHAINED_UPDATE);
+ declare_dependency<TransformPropagator>(RUN_BEFORE);
+
+ monitor.set_changed_callback([this](auto &b){ simulated_rigid_body_changed(b); });
+}
+
+void PhysicsSystem::simulated_rigid_body_changed(SimulatedRigidBody &body)
+{
+ if(!body.physics_body)
+ {
+ auto i = lower_bound(pending, body.entity);
+ if(i==pending.end() || *i!=body.entity)
+ pending.insert(i, body.entity);
+ }
+}
+
+void PhysicsSystem::early_tick()
+{
+ for(Handle<Entity> e: pending)
+ {
+ auto i = lower_bound_member(rigid_bodies, e, &SimulatedRigidBody::entity);
+ if(i==rigid_bodies.end() || i->entity!=e)
+ continue;
+
+ if(i->body && i->shape && !i->physics_body)
+ {
+ Handle<Transform> transform = i->entity->get_transform();
+ Physics::MotionType motion = (i->motion ? Physics::DYNAMIC : Physics::STATIC);
+ i->physics_body = make_unique<Physics::RigidBody>(world, i->shape->get_shape(), transform->get_position(), transform->get_rotation(), motion);
+ }
+ }
+ pending.clear();
+}
+
+void PhysicsSystem::tick(Time::TimeDelta dt)
+{
+ for(SimulatedRigidBody &b: rigid_bodies)
+ {
+ Handle<Transform> transform = b.entity->get_transform();
+ if(transform->get_read_generation()!=b.transform_generation)
+ {
+ const TransformValues &tv = transform->get_values();
+ b.physics_body->set_transform(tv.position, tv.rotation);
+ }
+ if(b.motion && b.motion->get_read_generation()!=b.motion_generation)
+ {
+ const MotionValues &mv = b.motion->get_values();
+ b.physics_body->set_velocities(mv.linear_velocity, mv.angular_velocity);
+ }
+ }
+
+ world.step(dt/Time::sec);
+
+ for(SimulatedRigidBody &b: rigid_bodies)
+ {
+ Handle<Transform> transform = b.entity->get_transform();
+ transform->set_position(b.physics_body->get_position());
+ transform->set_rotation(b.physics_body->get_rotation());
+ b.transform_generation = transform->get_write_generation();
+ if(b.motion)
+ {
+ b.motion->set_linear_velocity(b.physics_body->get_linear_velocity());
+ b.motion->set_angular_velocity(b.physics_body->get_angular_velocity());
+ b.motion_generation = b.motion->get_write_generation();
+ }
+ }
+}
+
+} // namespace Msp::Game
--- /dev/null
+#ifndef MSP_GAME_PHYSICSSYSTEM_H_
+#define MSP_GAME_PHYSICSSYSTEM_H_
+
+#include <msp/physics/rigidbody.h>
+#include <msp/physics/world.h>
+#include "archetype.h"
+#include "mspgame_api.h"
+#include "system.h"
+
+namespace Msp::Game {
+
+class Entity;
+class Motion;
+class RigidBody;
+class Shape;
+
+class MSPGAME_API PhysicsSystem: public System
+{
+private:
+ struct SimulatedRigidBody
+ {
+ Handle<Entity> entity;
+ Handle<RigidBody> body;
+ Handle<Shape> shape;
+ Handle<Motion> motion;
+ std::unique_ptr<Physics::RigidBody> physics_body;
+ uint8_t transform_generation = 0;
+ uint8_t motion_generation = 0;
+
+ using Components = ArchetypeComponents<&SimulatedRigidBody::body, &SimulatedRigidBody::shape, &SimulatedRigidBody::motion>;
+
+ SimulatedRigidBody(Handle<Entity> e): entity(e) { }
+ };
+
+ EventObserver event_observer;
+ Physics::World world;
+ std::vector<SimulatedRigidBody> rigid_bodies;
+ std::vector<Handle<Entity>> pending;
+ ArchetypeMonitor<SimulatedRigidBody> monitor;
+
+public:
+ PhysicsSystem(Stage &);
+
+private:
+ void simulated_rigid_body_changed(SimulatedRigidBody &);
+
+public:
+ void early_tick() override;
+ void tick(Time::TimeDelta) override;
+};
+
+} // namespace Msp::Game
+
+#endif
--- /dev/null
+#ifndef MSP_GAME_RIGIDBODY_H_
+#define MSP_GAME_RIGIDBODY_H_
+
+#include "component.h"
+#include "mspgame_api.h"
+
+namespace Msp::Game {
+
+class MSPGAME_API RigidBody: public Component
+{
+public:
+ RigidBody(Handle<Entity> e): Component(e) { }
+};
+
+} // namespace Msp::Game
+
+#endif
namespace Msp::Game {
-Stage::Stage(const string &n, Reflection::Reflector &f, DataFile::Collection &r):
+Stage::Stage(const string &n, ThreadPool &t, Reflection::Reflector &f, DataFile::Collection &r):
name(n),
+ threads(t),
reflector(f),
resources(r),
pools(reflector),
#define MSP_GAME_STAGE_H_
#include <memory>
+#include <msp/core/threadpool.h>
#include <msp/datafile/collection.h>
#include <msp/time/timedelta.h>
#include "eventbus.h"
private:
std::string name;
+ ThreadPool &threads;
Reflection::Reflector &reflector;
DataFile::Collection &resources;
PoolPool pools;
bool pending_reschedule = false;
public:
- Stage(const std::string &, Reflection::Reflector &, DataFile::Collection &);
+ Stage(const std::string &, ThreadPool &, Reflection::Reflector &, DataFile::Collection &);
~Stage();
const std::string &get_name() const { return name; }
+ ThreadPool &get_threads() const { return threads; }
Reflection::Reflector &get_reflector() const { return reflector; }
DataFile::Collection &get_resources() const { return resources; }
PoolPool &get_pools() { return pools; }