Hi
Could you quickly describe the rough design and maybe show how it can be used?
Some random comments about the code:
E* createEntity(int groupIdentifier)
{
std::unique_ptr<BaseEntity> entity(new E());
entity->setEntityID(mLastEntityID++);
entity->setGroup(groupIdentifier);
entity->setComponentManager(mComponentManager);
mEntityMap.insert(std::make_pair(mLastEntityID , std::move(entity)));
return dynamic_cast<E*>(mEntityMap.at(mLastEntityID).get());
}
Avoid
dynamic_cast, it's almost always a design mistake. Here, it's completely unnecessary; you could just store
std::unique_ptr<E> and then use the derived-to-base conversion when inserting it to the map. In the other cases, you should rather assert that the dynamic type is correct and then use
static_cast in release mode. Logic errors like expecting the wrong type must be recognized immediately, don't hide them by returning a null pointer.
You don't adhere to the Rule Of Three.
A lot of functions are virtual although they needn't be. In
EntityBase, most functions are only accessors to the attributes, why override them?
I would make the protected member variables private. It improves encapsulation and allows to modify the base class without breaking client code.
It's nice that you use RAII (smart pointers and STL containers) to store the objects. For
shared_ptr, make sure it's really necessary and you don't copy it too often (pass by reference). Also use
make_shared() where possible.
Get functions should be const-qualified.
Constructors taking a single element should be explicit, unless conversion is desired.
How do you ensure uniqueness of the integer IDs for entities, groups or component types? I could imagine that this could become a type-safety and scalability problem in a bigger project. An option would be opaque and typesafe handles (i.e. objects hiding the int internally), that your library gives to the user.