ECS.h 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /*
  2. * 2D Game Engine
  3. * ECS.h:
  4. * Based on pikuma.com 2D game engine in C++ and Lua course
  5. * Copyright (c) 2021 986-Studio. All rights reserved.
  6. *
  7. * Created by Manoël Trapier on 11/02/2021.
  8. */
  9. #ifndef GAMEENGINE_ECS_H
  10. #define GAMEENGINE_ECS_H
  11. #include <stdint.h>
  12. #include <bitset>
  13. #include <vector>
  14. #include <unordered_map>
  15. #include <typeindex>
  16. #include <set>
  17. #include <memory>
  18. #include <Logger.h>
  19. #include <Pool.h>
  20. const uint32_t MAX_COMPONENTS = 32;
  21. typedef std::bitset<MAX_COMPONENTS> Signature;
  22. struct IComponent
  23. {
  24. protected:
  25. static uint32_t nextId;
  26. };
  27. template <typename T> class Component: public IComponent
  28. {
  29. public:
  30. static uint32_t getId()
  31. {
  32. static auto id = IComponent::nextId++;
  33. return id;
  34. }
  35. };
  36. class Entity
  37. {
  38. private:
  39. uint32_t id;
  40. public:
  41. explicit Entity(uint32_t id): id(id) {};
  42. Entity(const Entity & entity) = default;
  43. uint32_t getId() const;
  44. Entity& operator=(const Entity & other) = default;
  45. bool operator==(const Entity &other) const { return this->id == other.id; };
  46. bool operator!=(const Entity &other) const { return this->id != other.id; };
  47. bool operator>(const Entity &other) const { return this->id > other.id; };
  48. bool operator<(const Entity &other) const { return this->id < other.id; };
  49. /* Some syntaxic sugar */
  50. template <typename T, typename ...TArgs> void addComponent(TArgs&& ...args);
  51. template <typename T> void removeComponent();
  52. template <typename T> bool hasComponent();
  53. template <typename T> T& getComponent();
  54. class Registry *registry = nullptr;
  55. };
  56. class System
  57. {
  58. private:
  59. Signature componentSignature;
  60. std::vector<Entity> entities;
  61. public:
  62. System() = default;
  63. ~System() = default;
  64. void addEntity(Entity entity);
  65. void removeEntity(Entity entity);
  66. std::vector<Entity> getSystemEntities() const;
  67. const Signature& getComponentSignature() const;
  68. template<typename T> void requireComponent();
  69. };
  70. template<typename T> void System::requireComponent()
  71. {
  72. const auto componentId = Component<T>::getId();
  73. this->componentSignature.set(componentId);
  74. }
  75. class Registry
  76. {
  77. private:
  78. uint32_t numEntities = 0;
  79. std::vector<std::shared_ptr<IPool>> componentPools;
  80. std::vector<Signature> entityComponentSignatures;
  81. std::unordered_map<std::type_index, std::shared_ptr<System>> systems;
  82. std::set<Entity> entitiesToBeAdded;
  83. std::set<Entity> entitiesToBeKilled;
  84. public:
  85. Registry() = default;
  86. ~Registry() = default;
  87. /* Entities */
  88. Entity createEntity();
  89. void addEntityToSystems(Entity entity);
  90. /* Components */
  91. template <typename T, typename ...TArgs> void addComponent(Entity entity, TArgs&& ...args);
  92. template <typename T> void removeComponent(Entity entity);
  93. template <typename T> bool hasComponent(Entity entity);
  94. template <typename T> T& getComponent(Entity entity);
  95. /* Systems */
  96. template<typename T, typename ...TArgs> void addSystem(TArgs&& ...args);
  97. template<typename T> void removeSystem();
  98. template<typename T> bool hasSystem() const;
  99. template<typename T> T& getSystem() const;
  100. /* Others */
  101. void update();
  102. };
  103. template<typename T, typename ...TArgs> void Registry::addComponent(Entity entity, TArgs&& ...args)
  104. {
  105. const auto componentId = Component<T>::getId();
  106. const auto entityId = entity.getId();
  107. std::shared_ptr<Pool<T>> componentPool;
  108. /* Check the pool is big enough */
  109. if (componentId >= this->componentPools.size())
  110. {
  111. this->componentPools.resize(componentId + 1, nullptr);
  112. }
  113. /* Is this component exist in the pool? */
  114. if (!this->componentPools[componentId])
  115. {
  116. this->componentPools[componentId] = std::make_shared<Pool<T>>();
  117. }
  118. componentPool = std::static_pointer_cast<Pool<T>>(this->componentPools[componentId]);
  119. if (entityId >= componentPool->getSize())
  120. {
  121. componentPool->resize(this->numEntities);
  122. }
  123. T newComponent(std::forward<TArgs>(args)...);
  124. componentPool->set(entityId, newComponent);
  125. this->entityComponentSignatures[entityId].set(componentId);
  126. Logger::Debug("Component id#%d was added to entity id#%d", componentId, entityId);
  127. }
  128. template <typename T> void Registry::removeComponent(Entity entity)
  129. {
  130. const auto componentId = Component<T>::getId();
  131. const auto entityId = entity.getId();
  132. this->entityComponentSignatures[entityId].set(componentId, false);
  133. Logger::Debug("Component id#%d was removed to entity id#%d", componentId, entityId);
  134. }
  135. template <typename T> bool Registry::hasComponent(Entity entity)
  136. {
  137. const auto componentId = Component<T>::getId();
  138. const auto entityId = entity.getId();
  139. return this->entityComponentSignatures[entityId].test(componentId);
  140. }
  141. template <typename T> T& Registry::getComponent(Entity entity)
  142. {
  143. const auto componentId = Component<T>::getId();
  144. const auto entityId = entity.getId();
  145. auto componentPool = std::static_pointer_cast<Pool<T>>(this->componentPools[componentId]);
  146. return componentPool->get(entityId);
  147. }
  148. template<typename T, typename ...TArgs> void Registry::addSystem(TArgs&& ...args)
  149. {
  150. std::shared_ptr<T> newSystem = std::make_shared<T>(std::forward<TArgs>(args)...);
  151. this->systems.insert(std::make_pair(std::type_index(typeid(T)), newSystem));
  152. }
  153. template<typename T> void Registry::removeSystem()
  154. {
  155. auto system = this->systems.find(std::type_index(typeid(T)));
  156. this->systems.erase(system);
  157. }
  158. template<typename T> bool Registry::hasSystem() const
  159. {
  160. return this->systems.find(std::type_index(typeid(T))) != this->systems.end();
  161. }
  162. template<typename T> T& Registry::getSystem() const
  163. {
  164. auto system = this->systems.find(std::type_index(typeid(T)));
  165. return *(std::static_pointer_cast<T>(system->second));
  166. }
  167. template <typename T, typename ...TArgs> void Entity::addComponent(TArgs&& ...args)
  168. {
  169. this->registry->addComponent<T>(*this, std::forward<TArgs>(args)...);
  170. }
  171. template <typename T> void Entity::removeComponent()
  172. {
  173. this->registry->removeComponent<T>(*this);
  174. }
  175. template <typename T> bool Entity::hasComponent()
  176. {
  177. return this->registry->hasComponent<T>(*this);
  178. }
  179. template <typename T> T& Entity::getComponent()
  180. {
  181. return this->registry->getComponent<T>(*this);
  182. }
  183. #endif /* GAMEENGINE_ECS_H */