aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLoek Le Blansch <loek@pipeframe.xyz>2024-12-11 16:51:03 +0100
committerLoek Le Blansch <loek@pipeframe.xyz>2024-12-11 16:51:03 +0100
commitf0ecbea57a4d75905c4ee79608807187cd8f3e72 (patch)
tree04a399dc7d400aaa9443be19ce13fd97e5822f95
parentd228d4b3856606ad4395723b2703759a0ebe9832 (diff)
WIP
-rw-r--r--src/crepe/Component.cpp5
-rw-r--r--src/crepe/Component.h8
-rw-r--r--src/crepe/api/LoopManager.cpp35
-rw-r--r--src/crepe/api/LoopManager.h21
-rw-r--r--src/crepe/api/LoopManager.hpp34
-rw-r--r--src/crepe/manager/ComponentManager.h24
-rw-r--r--src/crepe/manager/ReplayManager.h17
-rw-r--r--src/example/replay.cpp45
8 files changed, 141 insertions, 48 deletions
diff --git a/src/crepe/Component.cpp b/src/crepe/Component.cpp
index acfd35c..141e1a8 100644
--- a/src/crepe/Component.cpp
+++ b/src/crepe/Component.cpp
@@ -3,3 +3,8 @@
using namespace crepe;
Component::Component(game_object_id_t id) : game_object_id(id) {}
+
+Component & Component::operator=(const Component &) {
+ return *this;
+}
+
diff --git a/src/crepe/Component.h b/src/crepe/Component.h
index eff5a58..47c5c34 100644
--- a/src/crepe/Component.h
+++ b/src/crepe/Component.h
@@ -32,9 +32,13 @@ protected:
//! Only ComponentManager can create components
friend class ComponentManager;
- Component(const Component &) = delete;
+ // create snapshot
+ Component(const Component &) = default;
+ // restore snapshot
+ virtual Component & operator=(const Component &);
+
+ // components are never moved
Component(Component &&) = delete;
- virtual Component & operator=(const Component &) = delete;
virtual Component & operator=(Component &&) = delete;
public:
diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp
index 637fbe1..ff428fd 100644
--- a/src/crepe/api/LoopManager.cpp
+++ b/src/crepe/api/LoopManager.cpp
@@ -13,18 +13,17 @@
using namespace crepe;
using namespace std;
-LoopManager::LoopManager()
- : systems({
- ScriptSystem{this->mediator},
- PhysicsSystem{this->mediator},
- CollisionSystem{this->mediator},
- AnimatorSystem{this->mediator},
- ParticleSystem{this->mediator},
- RenderSystem{this->mediator},
- InputSystem{this->mediator},
- EventSystem{this->mediator},
- AudioSystem{this->mediator},
- }) { }
+LoopManager::LoopManager() {
+ this->load_system<ScriptSystem>();
+ this->load_system<PhysicsSystem>();
+ this->load_system<CollisionSystem>();
+ this->load_system<AnimatorSystem>();
+ this->load_system<ParticleSystem>();
+ this->load_system<RenderSystem>();
+ this->load_system<InputSystem>();
+ this->load_system<EventSystem>();
+ this->load_system<AudioSystem>();
+}
void LoopManager::start() {
this->setup();
@@ -32,16 +31,16 @@ void LoopManager::start() {
}
void LoopManager::fixed_update() {
- for (System & system : this->systems) {
- if (!system.active) continue;
- system.fixed_update();
+ for (auto & [type, system] : this->systems) {
+ if (!system->active) continue;
+ system->fixed_update();
}
}
void LoopManager::frame_update() {
- for (System & system : this->systems) {
- if (!system.active) continue;
- system.frame_update();
+ for (auto & [type, system] : this->systems) {
+ if (!system->active) continue;
+ system->frame_update();
}
}
diff --git a/src/crepe/api/LoopManager.h b/src/crepe/api/LoopManager.h
index 1183a4d..4b1fc1e 100644
--- a/src/crepe/api/LoopManager.h
+++ b/src/crepe/api/LoopManager.h
@@ -73,15 +73,32 @@ private:
SaveManager save_manager{mediator};
//! SDL context \todo no more singletons!
- SDLContext & sdl_context = SDLContext::get_instance();
+ SDLContext & sdl_context = mediator.sdl_context;
//! Loop timer \todo no more singletons!
LoopTimer & loop_timer = LoopTimer::get_instance();
private:
/**
* \brief Collection of System instances
+ *
+ * This map holds System instances indexed by the system's class typeid. It is filled in the
+ * constructor of \c LoopManager using LoopManager::load_system.
+ */
+ std::unordered_map<std::type_index, std::unique_ptr<System>> systems;
+ /**
+ * \brief Initialize a system
+ * \tparam T System type (must be derivative of \c System)
+ */
+ template <class T>
+ void load_system();
+ /**
+ * \brief Retrieve a reference to ECS system
+ * \tparam T System type
+ * \returns Reference to system instance
+ * \throws std::runtime_error if the System is not initialized
*/
- std::vector<System> systems;
+ template <class T>
+ T & get_system();
};
} // namespace crepe
diff --git a/src/crepe/api/LoopManager.hpp b/src/crepe/api/LoopManager.hpp
index 51afa70..627b281 100644
--- a/src/crepe/api/LoopManager.hpp
+++ b/src/crepe/api/LoopManager.hpp
@@ -1,5 +1,10 @@
#pragma once
+#include <memory>
+#include <cassert>
+#include <format>
+
+#include "../system/System.h"
#include "LoopManager.h"
namespace crepe {
@@ -9,4 +14,33 @@ void LoopManager::add_scene() {
this->scene_manager.add_scene<T>();
}
+template <class T>
+T & LoopManager::get_system() {
+ using namespace std;
+ static_assert(is_base_of<System, T>::value, "get_system must recieve a derivative class of System");
+
+ const type_info & type = typeid(T);
+ if (!this->systems.contains(type))
+ throw runtime_error(format("LoopManager: {} is not initialized", type.name()));
+
+ System * system = this->systems.at(type).get();
+ T * concrete_system = dynamic_cast<T *>(system);
+ assert(concrete_system != nullptr);
+
+ return *concrete_system;
+}
+
+template <class T>
+void LoopManager::load_system() {
+ using namespace std;
+ static_assert(is_base_of<System, T>::value,
+ "load_system must recieve a derivative class of System");
+
+ const type_info & type = typeid(T);
+ if (this->systems.contains(type))
+ throw runtime_error(format("LoopManager: {} is already initialized", type.name()));
+ System * system = new T(this->mediator);
+ this->systems[type] = unique_ptr<System>(system);
+}
+
} // namespace crepe
diff --git a/src/crepe/manager/ComponentManager.h b/src/crepe/manager/ComponentManager.h
index 19a8e81..94fd94f 100644
--- a/src/crepe/manager/ComponentManager.h
+++ b/src/crepe/manager/ComponentManager.h
@@ -21,13 +21,6 @@ class GameObject;
* This class manages all components. It provides methods to add, delete and get components.
*/
class ComponentManager : public Manager {
- // TODO: This relation should be removed! I (loek) believe that the scene manager should
- // create/destroy components because the GameObject's are stored in concrete Scene classes,
- // which will in turn call GameObject's destructor, which will in turn call
- // ComponentManager::delete_components_by_id or something. This is a pretty major change, so
- // here is a comment and temporary fix instead :tada:
- friend class SceneManager;
-
public:
ComponentManager(Mediator & mediator);
~ComponentManager(); // dbg_trace
@@ -49,12 +42,7 @@ public:
const vec2 & position = {0, 0}, double rotation = 0,
double scale = 1);
-protected:
- /**
- * GameObject is used as an interface to add/remove components, and the game programmer is
- * supposed to use it instead of interfacing with the component manager directly.
- */
- friend class GameObject;
+public:
/**
* \brief Add a component to the ComponentManager
*
@@ -154,6 +142,16 @@ public:
template <typename T>
RefVector<T> get_components_by_tag(const std::string & tag) const;
+ struct SnapshotComponent {
+ by_type<by_id_index<std::vector<std::unique_ptr<Component>>>> components;
+ Component component;
+ };
+ struct Snapshot {
+
+ };
+ Snapshot save();
+ void restore(const Snapshot &);
+
private:
/**
* \brief Get object IDs by predicate function
diff --git a/src/crepe/manager/ReplayManager.h b/src/crepe/manager/ReplayManager.h
index 242eae4..c50196c 100644
--- a/src/crepe/manager/ReplayManager.h
+++ b/src/crepe/manager/ReplayManager.h
@@ -1,6 +1,8 @@
#pragma once
#include "Manager.h"
+#include "ComponentManager.h"
+#include <unordered_map>
namespace crepe {
@@ -18,15 +20,18 @@ protected:
void record_frame();
private:
- bool recording;
- struct Recording {
- recording_t id;
- std::vector<Memento> frames;
- };
+ typedef std::vector<ComponentManager::Snapshot> Recording;
+
+ bool recording = false;
+ recording_t current_recording = -1;
+
+
+ std::unordered_map<recording_t, std::unique_ptr<Recording>> memory;
public:
void record_start();
recording_t record_end();
-
+ void play(recording_t handle);
+ void release(recording_t handle);
};
} // namespace crepe
diff --git a/src/example/replay.cpp b/src/example/replay.cpp
index 6b1ed46..a3c7fba 100644
--- a/src/example/replay.cpp
+++ b/src/example/replay.cpp
@@ -1,4 +1,4 @@
-#include "util/OptionalRef.h"
+#include <crepe/util/OptionalRef.h>
#include <crepe/api/BoxCollider.h>
#include <crepe/api/Camera.h>
#include <crepe/api/Color.h>
@@ -13,6 +13,7 @@
#include <crepe/api/Transform.h>
#include <crepe/manager/ComponentManager.h>
#include <crepe/manager/Mediator.h>
+#include <crepe/manager/ReplayManager.h>
using namespace crepe;
using namespace std;
@@ -22,27 +23,55 @@ class AnimationScript : public Script {
float t = 0;
void init() {
- Log::logf("AnimationScript init");
transform = &get_component<Transform>();
}
void update() {
- Log::logf("AnimationScript update");
- t += 0.01;
+ t += 0.05;
transform->position = { sin(t), cos(t) };
}
};
+class Timeline : public Script {
+ unsigned i = 0;
+ OptionalRef<ReplayManager> mgr;
+ recording_t recording;
+ void update() {
+ ReplayManager & mgr = this->mgr;
+ switch (i++) {
+ default: break;
+ case 10:
+ mgr.record_start();
+ Log::logf("start");
+ break;
+ case 60:
+ this->recording = mgr.record_end();
+ Log::logf("stop");
+ break;
+ case 70:
+ mgr.play(this->recording);
+ Log::logf("play");
+ break;
+ case 71:
+ mgr.release(this->recording);
+ Log::logf("end");
+ break;
+ case 72:
+ Log::logf("exit");
+ throw;
+ break;
+ };
+ }
+};
+
class TestScene : public Scene {
public:
using Scene::Scene;
void load_scene() {
- Log::logf("Initializing scene...");
Mediator & m = this->mediator;
ComponentManager & mgr = m.component_manager;
-
GameObject cam = mgr.new_object("cam");
cam.add_component<Camera>(ivec2{640,480},vec2{3,3}, Camera::Data{
.bg_color = Color::WHITE,
@@ -54,7 +83,9 @@ public:
.size = { 0.5, 0.5 },
});
square.add_component<BehaviorScript>().set_script<AnimationScript>();
- Log::logf("Done initializing scene");
+
+ GameObject scapegoat = mgr.new_object("");
+ scapegoat.add_component<BehaviorScript>().set_script<Timeline>();
}
string get_name() const { return "scene1"; }