ECS.h 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  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 <deque>
  19. #include <Logger.h>
  20. #include <Pool.h>
  21. const uint32_t MAX_COMPONENTS = 32;
  22. typedef std::bitset<MAX_COMPONENTS> Signature;
  23. struct IComponent
  24. {
  25. protected:
  26. static uint32_t nextId;
  27. };
  28. template <typename T> class Component: public IComponent
  29. {
  30. public:
  31. static uint32_t getId()
  32. {
  33. static auto id = IComponent::nextId++;
  34. return id;
  35. }
  36. };
  37. class Entity
  38. {
  39. private:
  40. uint32_t id;
  41. public:
  42. explicit Entity(uint32_t id): id(id) {};
  43. Entity(const Entity & entity) = default;
  44. uint32_t getId() const;
  45. Entity& operator=(const Entity & other) = default;
  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. bool operator<(const Entity &other) const { return this->id < other.id; };
  50. /* Some syntaxic sugar */
  51. template <typename T, typename ...TArgs> void addComponent(TArgs&& ...args);
  52. template <typename T> void removeComponent();
  53. template <typename T> bool hasComponent();
  54. template <typename T> T& getComponent();
  55. class Registry *registry = nullptr;
  56. void kill();
  57. void tag(const std::string &tag);
  58. bool hasTag(const std::string &tag) const;
  59. void group(const std::string &groupName);
  60. bool belongsToGroup(const std::string &groupName) const;
  61. };
  62. class System
  63. {
  64. private:
  65. Signature componentSignature;
  66. std::vector<Entity> entities;
  67. public:
  68. System() = default;
  69. ~System() = default;
  70. void addEntity(Entity entity);
  71. void removeEntity(Entity entity);
  72. std::vector<Entity> getSystemEntities() const;
  73. const Signature& getComponentSignature() const;
  74. template<typename T> void requireComponent();
  75. };
  76. template<typename T> void System::requireComponent()
  77. {
  78. const auto componentId = Component<T>::getId();
  79. this->componentSignature.set(componentId);
  80. }
  81. class Registry
  82. {
  83. private:
  84. uint32_t numEntities = 0;
  85. std::vector<std::shared_ptr<IPool>> componentPools;
  86. std::vector<Signature> entityComponentSignatures;
  87. std::unordered_map<std::type_index, std::shared_ptr<System>> systems;
  88. std::set<Entity> entitiesToBeAdded;
  89. std::set<Entity> entitiesToBeKilled;
  90. std::deque<uint32_t> freeIds;
  91. std::unordered_map<std::string, Entity> entityPerTag;
  92. std::unordered_map<uint32_t, std::string> tagPerEntity;
  93. std::unordered_map<std::string, std::set<Entity>> entitiesPerGroup;
  94. std::unordered_map<uint32_t, std::string> groupPerEntity;
  95. public:
  96. Registry() = default;
  97. ~Registry() = default;
  98. /* Entities */
  99. Entity createEntity();
  100. void killEntity(Entity entity);
  101. void tagEntity(Entity entity, const std::string &tag);
  102. bool entityHasTag(Entity entity, const std::string &tag) const;
  103. Entity getEntityByTag(const std::string &tag) const;
  104. void removeEntityTag(Entity entity);
  105. void groupEntity(Entity entity, const std::string &groupName);
  106. bool entityBelongsToGroup(Entity entity, const std::string &groupName) const;
  107. std::vector<Entity> getEntitiesByGroup(const std::string &groupName) const;
  108. void removeEntityGroup(Entity entity);
  109. void addEntityToSystems(Entity entity);
  110. void removeEntityFromSystems(Entity entity);
  111. /* Components */
  112. template <typename T, typename ...TArgs> void addComponent(Entity entity, TArgs&& ...args);
  113. template <typename T> void removeComponent(Entity entity);
  114. template <typename T> bool hasComponent(Entity entity);
  115. template <typename T> T& getComponent(Entity entity);
  116. /* Systems */
  117. template<typename T, typename ...TArgs> void addSystem(TArgs&& ...args);
  118. template<typename T> void removeSystem();
  119. template<typename T> bool hasSystem() const;
  120. template<typename T> T& getSystem() const;
  121. /* Others */
  122. void update();
  123. };
  124. template<typename T, typename ...TArgs> void Registry::addComponent(Entity entity, TArgs&& ...args)
  125. {
  126. const auto componentId = Component<T>::getId();
  127. const auto entityId = entity.getId();
  128. std::shared_ptr<PoolToUse<T>> componentPool;
  129. /* Check the pool is big enough */
  130. if (componentId >= this->componentPools.size())
  131. {
  132. this->componentPools.resize(componentId + 1, nullptr);
  133. }
  134. /* Is this component exist in the pool? */
  135. if (!this->componentPools[componentId])
  136. {
  137. this->componentPools[componentId] = std::make_shared<PoolToUse<T>>();
  138. }
  139. componentPool = std::static_pointer_cast<PoolToUse<T>>(this->componentPools[componentId]);
  140. if (entityId >= componentPool->getSize())
  141. {
  142. componentPool->resize(this->numEntities);
  143. }
  144. T newComponent(std::forward<TArgs>(args)...);
  145. componentPool->set(entityId, newComponent);
  146. this->entityComponentSignatures[entityId].set(componentId);
  147. //Logger::Debug("Component id#%d was added to entity id#%d", componentId, entityId);
  148. }
  149. template <typename T> void Registry::removeComponent(Entity entity)
  150. {
  151. const auto componentId = Component<T>::getId();
  152. const auto entityId = entity.getId();
  153. std::shared_ptr<PoolToUse<T>> componentPool;
  154. this->entityComponentSignatures[entityId].set(componentId, false);
  155. componentPool = std::static_pointer_cast<PoolToUse<T>>(this->componentPools[componentId]);
  156. componentPool.remove(entityId);
  157. //Logger::Debug("Component id#%d was removed to entity id#%d", componentId, entityId);
  158. }
  159. template <typename T> bool Registry::hasComponent(Entity entity)
  160. {
  161. const auto componentId = Component<T>::getId();
  162. const auto entityId = entity.getId();
  163. return this->entityComponentSignatures[entityId].test(componentId);
  164. }
  165. template <typename T> T& Registry::getComponent(Entity entity)
  166. {
  167. const auto componentId = Component<T>::getId();
  168. const auto entityId = entity.getId();
  169. auto componentPool = std::static_pointer_cast<PoolToUse<T>>(this->componentPools[componentId]);
  170. return componentPool->get(entityId);
  171. }
  172. template<typename T, typename ...TArgs> void Registry::addSystem(TArgs&& ...args)
  173. {
  174. std::shared_ptr<T> newSystem = std::make_shared<T>(std::forward<TArgs>(args)...);
  175. this->systems.insert(std::make_pair(std::type_index(typeid(T)), newSystem));
  176. }
  177. template<typename T> void Registry::removeSystem()
  178. {
  179. auto system = this->systems.find(std::type_index(typeid(T)));
  180. this->systems.erase(system);
  181. }
  182. template<typename T> bool Registry::hasSystem() const
  183. {
  184. return this->systems.find(std::type_index(typeid(T))) != this->systems.end();
  185. }
  186. template<typename T> T& Registry::getSystem() const
  187. {
  188. auto system = this->systems.find(std::type_index(typeid(T)));
  189. return *(std::static_pointer_cast<T>(system->second));
  190. }
  191. template <typename T, typename ...TArgs> void Entity::addComponent(TArgs&& ...args)
  192. {
  193. this->registry->addComponent<T>(*this, std::forward<TArgs>(args)...);
  194. }
  195. template <typename T> void Entity::removeComponent()
  196. {
  197. this->registry->removeComponent<T>(*this);
  198. }
  199. template <typename T> bool Entity::hasComponent()
  200. {
  201. return this->registry->hasComponent<T>(*this);
  202. }
  203. template <typename T> T& Entity::getComponent()
  204. {
  205. return this->registry->getComponent<T>(*this);
  206. }
  207. #endif /* GAMEENGINE_ECS_H */