PC Games
• Orb Tutorials
• 2D shoot 'em up Latest Updates
SDL2 Versus game tutorial
Download keys for SDL2 tutorials on itch.io
The Legend of Edgar 1.37
SDL2 Santa game tutorial 🎅
SDL2 Shooter 3 tutorial
Tags • android (3) • battle-for-the-solar-system (10) • blob-wars (10) • brexit (1) • code (6) • edgar (9) • games (43) • lasagne-monsters (1) • making-of (5) • match3 (1) • numberblocksonline (1) • orb (2) • site (1) • tanx (4) • three-guys (3) • three-guys-apocalypse (3) • tutorials (17) • water-closet (4) Books The Red Road For Joe Crosthwaite, surviving school was about to become more than just a case of passing his exams ... |
— Mission-based 2D shoot 'em up — Note: this tutorial assumes knowledge of C, as well as prior tutorials.
Introduction We've made a good start so far. We can fly our ship around, and see the starfield and background scroll along with it. What would be great to add in now is our weapons system. After all, this is a shoot 'em up. We're going to initally focus on the main guns, and add in the secondary weapons later on. Extract the archive, run cmake CMakeLists.txt, followed by make, and then use ./shooter3-02 to run the code. You will see a window open like the one above. Use the WASD control scheme to move the fighter around. Hold J to fire your main gun. The KIT-E fighter will support a number of upgrades, including rate of fire, number of shots fired, and damage. To modify these, you can edit game.c (starting at line 15), recompile, and run again: game.kite.reload = {1 - 20}; game.kite.output = {1 - 5}; game.kite.damage = {1 - 999}; Updating the values to one shown in the curly braces will modify the KIT-E's guns. A lower reload value will make the KIT-E fire faster. An output value between 1 and 5 will change the number of shots fired. damage will change the damage done per shot (although there is nothing to shoot right now). Obviously, you should use a literal number and not the curly braces shown here. When you're finished, close the window to exit. Inspecting the code Adding the ability to fire is something we've seen quite a few times before, and so we'll be sticking with the same forumla for issuing bullets. There are quite a few tweaks that need to be made to the code to enable this, but nothing out of the ordinary. So, let's start with defs.h:
We've added in a define to represent the minimum reload value of the KIT-E's guns. Having this as a constant will prove useful later. We've also added an enum:
The SIDE enum is something we've seen before, and will be used to determine to which side an entity belongs. In our game, aliens cannot shoot other aliens, and the player cannot harm any buddies that might also exist in the stage. We saw this used in both SDL2 Shooter and Battle Arena Donk. On to the updates the structs.h. Starting with Fighter:
We've added in a `reload` field, to handle the rate of fire. Next, we've added in a Bullet struct:
Again a familiar object. The only new thing here is a `tick` function. This exists to support the various different weapon type, that will all exhibit different behaviours. We'll see this come into full use when we start on the optional weapons. Of course, we've updated Stage:
We're supporting a Bullet linked list. Finally, we've added in a Game struct:
Not a lot in here right now, except for the KIT-E's data. This struct will be greatly expanded in future parts. Since we've seen the Game struct, we might as well discuss game.c quickly. There is only one function here - initGame:
We're defaulting our KIT-E's weapons systems here. As we'll see later, when we do things with our player's fighter, we'll often reference the `kite` struct in Game, as it's where we'll store the configuration, rather than embed it into a Fighter object. It allows us to work with a single point of truth as much as possible. initGame is called in the `main` (in main.c) function right now. Moving over to fighters.c, we've updated the fighterTick function:
We're decreasing the value of the fighter's `reload` variable, limiting it to 0. When `reload` is 0, our fighter will be able to fire their guns. Now over to player.c, where we've made a lot more changes. Starting with initPlayer:
The player entity's `side` is set to SIDE_CATS, since he is on the side of the felines (in case you're wondering what the plot of our game is, we'll get to that in a later part - short version is that it's cats vs greebles). We've also updated doPlayerControls:
We're now testing if the player's `reload` is 0 and that the fire control has been pressed (CONTROL_FIRE), and calling fireGuns if so. The fireGuns function is where the interesting things happen:
That's quite a big function, but one that's easy to understand. To begin with, we're assigning two variables: `dx`, that will determine the direction our bullet will travel, based on the direction the player is facing; and `y`, which will be the vertical position from where the bullet originates, based on the player's position, plus half the sprite's height. With that done, we're going to work out how many bullets we want to fire. Here is where we'll check the value of Game's `kite`'s `output`. We'll then call addStandardBullet the appropriate number of times, using a configuration for how we want the bullets to behave. We'll see how addStandardBullet works in a little while, but in summary our bullets will be fired as single, dual, or a spread format as the value of output increases. To the function, we're passing through the `dx` and `y` variables that we precalculated. Now let's turn our attention to bullets.c. Starting with initBullets:
Okay, we're preparing a linked list and loading some textures. Nothing special. Turning next to doBullets:
Again, a standard processing loop. Here, we're moving the bullets (adding `dx` and `dy` to `x` and `y`), decreasing health, and calling the `tick` function. We're also removing dead bullets (`health` being 0 or less). On to drawBullets:
Okay, we're calling each bullet's `draw` function, nothing more. We'll see the draw and tick functions we've set shortly. We also have a spawnBullet function:
We're just creating a bullet, adding it to our linked list, setting the `owner` to the entity passed into the function, and returning the bullet. This is basically going to be a shared function to generate a bullet. Now for the addStandardBullet function, that is being called when we fire the player's guns:
This function will create a bullet, set its `owner`, `damage`, vertical position (`y`), and velocity (`dx` and `dy`) using the parameters passed into the function. It will also assign the bullet's `texture` based on the side of the owner. In our game, cats will fire green bolts, while the enemies will fire red ones. Our textures reflect that. Finally, our bullets will live for 2 seconds. We're also assigning the `tick` and `draw` functions to standardTick and standardDraw. We can now see how our tick and draw functions work. Starting with standardTick:
This function only applies to the player's bullets. What we're doing here is testing if the bullet has travelled off screen, and if so we're killing it by setting its `health` to 0. What this means is that the player cannot shoot or harm enemies or other things that aren't visible. This might sound odd, but it basically prevents the player from destroying objects that they might not want to, due to stray fire. It also pushes the player to engage the enemies, rather than spraying fire everywhere and hoping for the best. The behaviour was adopted in Project: Starfighter. Next up we have standardDraw:
Nothing special here. Like our entities and effects, we're only rendering the bullet if it's on screen. The bullet's texture is flipped depending on the direction it is facing. That's it for our bullets and firing. We need only update stage.c with the appropriate function calls and we're finished. Starting with initStage:
We've added the call to initBullets. We next update doStage:
We've added a call to doBullets. Finally, we update `draw`:
To draw our bullets, we just call drawBullets. There we have it. In two parts we've added the ability to fly our ship around and fire our guns. What we need now is something to shoot. So, in the next part we're going to add in some enemies to destroy. Purchase The source code for all parts of this tutorial (including assets) is available for purchase: From itch.io It is also available as part of the SDL2 tutorial bundle: |