summary refs log tree commit diff stats
path: root/src/entity_manager.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/entity_manager.h')
-rw-r--r--src/entity_manager.h152
1 files changed, 152 insertions, 0 deletions
diff --git a/src/entity_manager.h b/src/entity_manager.h new file mode 100644 index 0000000..5f0f2d4 --- /dev/null +++ b/src/entity_manager.h
@@ -0,0 +1,152 @@
1#ifndef ENTITY_MANAGER_H_C5832F11
2#define ENTITY_MANAGER_H_C5832F11
3
4#include <map>
5#include <typeindex>
6#include <set>
7#include <cassert>
8#include "component.h"
9#include "algorithms.h"
10
11class EntityManager {
12 private:
13 struct EntityData {
14 std::map<std::type_index, std::unique_ptr<Component>> components;
15 };
16
17 std::map<int, EntityData> entities;
18 std::map<std::set<std::type_index>, std::set<int>> cachedComponents;
19
20 int nextEntityID = 0;
21
22 template <class T, class... R>
23 std::set<int> getEntitiesWithComponentsHelper(std::set<std::type_index>& componentTypes)
24 {
25 componentTypes.insert(typeid(T));
26
27 return getEntitiesWithComponents<R...>(componentTypes);
28 }
29
30 template <class... R>
31 std::set<int> getEntitiesWithComponents(std::set<std::type_index>& componentTypes)
32 {
33 return getEntitiesWithComponentsHelper<R...>(componentTypes);
34 }
35
36 public:
37 EntityManager() = default;
38 EntityManager(const EntityManager& copy) = delete;
39
40 int emplaceEntity()
41 {
42 // Find a suitable entity ID
43 while ((entities.count(nextEntityID) == 1) && (nextEntityID >= 0))
44 {
45 nextEntityID++;
46 }
47
48 if (nextEntityID < 0)
49 {
50 nextEntityID = 0;
51
52 while ((entities.count(nextEntityID) == 1) && (nextEntityID >= 0))
53 {
54 nextEntityID++;
55 }
56
57 assert(nextEntityID >= 0);
58 }
59
60 // Initialize the data
61 int id = nextEntityID++;
62 entities[id];
63
64 return id;
65 }
66
67 void deleteEntity(int entity)
68 {
69 assert(entities.count(entity) == 1);
70
71 // Uncache components
72 for (auto& cache : cachedComponents)
73 {
74 cache.second.erase(entity);
75 }
76
77 // Destroy the data
78 entities.erase(entity);
79 }
80
81 template <class T, class... Args>
82 T& emplaceComponent(int entity, Args&&... args)
83 {
84 assert(entities.count(entity) == 1);
85
86 EntityData& data = entities[entity];
87 std::type_index componentType = typeid(T);
88
89 assert(data.components.count(componentType) == 0);
90
91 // Initialize the component
92 std::unique_ptr<T> ptr = std::unique_ptr<T>(new T(std::forward<Args>(args)...));
93 T& component = *ptr;
94 data.components[componentType] = std::move(ptr);
95
96 // Invalidate related caches
97 erase_if(cachedComponents, [&componentType] (std::pair<const std::set<std::type_index>, std::set<int>>& cache) {
98 return cache.first.count(componentType) == 1;
99 });
100
101 return component;
102 }
103
104 template <class T>
105 void removeComponent(int entity)
106 {
107 assert(entities.count(entity) == 1);
108
109 EntityData& data = entities[entity];
110 std::type_index componentType = typeid(T);
111
112 assert(data.components.count(componentType) == 1);
113
114 // Destroy the component
115 data.components.erase(componentType);
116
117 // Uncache the component
118 for (auto& cache : cachedComponents)
119 {
120 if (cache.first.count(componentType) == 1)
121 {
122 cache.second.erase(entity);
123 }
124 }
125 }
126
127 template <class T>
128 T& getComponent(int entity)
129 {
130 assert(entities.count(entity) == 1);
131
132 EntityData& data = entities[entity];
133 std::type_index componentType = typeid(T);
134
135 assert(data.components.count(componentType) == 1);
136
137 return *((T*)data.components[componentType].get());
138 }
139
140 template <class... R>
141 std::set<int> getEntitiesWithComponents()
142 {
143 std::set<std::type_index> componentTypes;
144
145 return getEntitiesWithComponentsHelper<R...>(componentTypes);
146 }
147};
148
149template <>
150std::set<int> EntityManager::getEntitiesWithComponents<>(std::set<std::type_index>& componentTypes);
151
152#endif /* end of include guard: ENTITY_MANAGER_H_C5832F11 */