I'm currently trying to wrap my head around Entity, Component and Systems and I'm having a few problems with my design so far.
Basically Entities is a class that contains an index-value and an unique id associated with said index. I feel the way I create, store, recycle and iterate through the entities in the manger is quite unefficient and the code is filled with cluttery. I'm currently using a number of vectors that is somewhat hard to keep synced ( index-wise ) with each other.
#ifndef ENTITYMANAGER_HPP
#define ENTITYMANAGER_HPP
#include <vector>
#include "Entity.hpp"
#include "Component.hpp"
#include "System.hpp"
class EntityManager {
private:
unsigned int indexCount;
std::vector< Entity* > activeEntities;
std::vector< Entity* > deadEntities;
std::vector< std::vector<Component*> > components;
std::vector< System* > systems;
public:
EntityManager();
~EntityManager();
Entity createEntity();
void killEntity(Entity entity);
void registerComponent(Entity entity, Component* component);
void removeComponent(Entity entity, CID cid);
Component* getComponent(Entity entity, CID cid);
bool isAlive(Entity entity);
void invokeSystems();
};
#endif
#include "EntityManager.hpp"
#include "DummySystem.hpp"
EntityManager::EntityManager():indexCount(0) {
deadEntities.reserve(100);
activeEntities.reserve(100);
// This will initialize 100, like reserve but for 2D vectors.
components.reserve(100);
components.resize(100, std::vector<Component*>(CID::UNIQUE_COUNT, nullptr) );
systems.push_back(new DummySystem(this));
}
EntityManager::~EntityManager() {
for(Entity* e : activeEntities) delete e;
for(Entity* e : deadEntities) delete e;
for(System* s : systems) delete s;
for(auto& v : components)
for(Component* c : v) delete c;
}
Entity EntityManager::createEntity() {
// Try to recycle a dead entity
if ( !deadEntities.empty() ) {
Entity* entity = deadEntities.back();
deadEntities.pop_back();
// Give it a new unique id to make sure it is treated as a new entity
entity->setUID(entity->getUID()+1);
activeEntities[entity->getIndex()] = entity;
return (*entity);
}
Entity* entity = new Entity(indexCount++,0);
activeEntities.push_back(entity);
components.push_back( std::vector<Component*>(CID::UNIQUE_COUNT) );
return (*entity);
}
void EntityManager::killEntity(Entity entity) {
if (!isAlive(entity)) return;
for(int i = 0; i < CID::UNIQUE_COUNT; i++) {
delete components[entity.getIndex()][i];
components[entity.getIndex()][i] = nullptr;
}
deadEntities.push_back(activeEntities[entity.getIndex()]);
activeEntities[entity.getIndex()] = nullptr;
}
Component* EntityManager::getComponent(Entity entity, CID cid) {
if (!isAlive(entity)) return nullptr;
return components[entity.getIndex()][cid];
}
bool EntityManager::isAlive(Entity entity) {
if ( activeEntities.empty() ) return false;
if ( activeEntities[entity.getIndex()] == nullptr ) return false;
if ( activeEntities[entity.getIndex()]->getUID() != entity.getUID()) return false;
return true;
}
void EntityManager::registerComponent(Entity entity, Component* component) {
if (!isAlive(entity)) return;
if ( component == nullptr ) return;
if ( components[entity.getIndex()][component->getCID()] != nullptr )
delete components[entity.getIndex()][component->getCID()];
components[entity.getIndex()][component->getCID()] = component;
}
void EntityManager::removeComponent(Entity entity, CID cid) {
if (!isAlive(entity)) return;
if ( components[entity.getIndex()][cid] != nullptr )
delete components[entity.getIndex()][cid];
components[entity.getIndex()][cid] = nullptr;
}
void EntityManager::invokeSystems() {
for(Entity* e : activeEntities)
if (e != nullptr)
for(System* sys : systems) sys->process(e);
}
Should I rather use another container? Like std::set or std::map and just use a unsigned int id as a key?
Should the EntitySystem handle both entities, components and systems?