I repaired the CollisionManager. It was broke. I dont want to talk about it.
From yesterday though:
When the player fish and an enemy collides, two things will happen in this game right now:
1. The player receives experience points. These are what will make the Player grow and level up though out the game.
2. The enemy will be eaten. In other words both the enemy collider and the enemy object, carrying a sprite and some functions get deleted.
(Enemy object are not discussed in detail in this blog, it is not a part of my artifact. It is connected to the collisions and that’s why a part of it will be mentioned)
The new logic for this is presented below:
In Collider.h there is now a member which is a pointer to a game object called parent.
GameObject.h is a Base class. EnemyFishObject.h inherit from FishObject.h that inherit from GameObject.h. Enemy is a fish that’s an object in the game.
The player fish, PlayerFishObject.h, also inherit from FishObject.h. Player is a fish that’s an object in the game.
The GameObject pointer of the collider class is assigned a game object in the GameObject’s constructor:
As you can see it is also assigned a type(m_sType is a string object). The standard type is “GameObject” but this is altered via an accessor, SetType(std::string type), upon creation of a Player fish, enemy fish or an environmental object for example.
This way all colliders are linked with an object and there is no need for any bool, collider count or anything like that.
Before I show you how I check for collisions and delete the colliders and objects and give the player experience, I need to explain one function of GameObject.h.
virtual void OnCollision(GameObject* p_xOther);
This function is separated from the Collider class’s OnCollision-function. They share names because they work together. In the GameObject’s OnCollision-function, the things that happen to the game objects happen here.
This one is a virtual function, meaning this function can be overridden in the derived classes. This means every separate Game object, such as the player or enemy fish, can use this function in their own individual way, by defining it in their class’s .cpp file for example.
This is the call order of the function calls:
CollisionManager checks every rectangular collider for overlaps. If two of them are colliding, these two colliders call their OnCollision function, with the other collider as a parameter. Here is where the colliders are handled.
From Collider::OnCollision(Collider* p_xOther), the parents of the colliders call their OnCollision(GameObject* p_xOther) in a specific order, and here is where the game objects are handled.
I will go through it step by step with pictures of code.
First of all, are the colliders overlaping?
When there are two colliders overlaping, they will both call their OnCollision with the other collider as a parameter. This is to separate one collision into two different kinds of collisions so that you can perform at least 2 completely different actions if any one collision occurs.
The Collider::OnCollision – function:
Ok, let me break this down.
When m_axRectColliders[i] calls the function it is interpreted that m_axRectColliders[i] is colliding with m_axRectColliders[j].
The first thing that happens is a line of text displays on the consol screen reveling the parents types and which type is colliding with which.
The first nested if statements checks to see if there was a Player vs Enemy collision. If this is the case, the parent of the collider, its game object, calls its OnCollision – function.
Let’s say that the first nested if statement is true. That means the PlayerFishObject’s overridden OnCollision is called. Here is the code:
This means that if player has collided with an enemy, player gives itself experience. In this case the experience is added by 1.
Let’s look at what happens in the other nested if statement in Collider::OnCollision:
This is why this function is always called at least twice. Since the first call to this function in this example was a player vs enemy collision, the next call will be an enemy vs player collision and I can use this information to do something completely different.
Now the EnemyFishObject’s overridden function is called insted, and the pointer to this enemy, m_xParent, in collider.h is set to nullptr. This could otherwise potantially become a dangling pointer when the enemy object is deleted. But just before the pointer is set to nullptr Something else happens:
If the “other” game object p_other is a player, the enemy fish set’s its pointer to its collider to nullptr and call its destructor. What happens there is its sprite is deleted. This is only to have the image of the enemy disappear. The actual object is deleted in GameObjectManager. This will only be mentioned briefly, GameObjectManager Updates all objects. If there is a game object in the GameObject vector array that has a pointer to a collider set to point to nullptr, it is erased.
The last thing that happens is that the actual collider is removed.
The enemy collider is still existing but there is one thing separating it from the other colliders. Its link to the game object, m_xParent, is pointing to nullptr.
As of now, the collisionManager takes care of this with a function called RemoveEnemyCollider():
As you can probably see, if the link is broken, in other words if the collider’s parent points to nullptr, the collider object is deleted.
This is a better way to handle collisions than the former way I used because it is one step closer to having made a more dynamic collisionManager. There are some things that I would have to fix or change before I really have a dynamic collisionManager but an improvement is an improvement.
At least now I won’t have to worry about different bools and ints that complicate the coding and the readability of the code. And only with that removed, the CollisionManager is made more efficient.