2023-04-29 14:22:25 +00:00
|
|
|
#ifndef ENGINE_INCLUDE_SCENE_H_
|
|
|
|
#define ENGINE_INCLUDE_SCENE_H_
|
2022-11-30 00:46:03 +00:00
|
|
|
|
2023-04-29 14:22:25 +00:00
|
|
|
#include <cassert>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <map>
|
2023-05-24 17:52:06 +00:00
|
|
|
#include <stdexcept>
|
2023-04-29 14:22:25 +00:00
|
|
|
#include <typeinfo>
|
2022-12-15 10:07:22 +00:00
|
|
|
|
2023-05-01 13:13:35 +00:00
|
|
|
#include "ecs_system.h"
|
|
|
|
#include "event_system.h"
|
2023-01-02 17:24:20 +00:00
|
|
|
|
2022-11-30 00:46:03 +00:00
|
|
|
namespace engine {
|
|
|
|
|
2023-04-29 14:22:25 +00:00
|
|
|
class Application;
|
|
|
|
|
|
|
|
class Scene {
|
2023-04-29 14:56:49 +00:00
|
|
|
public:
|
2023-04-29 14:22:25 +00:00
|
|
|
Scene(Application* app);
|
|
|
|
Scene(const Scene&) = delete;
|
|
|
|
Scene& operator=(const Scene&) = delete;
|
|
|
|
~Scene();
|
|
|
|
|
|
|
|
void Update(float ts);
|
|
|
|
|
|
|
|
Application* app() { return app_; }
|
|
|
|
|
|
|
|
EventSystem* event_system() { return event_system_.get(); }
|
|
|
|
|
|
|
|
/* ecs stuff */
|
|
|
|
|
|
|
|
uint32_t CreateEntity(const std::string& tag, uint32_t parent = 0);
|
2023-04-29 14:56:49 +00:00
|
|
|
|
2023-04-29 14:22:25 +00:00
|
|
|
uint32_t getEntity(const std::string& tag, uint32_t parent = 0);
|
|
|
|
|
|
|
|
size_t GetComponentSignaturePosition(size_t hash);
|
2023-04-29 14:56:49 +00:00
|
|
|
|
2023-04-29 14:22:25 +00:00
|
|
|
template <typename T>
|
2023-05-02 11:02:43 +00:00
|
|
|
void RegisterComponent() {
|
2023-04-29 14:22:25 +00:00
|
|
|
size_t hash = typeid(T).hash_code();
|
|
|
|
assert(component_arrays_.contains(hash) == false &&
|
2023-04-29 14:56:49 +00:00
|
|
|
"Registering component type more than once.");
|
2023-04-29 14:22:25 +00:00
|
|
|
component_arrays_.emplace(hash, std::make_unique<ComponentArray<T>>());
|
|
|
|
|
|
|
|
size_t signature_position = next_signature_position_;
|
|
|
|
++next_signature_position_;
|
|
|
|
assert(signature_position < kMaxComponents &&
|
2023-04-29 14:56:49 +00:00
|
|
|
"Registering too many components!");
|
2023-04-29 14:22:25 +00:00
|
|
|
assert(component_signature_positions_.contains(hash) == false);
|
|
|
|
component_signature_positions_.emplace(hash, signature_position);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2023-04-29 14:56:49 +00:00
|
|
|
T* GetComponent(uint32_t entity) {
|
2023-04-29 14:22:25 +00:00
|
|
|
auto array = GetComponentArray<T>();
|
|
|
|
return array->GetData(entity);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2023-04-29 14:56:49 +00:00
|
|
|
T* AddComponent(uint32_t entity) {
|
2023-04-29 14:22:25 +00:00
|
|
|
size_t hash = typeid(T).hash_code();
|
|
|
|
|
|
|
|
auto array = GetComponentArray<T>();
|
|
|
|
array->InsertData(entity, T{}); // errors if entity already exists in array
|
|
|
|
|
|
|
|
// set the component bit for this entity
|
|
|
|
size_t signature_position = component_signature_positions_.at(hash);
|
|
|
|
auto& signature_ref = signatures_.at(entity);
|
|
|
|
signature_ref.set(signature_position);
|
|
|
|
|
2023-04-29 14:56:49 +00:00
|
|
|
for (auto& [system_name, system] : systems_) {
|
2023-04-29 14:22:25 +00:00
|
|
|
if (system->entities_.contains(entity)) continue;
|
|
|
|
if ((system->signature_ & signature_ref) == system->signature_) {
|
|
|
|
system->entities_.insert(entity);
|
|
|
|
system->OnComponentInsert(entity);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return array->GetData(entity);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2023-04-29 14:56:49 +00:00
|
|
|
void RegisterSystem() {
|
2023-04-29 14:22:25 +00:00
|
|
|
size_t hash = typeid(T).hash_code();
|
|
|
|
assert(systems_.find(hash) == systems_.end() &&
|
2023-04-29 14:56:49 +00:00
|
|
|
"Registering system more than once.");
|
2023-04-29 14:22:25 +00:00
|
|
|
systems_.emplace(hash, std::make_unique<T>(this));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2023-04-29 14:56:49 +00:00
|
|
|
T* GetSystem() {
|
2023-04-29 14:22:25 +00:00
|
|
|
size_t hash = typeid(T).hash_code();
|
|
|
|
auto it = systems_.find(hash);
|
|
|
|
if (it == systems_.end()) {
|
|
|
|
throw std::runtime_error("Cannot find ecs system.");
|
|
|
|
}
|
|
|
|
auto ptr = it->second.get();
|
|
|
|
auto casted_ptr = dynamic_cast<T*>(ptr);
|
|
|
|
assert(casted_ptr != nullptr);
|
|
|
|
return casted_ptr;
|
|
|
|
}
|
|
|
|
|
2023-04-29 14:56:49 +00:00
|
|
|
private:
|
2023-04-29 14:22:25 +00:00
|
|
|
Application* const app_;
|
|
|
|
uint32_t next_entity_id_ = 1000;
|
|
|
|
|
|
|
|
/* ecs stuff */
|
|
|
|
|
|
|
|
size_t next_signature_position_ = 0;
|
|
|
|
// maps component hashes to signature positions
|
|
|
|
std::map<size_t, size_t> component_signature_positions_{};
|
|
|
|
// maps entity ids to their signatures
|
|
|
|
std::map<uint32_t, std::bitset<kMaxComponents>> signatures_{};
|
|
|
|
// maps component hashes to their arrays
|
|
|
|
std::map<size_t, std::unique_ptr<IComponentArray>> component_arrays_{};
|
|
|
|
// maps system hashes to their class instantiations
|
|
|
|
std::map<size_t, std::unique_ptr<System>> systems_{};
|
|
|
|
|
|
|
|
template <typename T>
|
2023-04-29 14:56:49 +00:00
|
|
|
ComponentArray<T>* GetComponentArray() {
|
2023-04-29 14:22:25 +00:00
|
|
|
size_t hash = typeid(T).hash_code();
|
|
|
|
auto it = component_arrays_.find(hash);
|
|
|
|
if (it == component_arrays_.end()) {
|
|
|
|
throw std::runtime_error("Cannot find component array.");
|
|
|
|
}
|
|
|
|
auto ptr = it->second.get();
|
|
|
|
auto casted_ptr = dynamic_cast<ComponentArray<T>*>(ptr);
|
|
|
|
assert(casted_ptr != nullptr);
|
|
|
|
return casted_ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<EventSystem> event_system_{};
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace engine
|
|
|
|
|
2023-05-24 17:52:06 +00:00
|
|
|
#endif
|