SDL2 Shooter 2 tutorial
SDL2 Widget tutorial
SDL2 Adventure tutorial
Orb source code
— 2D Shoot 'Em Up Tutorial —
Note: this tutorial builds upon the ones that came before it. If you aren't familiar with the previous tutorials in this series you should read those first.
Our game is missing just one thing: a title screen. In this tutorial, we'll set one up and add some finishing touches to our game. Unpack the code and then type make to build. Once compiling is finished type ./shooter15 to run the code.
A 1280 x 720 window will open, with a colorful background. The title screen will be displayed, as in the screenshot above. Press the left control key to start. A spaceship sprite will also be shown. The ship can now be moved using the arrow keys. Up, down, left, and right will move the ship in the respective directions. You can also fire by holding down the left control key. Enemies (basically red versions of the player's ship) will spawn from the right and move to the left. Shoot enemies to destroy them. Enemies can fire back, so you should avoid their shots. Score points by collect points pods released from destroyed enemy ships. The highscore table is shown upon the player's death. If the player has earned a highscore, they will be prompted to enter their name. The highscore table is then shown and the game can be played again. Close the window by clicking on the window's close button.
Inspecting the code
The last few things that we've added to our code is the title screen and some tweaks. Not a great number of updates, so this final part of the tutorial will be quite short (and thankfully our final 10% didn't take 90% of the time!). First, let's look at the new title.c file. It contains just four functions. We'll go through them in order:
initTitle is called to initilize the title screen. We assign the delegate's logic and draw functions to our local ones, clear the keyboard input, and then load two textures - sdl2Texture and shooterTexture. These are for our title logo. Our logo is composed of two pieces, and we'll be drawing them separately so that we can add an effect that we'll see in a bit. We also set a timeout variable to 5 seconds. This variable will be used to change between the title page and the highscore table when timeout hits 0.
Moving onto the logic function, we won't see anything too unusual:
We're drawing our background and starfield, and then incrementing a variable called reveal. Again, this will be used for drawing our logo. We're capping the value this can reach at SCREEN_HEIGHT, just to prevent it from eventually overflowing and wrapping around. We're then decrementing timeout. If timeout is less 1, we're calling initHighscores to show the highscore table. This will make the game look a bit like the attract mode in arcade games. Finally, we're checking to see if the left control page (i.e., the fire button) has been pressed. If so, we're starting the game.
That's our logic done. Turning to our draw function:
Again, we're drawing our background and starfield, and then calling a new function called drawLogo (see below). We're also drawing our PRESS FIRE TO PLAY text. Note that we're testing the timeout variable before doing so. We're calculating the modulus of 40 and then checking to see if the result is less than 20. In effect, this will cause our text to blink off and on. The drawLogo function is a little more interesting:
Here, we're drawing our two logo textures that we loaded earlier. However, what we're also doing is drawing only a portion of each, according to the value of reveal. First, we're using SDL_QueryTexture to get the width and height of each texture, and storing these in the w and h of the SDL_Rect we've declared. We're then setting the rect's height as the lower value of r.h or reveal, and finally drawing the texturing using blitRect. Setting the rect's h to the lower value will cause it to slowly draw itself from top to bottom as reveal is incremented. We're also centering the logos by dividing SCREEN_WIDTH by two and subtracting half of the logo's width from it.
That's all for title.c. It's quite simple, really. All that's left to do with it is to make sure that we call initTitle at startup:
Calling initTitle in main.c (in place of initHighscores) means that the title screen will be the first thing shown.
There have been some other little tweaks throughout the code that we'll now touch on. None of these are essential, but more like finishing touches. Starting with highscores.c, we've made changes to the logic and draw functions:
As with title.c, we've added a timeout variable that we'll use to flip back and forth between the title screen and highscores. We've also updated the draw function to add in the blinking PRESS FIRE ... text:
One thing that you've perhaps noticed when playing the game is that the enemies sometimes spawn off the bottom of the screen. We can fix this in doEnemies:
The above tweak will use our MIN and MAX marcos to ensure that the entity's y never goes below 0 and never higher than SCREEN_HEIGHT minus their own height. This keeps the enemies on screen at all time. Another minor tweak we've made is to the enemies' movement:
In spawnEnemies, we've told the enemies that their dy can be a random between -1 and +1. This will mean that when created the enemies will move up and down the screen, as well as right to left. It's only a small change, but one that makes things a bit more interesting. Our final update is to drawing the points pods:
Before drawing the points pods, we're making a simple test. If the pod's health is greater than FPS * 2 (so, two seconds) we'll always draw it. If it's not, we'll calculate the modulus of the health (to 12). We'll then only draw the pod if the result of this calculation is less than 6. In effect, this will mean that pods that have less than two seconds to live will start flashing, giving the player a visual cue that they're about to expire (and help to know whether they're worth chasing after).
Our shooter is done! Hurrah! Hopefully you will have found this tutorial series easy to follow. The next batch of tutorials will kick things up a gear and consider things like mouse tracking, scrolling maps, joysticks, and a bunch of other things.
The source code for all parts of this tutorial (including assets) is available here:
It is also available as part of the SDL2 tutorial bundle (with on-going updates):