If you enjoy this tutorial, please consider supporting it by purchasing a book through one of the links on my site, such as this one ->
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.A couple of weeks ago we started work on spawning projectile and ended up with something like this:
Whenever we spawn an arrow we draw the sprite for all four directions as we have no meaningful method of knowing which direction the player is facing. As the title of this tutorial suggests that is all about to change. This week we are going to create a component that we can add to any object with a velocity (i.e. any object that can move), which will calculate the direction the object is facing. We’ll call this component C_Direction.
The sprite sheet for our projectiles contains the arrow for all four directions.Now we have a method of retrieving our current direction we can use that to set which sprite in the sprite sheet we use. C_ProjectileAttack (our projectile attack component) needs to store a reference to the direction component. As is typical we will retrieve the pointer to the component in the Awake function. Now we have the direction component we can retrieve the entities current moving direction when we spawn a projectile in the SpawnProjectile function. However, we still have no way of converting the direction to a texture rect for the arrow sprite. To do this we’ll create an unordered_map with the FacingDirection as the key and an IntRect representing the texture rect as the value. Add the unordered_map called textureDirectionBindings to C_ProjectileAttack. I’ve made the map static because all the projectile attacks will use the same texture (as we only have the one texture at the moment), which means they will also use the same texture rects. As a result, there is no need to maintain separate maps for each projectile attack component. For example, if we have 100 entities that can shoot projectiles in a scene and they all had to maintain a separate map, with each maps size being 40 bytes, we are using 40 * 100 = 4000 bytes in memory. Not a huge memory footprint on today’s computers but it’s nice to be able to save memory when we can. By the way, you can calculate the size of an object using the sizeof function. You may have trouble compiling your code now depending on which compiler you use. If you receive a compilation error saying something like: “Implicit instantiation of undefined template”, then you need to provide a hash as the third template parameter (with the enum being the first and sf::IntRect the second). We’ll create the hash in the C_ProjectileAttack class for now. If we find we need it for anything else we’ll move it to its own separate class. Again if you can compile fine then you do not need to create this hash and you can jump further on to where we initialise the unordered_map in the Start function. The hash object is a functor object, which is an object that defines the () operator and can be treated as if they are a function. If we use them in the core code for the game I’ll go through it in more detail.With the hash created we should set it as the third template parameter in our map.
With that complete, you should be able to compile without issues. For more information on why this was needed have a look at the question and its answers on stack overflow.
We’ll add four entries into the unordered_map, one for each direction. The IntRect accepts four parameters: left, top, width, height. We can work out what we need for each direction by examining the arrow sprite.
Using the image above we know that four directions and there corresponding texture locations are:
- Up = 0, 0, 64, 64
- Left = 64, 0, 64, 64
- Down = 128, 0, 64, 64
- Right = 192, 0, 64, 64
Add these entries in the Start function.And now we can use the rectangle returned from the unordered_map to specify which sprite we want to use. Now when we run the game and fire a projectile (‘e’ key), the correct sprite is used based on the player’s direction. Nice!
The arrow still doesn’t go anywhere but that will all change next week when we look at projectile movement and collisions.
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 🙂