• 2D shoot 'em up
SDL2 Santa game tutorial 🎅
SDL2 Shooter 3 tutorial
The Legend of Edgar 1.36
SDL2 map editor tutorial [UPDATED]
TBFTSS: The Pandoran War - Amiga OS4 Port
— Mission-based 2D shoot 'em up —
We have our objectives system in place, but it would be nice to be able to view the objectives that need fulfilling. Indeed, it would be best if the objectives could be displayed at the beginning of the mission. In this part, we're going to introduce such a view, as well as allow the player to pause the game and see the objectives at any time.
Extract the archive, run cmake CMakeLists.txt, followed by make, and then use ./shooter3-13 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 guns. Play the game as normal. The Tab key acts as the Pause button. Press this to dismiss the objectives display at the start, and also view it during gameplay. Once you have completed all objectives, the list will be shown again, at which point the game will effectively come to an end. Once you're finished, close the window to exit.
Inspecting the code
Our focus for this part, at least for now, is on stage.c. Later on, we'll be expanding the end game feature to make it more fancy, and also handle the player death. For now, the player remains immortal, and the mission cannot be failed.
Let's start with structs.h:
We've added one new field: missionCompleteTimer. This will be used to control how soon the mission ends after it has been completed or failed. Although it is only used by stage.c right now, we'll want to be able to access its state later on, and so we're adding it to the Stage struct.
Now, onto stage.c itself. We've started by adding in a pair of enums:
These enums will control our logic and rendering. When in SHOW_STAGE state, the game will play as normal. When in SHOW_PAUSE state, we'll be rendering our objectives list, and the game will be paused.
Now for the updates to our functions. Starting with initStage:
We're setting Stage's missionCompleteTimer to 1 second, a new variable called timePlayed (just used to track how long the stage took to complete) to 0, and also setting `show`, our logic and display control variable, to SHOW_PAUSE. This means that when the mission starts, we'll be greeted by the mission objectives list first.
The updates to `logic` follow:
You'll remeber that before, this function simply called doStage. We've now expanded it, to test the value of `show` and act accordingly. We're first testing if `show` is SHOW_STAGE. If so, we're then checking if Stage's `status` is MS_INCOMPLETE (the mission is currenly in progress) and allowing the use of the pause control. If the pause control is pressed, we're going to update `show` to SHOW_PAUSE, to pause the game. We're next testing if Stage's missionCompleteTimer is greater than MISSION_COMPLETE_STATUS_TIME (negative 1 second). If so, we're calling doStage and a new function called doStatus. In short, if the mission is still in what we consider an on-going state, we'll continue to drive the mission logic.
If `show` is SHOW_PAUSE, however, we're going to do nothing more than test to see if the pause control has been pushed to unpause the game, and resume play.
Next we've made a small update to doStage:
If the mission is still in progress, we're updating the timePlayed variable. Nothing more.
Now for the new doStatus function:
Right now, we're just testing the value of Stage's `status`. If it's MS_COMPLETE, we're going to reduce the value of Stage's missionCompleteTimer. Again, this is a function that will see a much larger update in the future.
That's our logic updates done, so now we can move onto the rendering phase. To begin with, we've made tweeks to the `draw` function:
Before, we were always drawing the HUD. Now, we're only drawing it if `show` is SHOW_STAGE, and also if Stage's missionCompleteTimer is greater than 0. We don't want to show our HUD if we've paused the game, as it can make things look cluttered. We also don't want to draw the HUD if the mission is drawing to a close (you'll notice the HUD goes away just before the mission complete screen is displayed). Next, we're checking if the game is paused. If so, we're calling a new function called drawPause. Finally, if the mission is complete and we've fallen below the value of MISSION_COMPLETE_STATUS_TIME, we'll call a new function named drawMissionComplete.
Let's look at drawPause now:
A simple function - we're drawing various pieces of text on the screen. However, we're also calling a function named drawObjectiveList, which we'll come to in a moment.
The drawMissionComplete function follows:
Again, we're drawing various pieces of information, including the time it took for the player to complete the mission. For this, we're using the value of timePlayed, formatting it into minutes and seconds (and placing the result int a variable called `text`). Like drawPause, this function is also calling drawObjectiveList.
So, let's look at the drawObjectiveList function now:
This function is very easy to understand. We're just looping through all our objectives and rendering their descriptions and progress (using their currentValue and targetValue variables) to the screen. Each one will be drawn below the previous. If the objective's currentValue is equals to its targetValue, we'll render the text in green (with help from an SDL_Color named `c`). Otherwise, it will be drawn in white.
We now have our objective being displayed when the mission starts, offer the ability to show them when pausing the game, and finally show them again when the mission is complete. There is more to add, but these can be added in later parts, as they become more relevant. But for the moment, this will do.
For now, our main gameplay is done, and we have a very solid foundation upon which to build our missions. What we should do now is move on to the part of our game that sits between missions. In the next several parts, we'll be looking at the intermission phase, which will involve the star system map, comms system, shop, statistics, options, and our save game management. As you can see, there is still much to do ...
The source code for all parts of this tutorial (including assets) is available for purchase:
It is also available as part of the SDL2 tutorial bundle: