This is part of an ongoing series where we write a complete 2D game engine in C++ and SFML. A new tutorial is released every Monday. You can find the complete list of tutorials here and download the source code from the projects GitHub page.
This week we are going to add a friend for the player. We’ll refractor the player creation code to reuse as much of it as possible and we’ll also create a new collision layer for the character and setup collisions between the player and his new friend.In the resources folder, you’ll find a new sprite sheet for the character called Skeleton.png.
The layout is the same as the player’s sprite sheet with the walking sprites on lines 9 to 12, melee attack on lines 13 to 16, and projectile attack on lines 17 to 20. Each line has the animation for a separate direction. Unlike the player, the skeleton has a dagger and no bow. Using the same layout will allow us to use the same code to initialise the animations for both characters.Before we write the code to add the skeleton to the game, we’ll move player creation to it’s own function:
Cut and paste all the code associated with player creation from the OnCreate function into the new CreatePlayer function.
Call the function in OnCreate. So with the player creation code removed, OnCreate now looks like this:
Add a new function to create the skeleton.
This will contain all of the code we use to instantiate the new character. Writing a separate function for each character is not sustainable for anything but the smallest game but it will do for now. We’ll look at different ways of doing this in future as we scale the game.
You may notice that much of this code is similar to the code we use to create the player, we’ll deal with that shortly. For now, call the CreateFriend function in OnCreate straight after we call the CreatePlayer function.
I’ve also commented out the lines where we create the level so we can focus on the new player.
Player standing with his new friend.
We don’t add as many components to the friend but it is very similar to that of CreatePlayer. In fact, the majority of each function is responsible for building animations and this is the same in both so we can refractor animation construction into its own function.
This function receives a shared pointer to the object and an id of the sprite sheet. Using this it will build the idle, walking, and projectile animations for the object.
Now we can remove the code that creates the animation component in CreatePlayer and CreateFriend and instead call AddAnimationComponent.
This reduces the size of both functions considerably. We could continue to separate common code however as these functions are just temporary I don’t want to spend too much time refactoring.
Now if you run the game you may have noticed that the player can walk right through his friend. The friend has a box collider but its collision layer is currently set to ‘Player’. The player layer doesn’t collide with itself, so let’s create a new collision layer for our friend. First, add a new entry to the CollisionLayer enum for the layer.
And then set the friends collider to that layer.
When we create a new layer we need to define if it collides with other layers in S_Collidables constructor. At the moment we want the player layer to collide with the NPC layer.
Now the player layer should collide with the default, tile, and npc layers. We can test the collisions by running the game and walking into our skeleton friend.
Player colliding with his friend.
Over the next few weeks, we’ll work on creating interactions between the player and his new friend. We’ll write code for raycasting and displaying text on the screen so that our friend can say hi.
As always, if you have any suggestions for what you would like covered or are having any trouble implementing a feature, then let me know in the comments and I’ll get back to you as soon as I can.
Thank you for reading 🙂