game-engine/libs/ecs/componentmanager.cpp
2024-10-10 14:00:33 -04:00

117 lines
4 KiB
C++

#include "componentmanager.hpp"
#include <cassert>
#include <memory>
/**
* ComponentArray
**/
template <typename T>
void ComponentArray<T>::InsertData(Entity entity, T component) {
assert(mEntityToIndexMap.find(entity) == mEntityToIndexMap.end() &&
"Component added to same entity more than once.");
// Put new entry at end and update the maps
size_t newIndex = mSize;
mEntityToIndexMap[entity] = newIndex;
mIndexToEntityMap[newIndex] = entity;
mComponentArray[newIndex] = component;
++mSize;
};
template <typename T> void ComponentArray<T>::RemoveData(Entity entity) {
assert(mEntityToIndexMap.find(entity) != mEntityToIndexMap.end() &&
"Removing non-existent component.");
// Copy element at end into deleted element's place to maintain density
size_t indexOfRemovedEntity = mEntityToIndexMap[entity];
size_t indexOfLastElement = mSize - 1;
mComponentArray[indexOfRemovedEntity] = mComponentArray[indexOfLastElement];
// Update map to point to moved spot
Entity entityOfLastElement = mIndexToEntityMap[indexOfLastElement];
mEntityToIndexMap[entityOfLastElement] = indexOfRemovedEntity;
mIndexToEntityMap[indexOfRemovedEntity] = entityOfLastElement;
mEntityToIndexMap.erase(entity);
mIndexToEntityMap.erase(indexOfLastElement);
--mSize;
};
template <typename T> T &ComponentArray<T>::GetData(Entity entity) {
assert(mEntityToIndexMap.find(entity) != mEntityToIndexMap.end() &&
"Retrieving non-existent component.");
// Return a reference to the entity's component
return mComponentArray[mEntityToIndexMap[entity]];
};
template <typename T> void ComponentArray<T>::EntityDestroyed(Entity entity) {
if (mEntityToIndexMap.find(entity) != mEntityToIndexMap.end()) {
// Remove the entity's component if it existed
RemoveData(entity);
}
};
/**
* ComponentManager
**/
// Private functions
template <typename T>
std::shared_ptr<ComponentArray<T>> ComponentManager::GetComponentArray() {
const char *typeName = typeid(T).name();
assert(mComponentTypes.find(typeName) != mComponentTypes.end() &&
"Component not registered before use.");
return std::static_pointer_cast<ComponentArray<T>>(
mComponentArrays[typeName]);
}
// Public functions
template <typename T> void ComponentManager::RegisterComponent() {
const char *typeName = typeid(T).name();
assert(mComponentTypes.find(typeName) == mComponentTypes.end() &&
"Registering component type more than once.");
// Add this component type to the component type map
mComponentTypes.insert({typeName, mNextComponentType});
// Create a ComponentArray pointer and add it to the component arrays map
mComponentArrays.insert({typeName, std::make_shared<ComponentArray<T>>()});
// Increment the value so that the next component registered will be different
++mNextComponentType;
};
template <typename T> ComponentType ComponentManager::GetComponentType() {
const char *typeName = typeid(T).name();
assert(mComponentTypes.find(typeName) != mComponentTypes.end() &&
"Component not registered before use.");
// Return this component's type - used for creating signatures
return mComponentTypes[typeName];
}
template <typename T>
void ComponentManager::AddComponent(Entity entity, T component) {
// Add a component to the array for an entity
GetComponentArray<T>()->InsertData(entity, component);
}
template <typename T> void ComponentManager::RemoveComponent(Entity entity) {
// Remove a component from the array for an entity
GetComponentArray<T>()->RemoveData(entity);
}
template <typename T> T &ComponentManager::GetComponent(Entity entity) {
// Get a reference to a component from the array for an entity
return GetComponentArray<T>()->GetData(entity);
}
void ComponentManager::EntityDestroyed(Entity entity) {
// Notify each component array that an entity has been destroyed
// If it has a component for that entity, it will remove it
for (auto const &pair : mComponentArrays) {
auto const &component = pair.second;
component->EntityDestroyed(entity);
}
};