Untitled Game engine no.5  1.0
ECS.hpp
1 #ifndef ECS_H
2 #define ECS_H
3 
4 #include <algorithm>
5 #include <stdexcept>
6 #include <unordered_map>
7 #include "Types.hpp"
8 #include "Base.hpp"
9 #include "ComponentArray.hpp"
10 #include "SystemBase.hpp"
11 #include <execinfo.h>
12 
13 namespace Engine {
15  class ComponentBase{};
16 
17  // initializes all components to defaults or whatever
19  class ECS {
20  private:
21  // typedefs
22  typedef std::unordered_map<ComponentTypeID, IComponentDataArray*> CompIdArrayMap;
23  typedef std::unordered_map<EntityID, Archetype> EntityArchMap;
24  typedef std::unordered_map<SystemID, Ref<SystemBase>> SystemMap;
25 
27  EntityID m_entityIdCounter;
28  SystemID m_systemIdCounter;
30  CompIdArrayMap m_componentMap;
32  EntityArchMap m_entityArch;
34  SystemMap m_systems;
35 
36  public:
38  ECS() : m_systemIdCounter(0), m_entityIdCounter(1) { }
39 
41  ~ECS() {
42  m_componentMap.clear();
43  m_entityArch.clear();
44  }
45 
47  EntityID CreateEntityID() {
48  // TODO: Check if we have too many entites
49  EntityID id = GetNewID();
50  m_entityArch[id] = Archetype().reset();
51  return id;
52  }
53 
56  template<class C>
57  void RemoveComponent(const EntityID& id)
58  {
59  ComponentTypeID compId = GetTypeID<C>();
60  if (!IsComponentRegistered<C>()){
61  Log::printStackTrace();
62  throw std::runtime_error("Component Not Registered!");
63  return;
64  }
65 
66  ComponentDataArray<C>* arr = getComponentArray<C>();
67  m_entityArch[id].set(compId, 0);
68  arr->Remove(id);
69  }
70 
73  Archetype GetArchetype(EntityID id) {
74  return m_entityArch[id];
75  }
76 
79  template<class C>
80  Ref<C> GetComponent(const EntityID& id) {
81  ComponentTypeID compId = GetTypeID<C>();
82  if (!IsComponentRegistered<C>()){
83  Log::printStackTrace();
84  throw std::runtime_error("Component Not Registered!");
85  return nullptr;
86  }
87 
88  ComponentDataArray<C>* arr = getComponentArray<C>();
89  return arr->GetComp(id);
90  }
91 
94  void RemoveEntity(const EntityID& id)
95  {
96  m_entityArch.erase(id);
97  for (auto itr : m_componentMap) {
98  itr.second->EntityDestroyed(id);
99  }
100  }
101 
105  template<class C, typename... Args>
106  Ref<C> AddComponent(EntityID id, Ref<C> args) {
107  ComponentTypeID compId = GetTypeID<C>();
108  if (!IsComponentRegistered<C>()){
109  Log::printStackTrace();
110  throw std::runtime_error("Component Not Registered!");
111  }
112 
113  // update the entity's archetype
114  m_entityArch[id].set(compId, true);
115  ComponentDataArray<C>* arr = getComponentArray<C>();
116  return arr->Insert(id, args);
117  }
118 
122  template<class C, typename... Args>
123  Ref<C> AddComponent(EntityID id, Args&&... args) {
124  ComponentTypeID compId = GetTypeID<C>();
125  if (!IsComponentRegistered<C>()){
126  Log::printStackTrace();
127  throw std::runtime_error("Component Not Registered!");
128  }
129 
130  // update the entity's archetype
131  m_entityArch[id].set(compId, true);
132  ComponentDataArray<C>* arr = getComponentArray<C>();
133  return arr->Insert(id, C(std::forward<Args>(args)...));
134  }
135 
140  // get the archetype of this system
141  s->m_id = m_systemIdCounter++;
142  m_systems[s->m_id] = s;
143  return s->m_id;
144  }
145 
148  void RunSystem(SystemID sid) {
149  Ref<SystemBase> sys = m_systems[sid];
150  // get the relevent entities and run on them
151  for (auto& e : GetEntitiesWith(sys->m_arch)) {
152  sys->Run(e);
153  }
154  }
155 
158  void RunSystemArch(Archetype a) {
159  for (auto& itr : m_systems) {
160  if (itr.second->m_arch == a) {
161  RunSystem(itr.first);
162  }
163  }
164  }
165 
166  template<class... Cs>
169  Archetype GetArchetype() {
170  Archetype arch;
171 
172  for(auto b : std::vector<bool>{{IsComponentRegistered<Cs>()...}}) {
173  if (!b)
174  Log::Err("ECS", "Oh no compnent not registered");
175  }
176 
177  std::vector<ComponentTypeID> ids = {{GetTypeID<Cs>()...}};
178  for (auto& i : ids) {
179  arch.set(i, 1);
180  }
181 
182  return arch;
183  }
184 
187  template<class... Cs>
188  std::vector<EntityID> GetEntitiesWith() {
189  Archetype a = GetArchetype<Cs...>();
190  std::vector<EntityID> ret;
191  for (auto& itr : m_entityArch) {
192  auto bits = itr.second;
193  // check if the other one at least has the same bits set
194  if ((itr.second & a) == a) {
195  ret.push_back(itr.first);
196  }
197  }
198  return ret;
199  }
200 
203  std::vector<EntityID> GetEntitiesWith(Archetype a) {
204  std::vector<EntityID> ret;
205  for (auto& itr : m_entityArch) {
206  auto bits = itr.second;
207  // check if the other one at least has the same bits set
208  if ((itr.second & a) == a) {
209  ret.push_back(itr.first);
210  }
211  }
212  return ret;
213  }
214 
217  template<class C>
219  ComponentTypeID typeId = GetTypeID<C>();
220 
221  // already registered
222  if (m_componentMap.find(typeId) != m_componentMap.end())
223  return;
224 
225  m_componentMap.emplace(typeId, new ComponentDataArray<C>);
226  }
227 
230  template<class C>
232  ComponentTypeID typeId = GetTypeID<C>();
233  return m_componentMap.find(typeId) != m_componentMap.end();
234  }
235 
236 
237  private:
240  template<class C>
241  ComponentDataArray<C>* getComponentArray() {
242  const ComponentTypeID compId = GetTypeID<C>();
243  if (!IsComponentRegistered<C>()){
244  throw std::runtime_error("Component Not Registered!");
245  return nullptr;
246  }
247 
248  return (ComponentDataArray<C>*) m_componentMap[compId];
249  }
250 
253  EntityID GetNewID() {
254  return m_entityIdCounter++;
255  }
256 
257  template<class C>
258  ComponentTypeID GetTypeID() {
259  return TypeIdGenerator<ComponentBase>::GetTypeID<C>();
260  }
261 
262  };
263 
264  // Enitialize entity counter to 1 so that we can
265  // reserve 0 for null
266 }
267 #endif
Engine::ECS
Entity Component System.
Definition: ECS.hpp:19
Engine::ECS::RemoveComponent
void RemoveComponent(const EntityID &id)
Definition: ECS.hpp:57
Engine::ECS::RemoveEntity
void RemoveEntity(const EntityID &id)
Definition: ECS.hpp:94
Engine::ECS::AddComponent
Ref< C > AddComponent(EntityID id, Ref< C > args)
Definition: ECS.hpp:106
Engine::Ref
std::shared_ptr< T > Ref
Has stuff for making references a lot more easily shared smart pointer.
Definition: Base.hpp:21
Engine::ECS::RegisterComponent
void RegisterComponent()
Definition: ECS.hpp:218
Engine::ECS::RunSystemArch
void RunSystemArch(Archetype a)
Definition: ECS.hpp:158
Engine::ECS::~ECS
~ECS()
ECS Destructor.
Definition: ECS.hpp:41
Engine::ECS::GetEntitiesWith
std::vector< EntityID > GetEntitiesWith()
Definition: ECS.hpp:188
Engine::ECS::CreateEntityID
EntityID CreateEntityID()
Creates an entity and returns it's ID.
Definition: ECS.hpp:47
Engine::ECS::ECS
ECS()
Creates a new ECS, entity counter is 1 to reserve for null.
Definition: ECS.hpp:38
Engine::ECS::GetArchetype
Archetype GetArchetype(EntityID id)
Definition: ECS.hpp:73
Engine::ComponentDataArray
An array of components of type T.
Definition: ComponentArray.hpp:16
Engine::ComponentDataArray::GetComp
Ref< T > GetComp(EntityID id)
Definition: ComponentArray.hpp:80
Engine::ECS::AddComponent
Ref< C > AddComponent(EntityID id, Args &&... args)
Definition: ECS.hpp:123
Engine::ECS::GetEntitiesWith
std::vector< EntityID > GetEntitiesWith(Archetype a)
Definition: ECS.hpp:203
Engine::ECS::GetArchetype
Archetype GetArchetype()
Definition: ECS.hpp:169
Engine::ECS::GetComponent
Ref< C > GetComponent(const EntityID &id)
Definition: ECS.hpp:80
Engine::ComponentDataArray::Insert
Ref< T > Insert(EntityID id, Ref< T > c)
Definition: ComponentArray.hpp:36
Engine
Definition: Animation.hpp:14
Engine::ComponentBase
Dummy class so we can make component type ids.
Definition: ECS.hpp:15
Engine::ECS::RunSystem
void RunSystem(SystemID sid)
Definition: ECS.hpp:148
Engine::ComponentDataArray::Remove
void Remove(EntityID id)
Definition: ComponentArray.hpp:64
Engine::ECS::RegisterSystem
SystemID RegisterSystem(Ref< SystemBase > &s)
Definition: ECS.hpp:139
Engine::ECS::IsComponentRegistered
bool IsComponentRegistered()
Definition: ECS.hpp:231