Easys
A minimalist, header-only C++ ECS library for efficient and fuss-free entity and component management.
Loading...
Searching...
No Matches
ecs.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <functional>
4#include <iostream>
5#include <memory>
6#include <queue>
7#include <set>
8
9#include "entity.hpp"
10#include "log.hpp"
11#include "registry.hpp"
12#include "view.hpp"
13
14namespace Easys {
15
20template <typename... AllComponentTypes>
21class ECS {
22 public:
28 {
30
31 for (Entity entity = 0; entity < MAX_ENTITIES; entity++)
32 {
33 availableEntityIds_.push(entity);
34 }
35 }
36
43 ECS(const std::set<Entity>& oldEntities)
44 {
46
47 // I decided against an addEntity(Entity) method to discourage
48 // tampering with entities too much. I think this really should be the ECS's
49 // responsibility.
50 for (Entity entity = 0; entity < MAX_ENTITIES; entity++)
51 {
52 if (oldEntities.contains(entity))
53 {
54 entities_.insert(entity);
55 } else
56 {
57 availableEntityIds_.push(entity);
58 }
59 }
60 }
61
68 {
70
72 {
73 Entity e = availableEntityIds_.front();
74 availableEntityIds_.pop();
75 entities_.insert(e);
76
78 return e;
79 }
80 EASYS_LOG_ERROR("addEntity(): MAX_ENTITIES reached.");
81 // throwing an exception here seems kind of drastic, but on the other hand
82 // maybe not
83 throw std::runtime_error("MAX NUMBER OF ENTITIES REACHED!");
84 }
85
91 inline void removeEntity(const Entity e)
92 {
94
95 // Remove all components associated with the entity
96 registry_.removeComponents(e);
97 // Remove entity from the set of active entities_
98 entities_.erase(e);
99 // Make the entity ID available again
100 availableEntityIds_.push(e);
101
103 }
104
110 inline bool hasEntity(const Entity e) const
111 {
113
114 return entities_.contains(e);
115 }
116
121 //inline std::set<Entity> getEntities() const
122 //{
123 // EASYS_LOG_ENTRY_EXIT;
124
125 // return entities_;
126 //}
127
128 inline View getEntities() const
129 {
131
132 std::vector<Entity> vec;
133 vec.reserve(entities_.size());
134 vec.assign(entities_.begin(), entities_.end());
135
136 return View(std::move(vec));
137 }
138
145 //template <typename... Ts>
146 //inline std::vector<Entity> getEntities() const
147 //{
148 // EASYS_LOG_ENTRY_EXIT;
149
150 // // return View(registry_.template getEntities<Ts...>());
151 // return registry_.template getEntities<Ts...>();
152 //}
153
154 template <typename... Ts>
155 inline View getEntities() const
156 {
158
159 return View(std::move(registry_.template getEntities<Ts...>()));
160 }
161
166 inline size_t getEntityCount() const
167 {
169
170 return entities_.size();
171 }
172
180 template <typename T>
181 inline void addComponent(const Entity e, T component)
182 {
184
185 // TODO: maybe we should check, if the entity already has a component of type T, mainly so emitted event types
186 // are consistent.
187 registry_.addComponent(e, std::move(component));
188
190 }
191
203 template <typename T, typename Func>
204 inline void modifyComponent(const Entity e, Func&& fn)
205 {
207
208 // we need the component for event dispatch, so we handle it manually.
209 T& c = getComponent<T>(e);
210 fn(c);
211 // registry_.template modifyComponent<T>(e, fn);
212
214 }
215
224 template <typename T>
225 inline void modifyComponent(const Entity e, T c)
226 {
228
229 // we need the component for event dispatch, so we handle it manually.
230 getComponent<T>(e) = c;
231 // registry_.template modifyComponent<T>(e, c);
232
234 }
235
241 template <typename T>
242 inline void removeComponent(const Entity e)
243 {
245
246 registry_.template removeComponent<T>(e);
247
249 }
250
256 template <typename... Ts>
257 inline void removeComponents(const Entity e)
258 {
260
261 (removeComponent<Ts>(e), ...);
262 }
263
268 inline void removeComponents(const Entity e)
269 {
271
272 removeComponents<AllComponentTypes...>(e);
273 // (removeComponent<AllComponentTypes>(e), ...);
274 }
275
282 template <typename T>
283 inline T& getComponent(const Entity e)
284 {
286
287 return registry_.template getComponent<T>(e);
288 }
289
296 template <typename T>
297 inline const T& getComponent(const Entity e) const
298 {
300
301 return registry_.template getComponent<T>(e);
302 }
303
312 template <typename T>
313 inline T& getComponentOr(const Entity e, T& c)
314 {
316
317 if (hasComponent<T>(e))
318 {
319 return registry_.template getComponent<T>(e);
320 }
321 return c;
322 }
323
332 template <typename T>
333 inline const T& getComponentOr(const Entity e, const T& c) const
334 {
336
337 if (hasComponent<T>(e))
338 {
339 return registry_.template getComponent<T>(e);
340 }
341 return c;
342 }
343
350 template <typename T>
351 inline bool hasComponent(const Entity e) const
352 {
354
355 return registry_.template hasComponent<T>(e);
356 }
357
364 template <typename... Ts>
365 inline size_t getComponentCount() const
366 {
368
369 return registry_.template size<Ts...>();
370 }
371
372 inline size_t getComponentCount() const
373 {
375
376 return getComponentCount<AllComponentTypes...>();
377 // return registry_.size();
378 }
379
384 template <typename T>
385 inline void clearComponent()
386 {
388
389 registry_.template clear<T>();
390
391 EASYS_LOG_INFO(std::format("Clearing all components of type {}", typeid(T).name()));
392 }
393
399 template <typename... Ts>
400 inline void clearComponents()
401 {
403
404 // registry_.template clear<Ts...>();
405 (clearComponent<Ts>(), ...);
406 }
407
408 inline void clearComponents()
409 {
411
412 (clearComponent<AllComponentTypes>(), ...);
413 // registry_.clear();
414 }
415
420 inline void clear()
421 {
423
425 clearEntities();
426 }
427
428 private:
429 std::queue<Entity> availableEntityIds_;
430 std::set<Entity> entities_;
431 Registry<AllComponentTypes...> registry_;
432
433 void clearEntities()
434 {
436
437 entities_.clear();
438
439 std::queue<Entity> empty;
440 std::swap(availableEntityIds_, empty);
441
442 for (Entity entity = 0; entity < MAX_ENTITIES; entity++)
443 {
444 availableEntityIds_.push(entity);
445 }
446
447 EASYS_LOG_INFO("Cleared all entities");
448 }
449};
450
451} // namespace Easys
Manages entities and components in an Entity-Component-System architecture.
Definition ecs.hpp:21
View getEntities() const
Returns a vector of entities that have all of the specified component types. Use smaller components f...
Definition ecs.hpp:155
void addComponent(const Entity e, T component)
Adds a component of type T to an entity.
Definition ecs.hpp:181
Entity addEntity()
Adds a new entity to the ECS.
Definition ecs.hpp:67
void modifyComponent(const Entity e, Func &&fn)
Modifies a component of type T for a given entity.
Definition ecs.hpp:204
void clearComponent()
Removes component of specific type from all entities within the ECS.
Definition ecs.hpp:385
void clearComponents()
Definition ecs.hpp:408
const T & getComponent(const Entity e) const
Retrieves a reference to a component of type T from an entity.
Definition ecs.hpp:297
size_t getEntityCount() const
Returns the total number of active entities in the ECS.
Definition ecs.hpp:166
size_t getComponentCount() const
Returns the total count of components of the specified types within the ECS.
Definition ecs.hpp:365
void removeEntity(const Entity e)
Removes an entity and all its associated components from the ECS.
Definition ecs.hpp:91
void clear()
Clears all entities and components from the ECS.
Definition ecs.hpp:420
T & getComponent(const Entity e)
Retrieves a reference to a component of type T from an entity.
Definition ecs.hpp:283
size_t getComponentCount() const
Definition ecs.hpp:372
ECS(const std::set< Entity > &oldEntities)
Initializes the ECS with a specific set of entities.
Definition ecs.hpp:43
bool hasEntity(const Entity e) const
Checks if an entity exists within the ECS.
Definition ecs.hpp:110
View getEntities() const
Returns a reference to the set of all entities.
Definition ecs.hpp:128
const T & getComponentOr(const Entity e, const T &c) const
Retrieves a reference to a component of type T from an entity. If the entity does not exist or does n...
Definition ecs.hpp:333
void clearComponents()
Removes components of specific types from all entities within the ECS.
Definition ecs.hpp:400
ECS()
Initializes the ECS with a predefined maximum number of entities (MAX_ENTITIES).
Definition ecs.hpp:27
void removeComponents(const Entity e)
Removes all components from an entity.
Definition ecs.hpp:268
void removeComponent(const Entity e)
Removes a component of type T from an entity.
Definition ecs.hpp:242
T & getComponentOr(const Entity e, T &c)
Retrieves a reference to a component of type T from an entity. If the entity does not exist or does n...
Definition ecs.hpp:313
bool hasComponent(const Entity e) const
Checks if an entity has a component of type T.
Definition ecs.hpp:351
void removeComponents(const Entity e)
Removes all components of types Ts from an entity.
Definition ecs.hpp:257
void modifyComponent(const Entity e, T c)
Modifies a component of type T for a given entity.
Definition ecs.hpp:225
Definition registry.hpp:15
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
A lightweight, read-only snapshot of a set of entities.
Definition view.hpp:30
#define EASYS_LOG_ENTRY_EXIT
Definition log.hpp:184
#define EASYS_LOG_ERROR(msg)
Definition log.hpp:180
#define EASYS_E_STR(e)
Definition log.hpp:193
#define EASYS_LOG_INFO(msg)
Definition log.hpp:181
#define EASYS_EC_STR(e)
Definition log.hpp:194
Definition ecs.hpp:14
const Entity MAX_ENTITIES
Definition entity.hpp:12
EASYS_ENTITY_TYPE Entity
Definition entity.hpp:11