Something I use in my game engine that I find highly useful is what I call a manager.

My managers are essentially classes that handle the generation and processing of entities. It sort of shares some concepts of Factory Design, but it is a little more particular.

EntityManager

I have the EntityManager, which is the parent manager class that holds the template methods for entity processing. It also holds the interface for any child manager that will be created under it.

Example: EnemyManager

I have a child class of EntityManager called EnemyManager. This class will be the overarching “factory” that handles the creation and processing of Enemies within the game. Inside this class, I have created containers (I use std::vectors) to hold the particular enemies that I desire.

std::vector<GuardDog *> m_guarddogcontainer;

This container will hold new instances of generated GuardDogs. You could use smart pointers in the container as well (which is what I actually use).

Next, I will create a method that allows me to generate a new Guard Dog.

GuardDog *MakeGuardDog(Vector pos, float speed, PathFinder *pathfinder, SoundManager *soundmanager);

This is why I called my manager class particular. Each entitiy may need certain parameters passed to it. So, a call to a generic MakeGuardDog() will not work because the Init() of the actual GuardDog class may need to be told how fast he is, how loud he is, and so on.

Now, MakeGuardDog will build a new instance of a GuardDog object and push it to m_guarddogcontainer. Within my game state (which houses the managers), loop EnemyManager::Think(), Draw(), etc. to think the GuardDog container, allowing all instanced GuardDogs to run within the game world.

It is also worth noting above that MakeGuardDog * returns a pointer to the newly created entity. This is if I need to immediately interact with the new instance of GuardDog.

Say I have a SoundManager that handles the creation and processing of sounds, I could call SoundManager::MakeSound(), get a pointer to the newly created sound, and attach it immediately to the entity that created it.

For Example: I create a helicopter and the helicopter creates a looping sound for its rotor. During initialization of the Helicopter instance, I could call SoundManager::MakeLoopedSound(), which will return a pointer to the newly made sound. Now, I can attach that sound to my Helicopter and allow its position in the world to be updated along with my helicopter movement. This shows how immediate access to a newly created entity can be useful.

Child Implementation

virtual void Think() = 0;

virtual void Draw() = 0;

virtual void UpdateCollision() = 0;

virtual void Cleanup() = 0;

Each child of EntityManager needs to have an implementation to handle the processing of their created entities. This allows each type of entity within the manager to be handled in whatever order or method in which it needs to be handled. So, if I want a certain type of Enemy to update or Draw() before another type, I can do that.

When each manager is finished (a new world loads, the game is exited…), Cleanup() makes sure all memory is freed up before we move on.

Manager Entity Pool

Each entity within the game world can be set as alive or dead. If an enemy is killed or a projectile hits a wall, it is set as dead. If an entity is dead, it is no longer processed within its particular EntityManager. Now, within the container, we have a dead entities waiting to be remade and reused. These entities contribute to what I call the Entity Pool. So, instead of just deleting and removing an entity from the container when it is no longer used, leaving empty spots in the container and forcing reinstantiation and reallocation of brand new entities, I can reuse dead ones.

The entities that seem to gain the most benefit from the pool system are ones that are dead and remade often, such as projectiles and sounds.

Conclusion

I use EntityManagers to generate, process, draw, and handle the lifetime of the major entities within the game world. They do a good job at keeping all the creation and processing duties contained.