Bomberman
Wal.hpp
Go to the documentation of this file.
1 //
2 // Created by Zoe Roux on 2021-05-14.
3 //
4 
5 
6 #pragma once
7 
8 #include <utility>
9 #include <vector>
10 #include <string>
11 #include <memory>
12 #include <typeinfo>
13 #include "Exception/WalError.hpp"
14 #include "System/ISystem.hpp"
15 #include "Models/Callback.hpp"
16 #include "Scene/Scene.hpp"
17 
18 #if defined(PLATFORM_WEB)
19 #include <emscripten/emscripten.h>
20 #endif
21 
22 namespace WAL
23 {
24  class Entity;
25 
27  class Wal
28  {
29  private:
31  std::vector<std::unique_ptr<ISystem>> _systems = {};
32 
34  std::shared_ptr<Scene> _scene;
35 
40  template<typename T>
41  void _run(const Callback<Wal &, T &> &callback, T state = T())
42  {
43  auto lastTick = std::chrono::steady_clock::now();
44  std::chrono::nanoseconds fBehind(0);
45 
46  while (!this->shouldClose) {
47  auto now = std::chrono::steady_clock::now();
48  std::chrono::nanoseconds dtime = now - lastTick;
49  fBehind += dtime;
50  lastTick = now;
51 
52  while (fBehind > Wal::timestep) {
53  fBehind -= Wal::timestep;
54  for (auto &system : this->_systems)
55  system->fixedUpdate();
56  }
57  for (auto &system : this->_systems)
58  system->update(dtime);
59  this->_scene->applyChanges();
60  callback(*this, state);
61  }
62  }
63 
64 #if defined(PLATFORM_WEB)
65  template<typename T>
66  static void _runIteration(void *param)
67  {
68  static auto [wal, callback, state] = *reinterpret_cast<std::tuple<Wal &, const Callback<Wal &, T &> &, T &> *>(param);
69  static auto lastTick = std::chrono::steady_clock::now();
70  static std::chrono::nanoseconds fBehind(0);
71 
72  auto now = std::chrono::steady_clock::now();
73  std::chrono::nanoseconds dtime = now - lastTick;
74  fBehind += dtime;
75  lastTick = now;
76  while (fBehind > Wal::timestep) {
77  fBehind -= Wal::timestep;
78  for (auto &system : wal._systems)
79  system->fixedUpdate();
80  }
81  for (auto &system : wal._systems)
82  system->update(dtime);
83  wal._scene->applyChanges();
84  callback(wal, state);
85  }
86 #endif
87  public:
89  bool shouldClose = false;
91  static constexpr std::chrono::nanoseconds timestep = std::chrono::milliseconds(32);
92 
94  std::shared_ptr<Scene> getScene() const
95  {
96  return this->_scene;
97  }
98 
100  void changeScene(std::shared_ptr<Scene> newScene)
101  {
102  if (this->_scene) {
103  for (auto &entity : this->_scene->getEntities()) {
104  for (auto &cmp : entity._components)
105  cmp.second->onStop();
106  }
107  }
108  this->_scene = std::move(newScene);
109  for (auto &entity : this->_scene->getEntities()) {
110  for (auto &cmp : entity._components)
111  cmp.second->onStart();
112  }
113  }
114 
117  template<typename T, class ...Types>
118  Wal &addSystem(Types &&...params)
119  {
120  const std::type_info &type = typeid(T);
121  auto existing = std::find_if(this->_systems.begin(), this->_systems.end(), [&type] (auto &sys) {
122  return typeid(*sys) == type;
123  });
124  if (existing != this->_systems.end())
125  throw DuplicateError("A system of the type \"" + std::string(type.name()) + "\" already exists.");
126  this->_systems.push_back(std::make_unique<T>(*this, std::forward<Types>(params)...));
127  return *this;
128  }
129 
132  template<typename T>
133  Wal &addSystem(const T &system)
134  {
135  const std::type_info &type = typeid(T);
136  auto existing = std::find_if(this->_systems.begin(), this->_systems.end(), [&type] (auto &sys) {
137  return typeid(*sys) == type;
138  });
139  if (existing != this->_systems.end())
140  throw DuplicateError("A system of the type \"" + std::string(type.name()) + "\" already exists.");
141  this->_systems.push_back(std::make_unique<T>(system));
142  return *this;
143  }
144 
147  template<typename T>
149  {
150  const std::type_info &type = typeid(T);
151  auto existing = std::find_if(this->_systems.begin(), this->_systems.end(), [&type] (auto &sys) {
152  return typeid(*sys) == type;
153  });
154  if (existing == this->_systems.end())
155  throw NotFoundError("A system of the type \"" + std::string(type.name()) + "\" could not be found.");
156  return *static_cast<T *>(existing->get());
157  }
158 
160  template<typename T>
162  {
163  const std::type_info &type = typeid(T);
164  auto existing = std::find_if(this->_systems.begin(), this->_systems.end(), [&type] (auto &sys) {
165  return typeid(*sys) == type;
166  });
167  if (existing == this->_systems.end())
168  throw NotFoundError("No system could be found with the type \"" + std::string(type.name()) + "\".");
169  this->_systems.erase(existing);
170  return *this;
171  }
172 
177  template<typename T>
178  void run(const Callback<Wal &, T &> &callback, T state = T())
179  {
180  #if defined(PLATFORM_WEB)
181  std::tuple<Wal &, const Callback<Wal &, T &> &, T &> iterationParams(*this, callback, state);
182  return emscripten_set_main_loop_arg((em_arg_callback_func)_runIteration<T>, (void *)&iterationParams, 0, 1);
183  #else
184  return this->_run(callback, state);
185  #endif
186  }
187 
189  Wal() = default;
191  Wal(const Wal &) = delete;
193  ~Wal() = default;
195  Wal &operator=(const Wal &) = delete;
196  };
197 } // namespace WAL
WAL::Wal::_scene
std::shared_ptr< Scene > _scene
The scene that contains entities.
Definition: Wal.hpp:34
WAL::Wal::removeSystem
Wal & removeSystem()
Remove a system using it's type.
Definition: Wal.hpp:161
WAL::Wal::shouldClose
bool shouldClose
True if the engine should close after the end of the current tick.
Definition: Wal.hpp:89
WAL
Definition: Component.cpp:7
Callback.hpp
WAL::Wal::getScene
std::shared_ptr< Scene > getScene() const
Retrieve the current scene.
Definition: Wal.hpp:94
WAL::Wal::run
void run(const Callback< Wal &, T & > &callback, T state=T())
Start the game loop.
Definition: Wal.hpp:178
WAL::Wal
The main WAL class, it is used to setup and run the ECS.
Definition: Wal.hpp:27
WAL::Wal::addSystem
Wal & addSystem(Types &&...params)
Create a new system in place.
Definition: Wal.hpp:118
WAL::Wal::_systems
std::vector< std::unique_ptr< ISystem > > _systems
The list of registered systems.
Definition: Wal.hpp:31
WAL::Wal::Wal
Wal()=default
A default constructor.
WAL::Wal::~Wal
~Wal()=default
A default destructor.
WAL::Wal::addSystem
Wal & addSystem(const T &system)
Add a system by copy.
Definition: Wal.hpp:133
WAL::Callback
A callback where you can subscribe to and emit it.
Definition: Callback.hpp:16
WalError.hpp
ISystem.hpp
WAL::Wal::timestep
static constexpr std::chrono::nanoseconds timestep
The time between each fixed update.
Definition: Wal.hpp:91
WAL::Wal::getSystem
T & getSystem()
Get a system of a specific type.
Definition: Wal.hpp:148
WAL::Wal::_run
void _run(const Callback< Wal &, T & > &callback, T state=T())
Start the game loop.
Definition: Wal.hpp:41
WAL::Wal::changeScene
void changeScene(std::shared_ptr< Scene > newScene)
Change the current scene.
Definition: Wal.hpp:100
Scene.hpp
WAL::Wal::operator=
Wal & operator=(const Wal &)=delete
A WAL can't be assigned.
WAL::NotFoundError
An exception informing the user that something could not be found.
Definition: WalError.hpp:43
WAL::DuplicateError
An exception informing the user that something already exists.
Definition: WalError.hpp:29