Hello again!
In this video, we are going to have an overview of the entity manager.
So this is going to be the second stage of our code refactoring.
We are going to take all the code which is related to entities out of the game loop, and put it into
its own class.
So if the game loop needs to do anything which involves entities. Such as creating a new entity object,
updating all the entities, drawing them and so on, it will now call a member function of the entity
manager.
And the idea of this is to simplify the game loop, and also to provide better abstraction.
So if we want to change the game by creating more entity objects or even adding new types of entities,
then this should make it easier.
The entity manager is going to use polymorphism.
It is going to store the entity objects as pointers to the base class, to the entity class.
And operations will involve calling virtual functions, through these pointers to base. At runtime,
these will resolve to the correct member functions for the actual type of the entity in the game.
It will also provide an interface for performing operations on entities.
And there are two types of operations.
There are operations which will affect all the entities in the game.
For example, destroying all the entities when we reset the game. And operations which will only affect
one type of entity.
So for example, if we want to change the colour of all the bricks.
The entity manager is responsible for managing the lifetime of all the entities in the game.
So the entity manager will create all the objects. And, when necessary, it will delete them. On each iteration
through the game loop,
the manager is going to scan through all the entities. And, if there are any instances which have been
marked as destroyed, then the manager will delete them.
The class will have two data members and these provide different views of the entities. With all_entities,
this will have all the entities in the game, as a vector, and the elements of this vector will be a
unique pointer to the base class.
There is also a grouped_entities which has all the entities, but this time grouped by their type.
And we are going to use a map for this.
The key of the map will depend on the type of the entity, and the value of the map will be a vector
of pointers to entity objects. Again, to the base class.
So this will be all the objects which have the same type as the key. And these are going to be aliases,
or references, if you like.
If this was Java or C#, then these really would be references.
But in C++ you cannot have a container with references.
So we have to use pointers.
And this is actually one of the rare occasions in C++, where it is advisable to use traditional pointers.
Because they are referring to an object which is owned by someone else.
In this case, the object is owned by the unique pointer.
So this is how it will look.
I have got a very simple game with just one ball object and one brick object.
The all_entities vector has unique pointers to all the objects in the game.
grouped_entities, with key ball, will have a vector of pointers to all the ball objects.
So that is just this one.
And with the brick as the key, it will be a vector with pointers to the brick objects.
The unique pointer will allocate memory for the ball object, and then call the constructor for the ball.
When this unique pointer is destroyed, then it will destroy the ball object and release the memory.
And the same goes for the brick.
These pointers here are just pointers which have the raw address.
So if these [unique] pointers go away, then these pointers are going to be invalid.
So when we delete things, we need to make sure that we delete from the grouped_ entities first.
So we get rid of these pointers, so we cannot use them by accident.
And then we delete these pointers which will actually destroy the object.
And then finally the interface to the class.
The create() member function will create an entity object of a given type, and it will update the data members.
So it is going to add it to the vector which has all the entities, and it is going to add it to the map
element which has all the elements of that type.
The rest of the member functions are fairly self-explanatory, really.
refresh() will redraw all the entities.
clear() will destroy everything. get_all() will return all the entities which have a given type.
And then there is this apply_all() function.
This will take a callable object, and then it will iterate over all the entities which have a given type.
And it will call this function with each of the entity objects of that type as its argument.
So this is a bit like an algorithm call really, with a predicate.
So we're going to iterate and then call this function on every element.
And then the update() and draw() member functions are basically the same as we had before, in the game loop.
Okay, so that is it for this video.
In the next video, I will go into the entity manager class in more detail with the implementation, but
that is all for now.
I will see you next time,
but until then, keep coding!