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 ... |
— Simple 2D adventure game — Note: this tutorial assumes knowledge of C, as well as prior tutorials.
Introduction The third icon that the Prisoner needs to find is guarded by a hoard of vampire bats! In order to get past them, the Prisoner will need to get his hands on a silver dagger. This can be done by fetching 14 silver coins and giving them to the blacksmith, who will furnish the Prisoner with the weapon. Extract the archive, run cmake CMakeLists.txt, followed by make, and then use ./adventure12 to run the code. The usual controls apply. The 14 silver coins can be found scattered around the dungeon, so you will need to explore. Once you find all of them, return to the blacksmith, and then, with the dagger in your inventory, make your way to the vampire bats (Casa de Chiroptera). To kill the bats, simply walk into them. You will soon get the icon. Close the window to exit. Inspecting the code We've added in our final NPC: a blacksmith. He resides in the same area as the Dungeon Mistress and the Merchant, in the starting zone. He doesn't operate that much different from the Merchant. Let's start by looking at structs.h:
Our Blacksmith struct is basically identical to ther Merchant. There was a temptation here to change both the Merchant and Blacksmith into a single struct called ShopKeeper, but doing such things could lead to problems when creating larger projects, so best to leave them as separate structures (unless we suddenly found we had half a dozen identical ones..!). Moving on, the Blacksmith's functions are all defined in blacksmith.c. There are three functions here - the init, the touch, and the load. We'll start with initBlacksmith:
You'll know what's going on here by now; it's the usual data setup for the blacksmith, as with the other NPCs. We can quickly move on to the touch function:
It might look like there's a lot going on, but keep in mind a lot of this is just text boxes for conversations. When touched, the Blacksmith will face the player, and then test his state. He starts in STATE_INIT, where he'll just chat with the player. After that, he moves into STATE_NEED_SILVER. If the player has yet to find any silver, he will tell them to return once they do. If they have fewer than the required number, he'll inform them they need to find more coins. Otherwise, we can move into the phase of turning over the dagger and completing the task. Something that's important here is that we're first testing the outcome of addToInventory for the dagger. If we can successfully add the dagger to the player's inventory, we remove the silver, null the Blacksmith's item, and update the Blacksmith's state. This will effectively complete the task. However, if we're unable to add the dagger to the player's inventory, we'll show a message box to say we need to drop something first. This is important, as unlike taking items from a chest or exchanging the record with the Merchant, we cannot be certain an inventory slot will be available. Silver isn't an inventory item, but a separate stat, meaning the player's inventory might be full. Finally, if the Blacksmith's state is STATE_HAS_SILVER, he'll merely say how much he's enjoying the chocolate we've brought him. The final function to look at is load. It's not much different from the Merchant or Chest:
We're just looking for the item to set to the Blacksmith, according to the item id. This item id is used in the same way as the Chest and Merchant in the postLoad function, in entities.c:
We're doing the same thing for each data structure here. Should this function have started to grow larger, we might want to create a postLoad function pointer in the Entity structure, and call that instead of using this global system that tests the name of the entity. That's the Blacksmith handled, so we can see what else has now changed. As stated earlier, we've updated the Prisoner so that he can hold silver, as well as gold and have an inventory. However, we've also added another new field:
hasDagger will be used to determine whether the player is holding the dagger, much in the same way that we test if the player has the Lantern. We've updated the updatePrisonerAttributes function in inventory.c to deal with this:
A simple update. We've just checking to see if the player is holding an inventory item called Dagger, and setting the hasDagger field to 1 (true) if they do. As one of the objectives of the adventure is to find silver coins, we need to define these. Remember that silver coins are not items, and they are not gold coins either, so need different logic. This is defined in silver.c. The file is simple, containing just two functions - an init and a touch. The initSilver function is simple:
We're setting the texture of our entity and assigning the touch function. Nothing we've not seen before. The touch function itself is also very simple:
When the Prisoner touches a silver coin, their silver variable is incremented, the coin is marked as dead, and we set a message saying we've picked up a coin. But what of the vampire bats themselves. Well, they're also very simple in their implementation. Defined in bat.c, they have just two functions - an init and a touch. Starting with initBat:
There's probably not much to say about this, to be honest. The bats are solid, though, so that they block the player movement (and line of sight). The touch function is a little more interesting:
This is where the Prisoner's hasDagger variable comes into play. When the player walks into a bat, we test to see if the player has the dagger. If so, the bat is killed by setting its alive state to ALIVE_DEAD. However, if the player doesn't have the dagger, the Prisoner will complain the bat bit him. As the bat is solid, it becomes impassable and prevents the player from proceeding any further. That's more or less it for the Blacksmith, coins, and bats. To enable them in our dungeon, we need to remember to add them to initEntityFactory:
Before we finish up, let's take a quick look at the other changes we've made. As we can now collect 3 icons, we've updated the Dungeon Mistress to respond to this event. In dungeonMistress.c, the touch function now handles 3 Icons having been returned:
The Dungeon Mistress is starting to become annoyed with the Prisoner's progress, finding it unbelievable that he's managing to find the Icons, and accusing him of cheating when he turns over the 3rd one. The final little tweak we've made is the initPlayer, to set the colour of his message box:
Along with the new silver and hasDagger variables that we added to the Prisoner struct, we also added in an SDL_Color called mbColor (message box colour). This can be used when the player is speaking, so that can centralize the colour of the Prisoner's message box. If we want to change the colour, we need just update this variable, rather than hunt around for each place he speaks to update those. We're almost finished! Just one room left to create, and then some finishing touches to go! In the next tutorial, we'll look at creating the Escape Room, a room that shuts the Prisoner in and seemingly has no way out. 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: |