Program Listing for File componentManager.h
↰ Return to documentation for file (PrismEngine/src/componentManager.h)
#pragma once
#include "entity.h"
#include <unordered_map>
#include <set>
#include <typeindex>
#include <memory>
#include <algorithm>
#include <iterator>
#include <vector>
namespace prism {
namespace scene {
class ComponentManager
{
public:
ComponentManager() = default;
template<typename T>
bool addComponent(Entity entityId, T&& component) {
auto& storage = getComponentStorage<std::decay_t<T>>();
storage.addComponent(entityId, std::forward<T>(component));
return true;
}
template<typename T>
bool removeComponent(Entity entityId) {
ComponentStorage<T>& storage = getComponentStorage<T>();
return storage.removeComponent(entityId);
}
template<typename T>
bool hasComponent(Entity entityId) const {
const ComponentStorage<T>* storage = getComponentStorageConst<T>();
return storage ? storage->hasComponent(entityId) : false;
}
template<typename T>
T* getComponent(Entity entityId) {
ComponentStorage<T>& storage = getComponentStorage<T>();
return storage.getComponent(entityId);
}
template<typename T>
const std::vector<Entity>& getEntitiesWith() const {
static const std::vector<Entity> empty;
const ComponentStorage<T>* storage = getComponentStorageConst<T>();
return storage ? storage->entities : empty;
}
template<typename T>
struct StorageView {
const std::vector<T>& components;
const std::vector<Entity>& entities;
};
template<typename T>
StorageView<T> view() const {
const auto* storage = getComponentStorageConst<T>();
if (storage) {
return { storage->components, storage->entities };
}
else {
static const std::vector<T> emptyComp;
static const std::vector<Entity> emptyEnt;
return { emptyComp, emptyEnt };
}
}
template<typename... ComponentTypes>
std::vector<Entity> getEntitiesWithAll() const {
if constexpr (sizeof...(ComponentTypes) == 0) return {};
else {
// Собираем векторы сущностей для каждого типа
std::vector<const std::vector<Entity>*> entityVectors;
(entityVectors.push_back(&getEntitiesWith<ComponentTypes>()), ...);
// Выбираем самый маленький вектор для итерации
auto smallestIt = std::min_element(entityVectors.begin(), entityVectors.end(),
[](const auto* a, const auto* b) { return a->size() < b->size(); });
const auto& smallestVec = **smallestIt;
std::vector<Entity> result;
result.reserve(smallestVec.size());
for (Entity e : smallestVec) {
if ((hasComponent<ComponentTypes>(e) && ...)) {
result.push_back(e);
}
}
return result;
}
}
void removeAllComponents(Entity entityId);
private:
struct IComponentStorage {
virtual ~IComponentStorage() = default;
virtual void removeEntity(Entity entityId) = 0;
};
template<typename T>
struct ComponentStorage : public IComponentStorage {
std::vector<T> components;
// @brief Сущности, соответствующие компонентам
std::vector<Entity> entities;
// @brief Позиция в массивах
std::unordered_map<Entity, size_t> entityToIndex;
template<typename U>
void addComponent(Entity entity, U&& component) {
auto it = entityToIndex.find(entity);
if (it != entityToIndex.end()) {
components[it->second] = std::forward<U>(component);
return;
}
size_t index = components.size();
components.push_back(std::forward<U>(component));
entities.push_back(entity);
entityToIndex[entity] = index;
}
bool removeComponent(Entity entity) {
auto it = entityToIndex.find(entity);
if (it == entityToIndex.end()) return false;
size_t index = it->second;
size_t lastIndex = components.size() - 1;
if (index != lastIndex) {
components[index] = std::move(components[lastIndex]);
entities[index] = entities[lastIndex];
entityToIndex[entities[index]] = index;
}
components.pop_back();
entities.pop_back();
entityToIndex.erase(it);
return true;
}
T* getComponent(Entity entity) {
auto it = entityToIndex.find(entity);
if (it == entityToIndex.end()) return nullptr;
return &components[it->second];
}
bool hasComponent(Entity entity) const {
return entityToIndex.find(entity) != entityToIndex.end();
}
void removeEntity(Entity entityId) override {
removeComponent(entityId);
}
};
template<typename T>
ComponentStorage<T>& getComponentStorage() {
auto typeIndex = std::type_index(typeid(T));
auto it = componentStorages.find(typeIndex);
if (it == componentStorages.end()) {
auto storage = std::make_unique<ComponentStorage<T>>();
auto* ptr = storage.get();
componentStorages[typeIndex] = std::move(storage);
return *ptr;
}
return static_cast<ComponentStorage<T>&>(*it->second);
}
template<typename T>
const ComponentStorage<T>* getComponentStorageConst() const {
auto typeIndex = std::type_index(typeid(T));
auto it = componentStorages.find(typeIndex);
if (it == componentStorages.end()) return nullptr;
return static_cast<const ComponentStorage<T>*>(it->second.get());
}
// Карта "тип -> хранилище"
std::unordered_map<std::type_index, std::unique_ptr<IComponentStorage>> componentStorages;
};
}
}