PixelBullet  0.0.1
A C++ game engine
Loading...
Searching...
No Matches
scene.h
1#pragma once
2
4#include "pixelbullet/scene/component_storage.h"
5#include "pixelbullet/scene/entity_id.h"
6
7#include <functional>
8#include <memory>
9#include <stdexcept>
10#include <string>
11#include <string_view>
12#include <type_traits>
13#include <typeindex>
14#include <unordered_map>
15#include <vector>
16
17namespace pixelbullet
18{
19class SceneSerializer;
20
21class Scene
22{
23public:
24 Scene();
25
26 EntityId CreateEntity();
27 void DestroyEntity(EntityId entityId);
28
29 [[nodiscard]] bool IsAlive(EntityId entityId) const
30 {
31 return entityId.Index() < entities_.size() && entities_[entityId.Index()] == entityId;
32 }
33
34 [[nodiscard]] std::vector<EntityId> GetEntities() const
35 {
36 std::vector<EntityId> entities;
37 entities.reserve(entities_.size());
38 for (const EntityId entity : entities_)
39 {
40 if (entity)
41 {
42 entities.push_back(entity);
43 }
44 }
45 return entities;
46 }
47
48 template <typename T, typename... Args>
49 T& AddComponent(EntityId entityId, Args&&... args)
50 {
51 ASSERT(IsAlive(entityId), "Cannot add component to stale or invalid entity");
52 auto storage = GetOrCreateComponentStorage<T>();
53 T component{ std::forward<Args>(args)... };
54 storage->set.Insert(entityId.Index(), component);
55 return storage->set.Get(entityId.Index());
56 }
57
58 template <typename T>
59 void RemoveComponent(EntityId entityId)
60 {
61 ASSERT(IsAlive(entityId), "Cannot remove component from stale or invalid entity");
62 auto storage = GetOrCreateComponentStorage<T>();
63 storage->set.Erase(entityId.Index());
64 }
65
66 template <typename T>
67 bool HasComponent(EntityId entityId) const
68 {
69 if (!IsAlive(entityId))
70 {
71 return false;
72 }
73
74 const auto typeId = std::type_index(typeid(T));
75 auto it = component_storage_.find(typeId);
76 if (it != component_storage_.end())
77 {
78 const auto* storage = static_cast<const ComponentStorage<T>*>(it->second.get());
79 return storage->set.Has(entityId.Index());
80 }
81 return false;
82 }
83
84 template <typename T>
85 void RegisterComponent(std::string_view serializationName)
86 {
87 RegisterComponentType(
88 std::type_index(typeid(T)), std::string(serializationName), []() { return std::make_unique<ComponentStorage<T>>(); }, true);
89 }
90
91 template <typename T>
92 T& GetComponent(EntityId entityId)
93 {
94 ASSERT(IsAlive(entityId), "Cannot get component from stale or invalid entity");
95 auto storage = GetOrCreateComponentStorage<T>();
96 return storage->set.Get(entityId.Index());
97 }
98
99 template <typename T>
100 const T& GetComponent(EntityId entityId) const
101 {
102 ASSERT(IsAlive(entityId), "Cannot get component from stale or invalid entity");
103 const auto* storage = TryGetComponentStorage<T>();
104 ASSERT(storage, "Component not found");
105 return storage->set.Get(entityId.Index());
106 }
107
108 template <typename T>
109 const SparseSet<T>& GetComponentSet() const
110 {
111 const auto typeId = std::type_index(typeid(T));
112 auto it = component_storage_.find(typeId);
113 if (it != component_storage_.end())
114 {
115 const auto* storage = static_cast<const ComponentStorage<T>*>(it->second.get());
116 return storage->set;
117 }
118 throw std::runtime_error("Component not found");
119 }
120
121 template <typename T, typename Func>
122 void Each(Func&& func)
123 {
124 auto* storage = TryGetComponentStorage<T>();
125 if (!storage)
126 {
127 return;
128 }
129
130 for (const auto& entry : storage->set)
131 {
132 if (entry.id >= entities_.size())
133 {
134 continue;
135 }
136
137 const EntityId entity = entities_[entry.id];
138 if (!entity)
139 {
140 continue;
141 }
142
143 func(entity, storage->set.Get(entry.id));
144 }
145 }
146
147 template <typename T, typename Func>
148 void Each(Func&& func) const
149 {
150 const auto* storage = TryGetComponentStorage<T>();
151 if (!storage)
152 {
153 return;
154 }
155
156 for (const auto& entry : storage->set)
157 {
158 if (entry.id >= entities_.size())
159 {
160 continue;
161 }
162
163 const EntityId entity = entities_[entry.id];
164 if (!entity)
165 {
166 continue;
167 }
168
169 func(entity, storage->set.Get(entry.id));
170 }
171 }
172
173 template <typename T, typename U, typename Func>
174 void Each(Func&& func)
175 {
176 auto* primary = TryGetComponentStorage<T>();
177 auto* secondary = TryGetComponentStorage<U>();
178 if (!primary || !secondary)
179 {
180 return;
181 }
182
183 if (secondary->set.Size() < primary->set.Size())
184 {
185 for (const auto& entry : secondary->set)
186 {
187 if (entry.id >= entities_.size())
188 {
189 continue;
190 }
191
192 const EntityId entity = entities_[entry.id];
193 if (!entity || !primary->set.Has(entry.id))
194 {
195 continue;
196 }
197
198 func(entity, primary->set.Get(entry.id), secondary->set.Get(entry.id));
199 }
200 return;
201 }
202
203 for (const auto& entry : primary->set)
204 {
205 if (entry.id >= entities_.size())
206 {
207 continue;
208 }
209
210 const EntityId entity = entities_[entry.id];
211 if (!entity || !secondary->set.Has(entry.id))
212 {
213 continue;
214 }
215
216 func(entity, primary->set.Get(entry.id), secondary->set.Get(entry.id));
217 }
218 }
219
220 template <typename T, typename U, typename Func>
221 void Each(Func&& func) const
222 {
223 const auto* primary = TryGetComponentStorage<T>();
224 const auto* secondary = TryGetComponentStorage<U>();
225 if (!primary || !secondary)
226 {
227 return;
228 }
229
230 if (secondary->set.Size() < primary->set.Size())
231 {
232 for (const auto& entry : secondary->set)
233 {
234 if (entry.id >= entities_.size())
235 {
236 continue;
237 }
238
239 const EntityId entity = entities_[entry.id];
240 if (!entity || !primary->set.Has(entry.id))
241 {
242 continue;
243 }
244
245 func(entity, primary->set.Get(entry.id), secondary->set.Get(entry.id));
246 }
247 return;
248 }
249
250 for (const auto& entry : primary->set)
251 {
252 if (entry.id >= entities_.size())
253 {
254 continue;
255 }
256
257 const EntityId entity = entities_[entry.id];
258 if (!entity || !secondary->set.Has(entry.id))
259 {
260 continue;
261 }
262
263 func(entity, primary->set.Get(entry.id), secondary->set.Get(entry.id));
264 }
265 }
266
267 friend Node& operator<<(Node& node, const Scene& scene);
268 friend const Node& operator>>(const Node& node, Scene& scene);
269 friend class SceneSerializer;
270
271private:
272 using ComponentTypeId = std::type_index;
273 using ComponentStorageFactory = std::function<std::unique_ptr<ComponentStorageBase>()>;
274
275 struct ComponentRegistration
276 {
277 std::string name;
278 ComponentStorageFactory factory;
279 bool is_explicit = false;
280 };
281
282 void Serialize(Node& node) const;
283 void Deserialize(const Node& node);
284 void ClearSceneState();
285 void RegisterBuiltInComponents();
286 void RegisterComponentType(ComponentTypeId typeId, std::string serializationName, ComponentStorageFactory factory,
287 bool explicitRegistration);
288 ComponentStorageBase* FindOrCreateStorage(ComponentTypeId typeId, std::string_view serializationName);
289 [[nodiscard]] const ComponentRegistration* FindComponentRegistration(ComponentTypeId typeId) const;
290
291private:
292 std::vector<EntityId> entities_;
293 std::vector<uint8_t> entity_versions_;
294 std::vector<uint32_t> free_entities_;
295 std::unordered_map<ComponentTypeId, std::unique_ptr<ComponentStorageBase>> component_storage_;
296 std::unordered_map<ComponentTypeId, ComponentRegistration> component_registrations_;
297 std::unordered_map<std::string, ComponentTypeId> component_types_by_name_;
298 std::unordered_map<std::string, ComponentStorageFactory> component_storage_factories_by_name_;
299
300private:
301 template <typename T>
302 ComponentStorage<T>* GetOrCreateComponentStorage()
303 {
304 EnsureComponentRegistered<T>();
305
306 const auto typeId = std::type_index(typeid(T));
307 auto it = component_storage_.find(typeId);
308 if (it != component_storage_.end())
309 {
310 return static_cast<ComponentStorage<T>*>(it->second.get());
311 }
312 else
313 {
314 auto storage = std::make_unique<ComponentStorage<T>>();
315 ComponentStorage<T>* ptr = storage.get();
316 component_storage_[typeId] = std::move(storage);
317 return ptr;
318 }
319 }
320
321 template <typename T>
322 ComponentStorage<T>* TryGetComponentStorage()
323 {
324 const auto typeId = std::type_index(typeid(T));
325 auto it = component_storage_.find(typeId);
326 if (it == component_storage_.end())
327 {
328 return nullptr;
329 }
330 return static_cast<ComponentStorage<T>*>(it->second.get());
331 }
332
333 template <typename T>
334 const ComponentStorage<T>* TryGetComponentStorage() const
335 {
336 const auto typeId = std::type_index(typeid(T));
337 auto it = component_storage_.find(typeId);
338 if (it == component_storage_.end())
339 {
340 return nullptr;
341 }
342 return static_cast<const ComponentStorage<T>*>(it->second.get());
343 }
344
345 template <typename T>
346 void EnsureComponentRegistered()
347 {
348 const auto typeId = std::type_index(typeid(T));
349 if (component_registrations_.find(typeId) != component_registrations_.end())
350 {
351 return;
352 }
353
354 RegisterComponentType(
355 typeId, typeid(T).name(), []() { return std::make_unique<ComponentStorage<T>>(); }, false);
356 }
357};
358
359} // namespace pixelbullet
Provides assertion and panic mechanisms with optional custom formatting.
#define ASSERT(condition,...)
Asserts that a condition is true.
Definition assert.h:163
Definition entity_id.h:11
Represents a hierarchical node capable of storing various data types and supporting YAML serializatio...
Definition node.h:45
Definition scene_serializer.h:22
Definition scene.h:22
Definition sparse_set.h:13
Definition component_storage.h:13
Definition component_storage.h:23