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 Battle for the Solar System (Complete) The Pandoran war machine ravaged the galaxy, driving the human race to the brink of destruction. Seven men and women stood in its way. This is their story. |
— 2D Santa game — Note: this tutorial assumes knowledge of C, as well as prior tutorials.
Introduction Having added in our first enchanted snowman, we're ready to add in the second. The first snowman tossed a snowball up into the air, while this second one is going to toss his head! Not only that, but the fiend is going to be shooting magic carrots at Santa, in a bid to disrupt Christmas. Just as with the snowball, a hit will result in an immediate game over. Extract the archive, run cmake CMakeLists.txt, followed by make, and then use ./santa12 to run the code. Press Space to play. Use the same controls as before. As you play, enchanted snowmen will appear, tossing snowballs into the air, as well as their own heads, shooting carrots at you. Avoid the snowballs, heads, and carrots, and continue to deliver gifts and collect sacks. The game will continue for as long as you are able to maintain your Xmas Spirit (and don't crash into a house or other hazard). When you're finished, close the window to exit. Inspecting the code Adding in this new "enemy" is extremely easy, as they are similiar to the previous one in several aspects! In fact, you're going to feel a sense of déjà vu as we go through the code for our second enchanted snowman. Let's dive in. Starting with defs.h:
We've added in three new entity types: ET_HEADLESS_SNOWMAN, to define the headless snowman himself; ET_SNOWMAN_HEAD, to define the headless snowman's head; and ET_CARROT, the type that will be used for the carrot that is fired out. Over next to structs.h, where we've added in one new struct:
SnowmanHead is similar to the Snowball we created in the last part, but with an additional field. `carrotTimer` is a control variable that will set how often the snowman's head can fire out a new carrot. The other fields operate the same way as the snowball, as we'll see. We've added in three new compilation units to this part, that we'll attempt to work through in a logical order. First up is headlessSnowman.c:
Very similar to our original snowman's init function, so we'll only cover this briefly. We're yet again ensuring we have room to add the snowman before doing so (via canAddEntity). Once confirmed, the only difference compared to the previous setup is that we're calling initSnowmanHead, passing over the `x` and `y` positions we want, as well as some minor adjustments to place the head correctly. We'll come to the initSnowmanHead function in a little bit. For our main entity, we're setting the `x`, `y`, `texture`, `tick`, `draw`, and `touch` functions. Before that, let's consider the other functions. Starting with `tick`:
We're moving the snowman to the left, removing it when it goes offscreen. `draw` is up next:
We're just rendering the snowman, using its `texture`. Finally, we have `touch`:
Once more, we're checking if the player has collided with the snowman, and calling killPlayer. As you can see, other than the init function, the Headless Snowman is very much the same as the original Snowman. Let's now look at snowmanHead.c, the compilation unit that will control the bouncing of the head. Once again, you will find parts of this very familiar. Starting with initSnowmanHead:
As with our snowball, this function takes two arguments - `x` and `y`, that will be used to determine where the head is initially positioned. We create a SnowmanHead, setting its thinkTime to 1 second (FPS), and also set its `startY` to the value of `y`. We're also setting the carrotTimer to a random value between 0 and 3 seconds. We're then setting all the usual pieces of data for the entity, such as the `x`, `y`, `texture`, `tick`, `draw`, and `touch`. Now to `tick`, where things actually get a bit more interesting:
A little bit more interesting, yes, but this is actually rather similar to the `tick` function in snowball.c. Our snowman head is bound by the same jumping logic, where it will rise up into the air by a random velocity if its thinkTime is 0, before returning back to its starting point (`startY`) as gravity takes hold. The major difference here, however, is that while in the air (thinkTime > 0), we are decreasing the value of carrotTimer. If it hits 0 or less, we're going to call initCarrot, passing over the head's `x` and `y` as the position we want to spawn the carrot at. With that done, we're reset carrotTimer to a random value of FPS (1 second). This means that while airborne our head can issue quite a number of carrots! The carrotTimer resets to longer when it lands back on the ground (up to 3 seconds). As with all other entities in the game, the head is moved to the left as its `x` decreases by the value of Stage's `speed`, being removed from the game once it goes off the edge of the screen. We'll briefly look at the `draw` and `touch` functions before we move on from snowman.c. First `draw`:
We're just rendering the entity using its `texture`. `touch` follows:
We're checking if the player has hit the head, and calling killPlayer if so (and passing over the head's `x` and `y`). As with the snowball, we're also removing the head, by setting its `dead` flag to 1. As you can see, the snowman head behaves very much like the snowball, except that it has the ability to shoot a volley of carrots! Let's now move over to carrot.c, where we're defining all our carrot entity functions. First to initCarrot:
We're building our carrot entity, setting its attributes (and using the `x` and `y` that were passed into the function). All good, let's move on to `tick`:
Here, we're decreasing the carrot's `x` according to the `speed` of Stage, plus a little extra (7) to make it move faster than the scene itself. Note that the carrots only ever fly from right to left; we never attempt to shoot the player in the back! Otherwise, once the carrot moves the left of the screen, we're removing it. `draw` follows:
We're simply rendering the carrot, using its `texture`. And finally, we have `touch`:
As expected, we're testing if the carrot has come into contact with the player, and calling killPlayer. As with the snowball and snowman head, we're passing over the carrot's `x` and `y` values, so that the explosion texture on the player appears where the carrot struck the sleigh. That's all for carrot.c. With our Headless Snowman, his head, and the carrot all done, we need only update stage.c to put him into the game. So, let's head over there now, and update addObject:
We've added an extra if check here for `n`. Now, if `n` is less than 65, we'll be calling initHeadlessSnowman. So, there's now a chance that we'll add a gift sack, a coal sack, a regular snowman, and a headless snowman. Any other value of `n` will result in nothing happening. We're done! We've added in all our collectables and hazards now, making our game more or less complete. We can score points, earn a place on the highscore table, and all the rest. It could be prettier though, right? I mean, shouldn't it be snowing? A nice wintery scene would be the icing on the cake. So, in the next few parts we're going to enter the prettification phase, where we make our whole game a bit nicer to look at. We'll start with some gentle snowfall. Purchase The source code for all parts of this tutorial (including assets) is available for purchase, as part of the SDL2 tutorials bundle: From itch.io |