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 T, typename Func>
28 inline void modifyComponent(const Entity e, Func&& fn)
29 {
30 T& c = getComponent<T>(e);
31 fn(c);
32 }
33
34 template <typename T>
35 inline void modifyComponent(const Entity e, T c)
36 {
37 getComponent<T>(e) = c;
38 }
39
40 template <typename ComponentType>
41 inline void removeComponent(const Entity entity)
42 {
43 auto& componentSet = getComponentSet<ComponentType>();
44 componentSet.remove(entity);
45 }
46
47 template <typename... ComponentTypes>
48 inline void removeComponents(const Entity entity)
49 {
50 (removeComponent<ComponentTypes>(entity), ...);
51 }
52
53 inline void removeComponents(const Entity entity)
54 {
55 removeComponents<AllComponentTypes...>(entity);
56 }
57
58 template <typename ComponentType>
59 inline ComponentType& getComponent(const Entity entity)
60 {
61 auto& componentSet = getComponentSet<ComponentType>();
62 // could be optimized with direct access. get() calls contains() internally
63 return componentSet.get(entity);
64 }
65
66 template <typename ComponentType>
67 inline const ComponentType& getComponent(const Entity entity) const
68 {
69 const auto& componentSet = getComponentSet<ComponentType>();
70 // could be optimized with direct access. get() calls contains() internally
71 return componentSet.get(entity);
72 }
73
74 template <typename ComponentType>
75 inline bool hasComponent(const Entity entity) const
76 {
77 return getComponentSet<ComponentType>().contains(entity);
78 }
79
80 template <typename... ComponentTypes>
81 inline std::vector<Entity> getEntities() const
82 {
83 std::vector<Entity> entities;
84 bool isFirstComponentType = true;
85
86 // Iterate over each component type and intersect entities
87 forEachComponentType<ComponentTypes...>(
88 [this, &entities, &isFirstComponentType]<typename T>()
89 {
90 if (isFirstComponentType)
91 {
92 entities = getComponentSet<T>().getKeys();
93 isFirstComponentType = false;
94 }
95
96 else
97 {
98 std::vector<Easys::Entity> newEntities;
99 newEntities.reserve(entities.size());
100
101 for (const auto& e : entities)
102 {
103 if (hasComponent<T>(e))
104 {
105 newEntities.push_back(e);
106 }
107 }
108
109 entities = std::move(newEntities);
110 }
111 });
112
113 return entities;
114 }
115
116 //template <typename... ComponentTypes>
117 //const auto& smallestPool() const {
118 // forEachComponentType<ComponentTypes...>([]<typename T>() {
119 // const size_t size = size<T>();
120 // });
121 //}
122
123 template <typename... ComponentTypes>
124 inline size_t size() const
125 {
126 return (... + getComponentSet<ComponentTypes>().size());
127 }
128
129 inline size_t size() const
130 {
131 return size<AllComponentTypes...>();
132 }
133
134 template <typename... ComponentTypes>
135 inline void clear()
136 {
137 (getComponentSet<ComponentTypes>().clear(), ...);
138 }
139
140 inline void clear()
141 {
142 clear<AllComponentTypes...>();
143 }
144
145 private:
146 template <typename T>
147 static constexpr bool isRegisteredComponent = (std::is_same_v<T, AllComponentTypes> || ...);
148
149 template <typename... ComponentTypes, typename Func>
150 inline void forEachComponentType(Func&& f) const
151 {
152 // MSVC does not support multiple expressions in a fold statement so we use this small helper
153 auto staticAssertAndCall = [&f]<typename T>()
154 {
155 static_assert(isRegisteredComponent<T>, "Tried to access an unregistered component type in ECS.");
156 f.template operator()<T>();
157 };
158
159 (staticAssertAndCall.template operator()<ComponentTypes>(), ...);
160 }
161
162 template <typename ComponentType>
163 inline SparseSet<Entity, ComponentType>& getComponentSet()
164 {
165 static_assert(isRegisteredComponent<ComponentType>, "Tried to access an unregistered component type.");
166 return std::get<SparseSet<Entity, ComponentType>>(componentSets);
167 }
168
169 template <typename ComponentType>
170 inline const SparseSet<Entity, ComponentType>& getComponentSet() const
171 {
172 static_assert(isRegisteredComponent<ComponentType>, "Tried to access an unregistered component type.");
173 return std::get<SparseSet<Entity, ComponentType>>(componentSets);
174 }
175};
176
177} // namespace Easys
Definition registry.hpp:15
ComponentType & getComponent(const Entity entity)
Definition registry.hpp:59
size_t size() const
Definition registry.hpp:129
const ComponentType & getComponent(const Entity entity) const
Definition registry.hpp:67
void modifyComponent(const Entity e, Func &&fn)
Definition registry.hpp:28
void removeComponents(const Entity entity)
Definition registry.hpp:48
void clear()
Definition registry.hpp:135
void addComponent(const Entity entity, const ComponentType &component)
Definition registry.hpp:21
void modifyComponent(const Entity e, T c)
Definition registry.hpp:35
void clear()
Definition registry.hpp:140
bool hasComponent(const Entity entity) const
Definition registry.hpp:75
void removeComponents(const Entity entity)
Definition registry.hpp:53
void removeComponent(const Entity entity)
Definition registry.hpp:41
std::vector< Entity > getEntities() const
Definition registry.hpp:81
size_t size() const
Definition registry.hpp:124
Definition ecs.hpp:14
EASYS_ENTITY_TYPE Entity
Definition entity.hpp:11