diff options
Diffstat (limited to 'src/entity_manager.h')
-rw-r--r-- | src/entity_manager.h | 152 |
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 | |||
11 | class 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 | |||
149 | template <> | ||
150 | std::set<int> EntityManager::getEntitiesWithComponents<>(std::set<std::type_index>& componentTypes); | ||
151 | |||
152 | #endif /* end of include guard: ENTITY_MANAGER_H_C5832F11 */ | ||