Easys
A minimalist, header-only C++ ECS library for efficient and fuss-free entity and component management.
Loading...
Searching...
No Matches
registry.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <any>
4#include <stdexcept>
5#include <typeindex>
6#include <unordered_map>
7#include <vector>
8
9#include "entity.hpp"
10#include "sparse_set.hpp"
11
12namespace Easys {
13
14template <typename... AllComponentTypes>
15class Registry {
16 private:
17 mutable std::tuple<SparseSet<Entity, AllComponentTypes>...> componentSets;
18
19 public:
20 template <typename ComponentType>
21 inline void addComponent(const Entity entity, const ComponentType& component)
22 {
23 auto& componentSet = getComponentSet<ComponentType>();
24 componentSet.set(entity, std::move(component));
25 }
26
27 template <typename ComponentType>
28 inline void removeComponent(const Entity entity)
29 {
30 auto& componentSet = getComponentSet<ComponentType>();
31 componentSet.remove(entity);
32 }
33
34 inline void removeComponents(const Entity entity)
35 {
36 forEachComponentType<AllComponentTypes...>(
37 [&]<typename Component>()
38 {
39 removeComponent<Component>(entity);
40 });
41 }
42
43 template <typename... ComponentTypes>
44 inline void removeComponents(const Entity entity)
45 {
46 forEachComponentType<ComponentTypes...>(
47 [&]<typename Component>()
48 {
49 removeComponent<Component>(entity);
50 });
51 }
52
53 template <typename ComponentType>
54 inline ComponentType& getComponent(const Entity entity)
55 {
56 auto& componentSet = getComponentSet<ComponentType>();
57 // could be optimized with direct access. get() calls contains() internally
58 return componentSet.get(entity);
59 }
60
61 template <typename ComponentType>
62 inline const ComponentType& getComponent(const Entity entity) const
63 {
64 const auto& componentSet = getComponentSet<ComponentType>();
65 // could be optimized with direct access. get() calls contains() internally
66 return componentSet.get(entity);
67 }
68
69 template <typename ComponentType>
70 inline bool hasComponent(const Entity entity) const
71 {
72 return getComponentSet<ComponentType>().contains(entity);
73 }
74
75 template <typename ComponentType>
76 inline const std::vector<Entity>& getEntitiesByComponent() const
77 {
78 return getComponentSet<ComponentType>().getKeys();
79 }
80
81 template <typename... ComponentTypes>
82 inline std::vector<Entity> getEntitiesByComponents() const
83 {
84 std::vector<Entity> entities;
85 bool isFirstComponentType = true;
86
87 // Helper lambda to intersect two sorted vectors
88 auto intersect = [](const std::vector<Entity>& v1, const std::vector<Entity>& v2)
89 {
90 std::vector<Entity> v_intersection;
91 std::set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(v_intersection));
92 return v_intersection;
93 };
94
95 // Iterate over each component type and intersect entities
96 forEachComponentType<ComponentTypes...>(
97 [this, &entities, &isFirstComponentType, &intersect]<typename T>()
98 {
99 // We sort here. This is not optimal. We probably want to lazily
100 // sort based on a flag (refer to github issue #7):
101 auto componentEntities = getEntitiesByComponent<T>();
102 std::sort(componentEntities.begin(), componentEntities.end());
103 // Temporary fix end
104 if (isFirstComponentType)
105 {
106 entities = componentEntities;
107 isFirstComponentType = false;
108 } else
109 {
110 entities = intersect(entities, componentEntities);
111 }
112 });
113
114 return entities;
115 }
116
117 inline size_t size() const
118 {
119 size_t totalSize = 0;
120
121 forEachComponentType<AllComponentTypes...>(
122 [this, &totalSize]<typename T>()
123 {
124 totalSize += getComponentSet<T>().size();
125 });
126
127 return totalSize;
128 }
129
130 template <typename... ComponentTypes>
131 inline size_t size() const
132 {
133 size_t totalSize = 0;
134
135 forEachComponentType<ComponentTypes...>(
136 [this, &totalSize]<typename T>()
137 {
138 totalSize += getComponentSet<T>().size();
139 });
140
141 return totalSize;
142 }
143
144 inline void clear()
145 {
146 forEachComponentType<AllComponentTypes...>(
147 [this]<typename T>()
148 {
149 getComponentSet<T>().clear();
150 });
151 }
152
153 template <typename... ComponentTypes>
154 inline void clear()
155 {
156 forEachComponentType<ComponentTypes...>(
157 [this]<typename T>()
158 {
159 getComponentSet<T>().clear();
160 });
161 }
162
163 private:
164 template <typename T>
165 static constexpr bool isRegisteredComponent = (std::is_same_v<T, AllComponentTypes> || ...);
166
167 template <typename... ComponentTypes, typename Func>
168 inline void forEachComponentType(Func&& f) const
169 {
170 // MSVC does not support multiple expressions in a fold statement so we use this small helper
171 auto staticAssertAndCall = [&f]<typename T>()
172 {
173 static_assert(isRegisteredComponent<T>, "Tried to access an unregistered component type in ECS.");
174 f.template operator()<T>();
175 };
176
177 (staticAssertAndCall.template operator()<ComponentTypes>(), ...);
178 }
179
180 template <typename ComponentType>
181 inline SparseSet<Entity, ComponentType>& getComponentSet()
182 {
183 static_assert(isRegisteredComponent<ComponentType>, "Tried to access an unregistered component type.");
184 return std::get<SparseSet<Entity, ComponentType>>(componentSets);
185 }
186
187 template <typename ComponentType>
188 inline const SparseSet<Entity, ComponentType>& getComponentSet() const
189 {
190 static_assert(isRegisteredComponent<ComponentType>, "Tried to access an unregistered component type.");
191 return std::get<SparseSet<Entity, ComponentType>>(componentSets);
192 }
193};
194
195} // namespace Easys
Definition registry.hpp:15
ComponentType & getComponent(const Entity entity)
Definition registry.hpp:54
size_t size() const
Definition registry.hpp:117
const ComponentType & getComponent(const Entity entity) const
Definition registry.hpp:62
std::vector< Entity > getEntitiesByComponents() const
Definition registry.hpp:82
void removeComponents(const Entity entity)
Definition registry.hpp:44
void clear()
Definition registry.hpp:154
void addComponent(const Entity entity, const ComponentType &component)
Definition registry.hpp:21
void clear()
Definition registry.hpp:144
bool hasComponent(const Entity entity) const
Definition registry.hpp:70
const std::vector< Entity > & getEntitiesByComponent() const
Definition registry.hpp:76
void removeComponents(const Entity entity)
Definition registry.hpp:34
void removeComponent(const Entity entity)
Definition registry.hpp:28
size_t size() const
Definition registry.hpp:131
Definition ecs.hpp:12
EASYS_ENTITY_TYPE Entity
Definition entity.hpp:11