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 will add a new projectile attack animation to our player. We will be working on the projectile system over the next few weeks as we will need to make changes to our current movement system by creating a velocity and direction component, update our animation system so that we can run actions on animation frames, and update our collision system to enable objects to communicate with each other when they collide. But for this week we’ll start simply by:
- Creating and adding a new projectile animation for the player.
- Adding a new projectile animation state in our animation system.
- Writing a component that will run the new projectile animation.
This is a similar process to how we created our previous walk and idle animations. Start by creating the projectile animation in SceneGame right after we create the walking animation. It uses the same sprite sheet as the other animations (Player.png), which can be found in the resources folder for this weeks tutorial.
I’ve included the complete OnCreate function because, as well as adding the projectile animations, I’ve also changed the way we create the other animations. Instead of creating the animation directions individually we now use a loop. A small change but it reduces the size of the function considerably. If we move to a more data-driven engine (where we store all the entity data in files and parse those files to create our entities instead of creating them in code) we would be able to remove most of the initialisation code for the animations.
The projectile animation state does not yet exist so let’s add it to the projectile AnimationState enum in C_Animation.
With the animation state added and the animation added to the object, we now need some way of activating the animation when the player presses a specific key. We’ll create a component to do this. Create a new class called C_ProjectileAttack.
The Update function checks if the ‘e’ key is pressed and sets the entities animation state to ‘Projectile’, which will play our new projectile attack animation.
The ‘e’ key is not currently part of our Input system so we should add it now. To add a key we first add it the Key enum in the Input class.
We then need to check if the key has been pressed at the end of the Input’s Update function.
For more information on how this works see the previous tutorial where we created the Input system.The last step is to add the new component to the player. We’ll do this in SceneGame’s OnCreate function.
I add the component just before we add the player to the object collection near the end of the function. Don’t forget to set the projectile attacks input. It is a bit of a pain that we have to manually inject our component with common classes (such as the Input class), we’ll look at a better way of doing this in the next few weeks.
Now if you run the game and press the ‘e’ key absolutely nothing happens, which at first doesn’t make much sense. Surely if we are pressing the correct key the component should be playing our projectile animation. And in fact it is but it’s being overridden by the keyboard movement as it is always setting the animation to either idle or walking.
To fix this we will need to create a separate velocity component and create a new way of setting the animation based on movement speed, which is what we will cover next week. However, if you would like a sneak peek of what the animations look like you can temporarily disable the keyboard controller by adding a return statement at the beginning of the Update function.
Then when you run the game and press the e key you’ll see the projectile attack animation.
You’ll only be able to see the animation for shooting down as we’re no longer setting the facing direction in the keyboard controller.
Before you finish for the week don’t forget to remove the return statement if you added it.
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 🙂