![]() | |
PC Games
• Orb Tutorials
• 2D shoot 'em up Latest Updates
SDL2 Quest game tutorial
SDL2 Versus game tutorial
Download keys for SDL2 tutorials on itch.io
The Legend of Edgar 1.37
SDL2 Santa game tutorial 🎅
Tags • android (3) • battle-for-the-solar-system (10) • blob-wars (10) • brexit (1) • code (6) • edgar (9) • games (44) • lasagne-monsters (1) • making-of (5) • match3 (1) • numberblocksonline (1) • orb (2) • site (1) • tanx (4) • three-guys (3) • three-guys-apocalypse (3) • tutorials (18) • 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. |
— Simple 2D quest game — Note: this tutorial assumes knowledge of C, as well as prior tutorials.
Introduction We're now able to explore the island using our robot. However, we're confined to a single island, with no means of escape. There could be several other islands waiting for us to discover, but we are unable to get to them, because our robot cannot cross the seas. In this part, we'll rectify that by adding in the ability to board a sail boat, and head off to these yet to be discovered lands. Extract the archive, run cmake CMakeLists.txt, followed by make, and then use ./quest05 to run the code. As before, you can move around with the WASD control scheme. Explore the island you start on until you find a boat; this will be located on the shoreline, somewhere around the island. As the game now starts on the smallest island, this shouldn't take long (unless there is only one large island..!) Take control of the boat by walking into it. You will be able to sail acrosss the sea now. To dock the boat, simply steer it into land or shallows. When you're finished, close the window to exit. Inspecting the code Adding in our boat is quite a straightforward task; entering the boat, for example, merely involves having to handle the robot touching the boat. However, there are a few additional things we need to do, such as adding a boat to each island, and placing it in the shallows. This is, again, quite simple, as we'll see. Let's start first by looking an update to the Island struct:
We've added in a new field here called lowPoint. This will hold the data about the lowest point of elevation of the island. Knowing this will enable us to add in the boat, as we'll see. Next, over to islands.c, where we've updated createIsland:
Here, we're now recording the lowest elevation point of our island (lowPoint). We're doing this by tracking the `elevation` data as we flood fill our island, to collect the land. By first setting a variable called minElevation to 1.0, we can subsequently test if the `elevation` at our flood fill nodes is lower than the current minElevation value. If so, we'll set lowPoint's `x` and `y` values to those of the flood fill node. When we finally come to create our island, we'll copy the local lowPoint data into the island's lowPoint field. Thus, we are left with a location on our island that is close to the sea. With that done, we can now move over to overworldGen.c, where we've made a couple of simple updates. First, we've updated generateOverworldWorker:
Now, as well as addAdventurer, we're calling a new function named addBoats. Note that we want to call addBoats before addAdventurer; addAdventurer checks for entity overlaps when randomly positioning the player character, while addBoats will always use a fixed location. We don't want our robot to be placed on top of one of our boats. Let's look at addBoats now:
We're going to be adding in one boat per island. This function therefore loops through each island in the world, creates a boat, and then places the boat at the island's lowPoint. All in all, this should ensure that our boats are placed near the sea. All very simple so far! Let's now look at boat.c (in game), that defines the entity itself. There's only a handful of functions in this file, both of which are easy enough to understand. Starting with initBoat:
A pretty standard init function for an entity. Note how we're randomly choosing a boat texture, so that the boats in the game don't all look the same. Moving on next to the `touch` function, where things are a little more interesting:
Here, we're checking if the boat has been touched by the player (which it no doubt will be, since nothing else in the game moves..!), and also if the player themselves is currently an ET_ADVENTURER. If so, we make the player invisible and non-interactable by setting their `hidden` flag to 1, and then making the current Map's `player` reference the boat itself (`self`). In effect, this removes the robot from view, and allows the user to now control the boat instead. This simple bit of logic gives us the impression that the robot has boarded the boat. That's all there is to boat.c, so we can finally head over to player.c, where we've made a few tweaks to handle controlling the boat. First, we've updated doPlayer:
When controlling the robot, we're accelerating up to a maximum speed, to allow for more fine-grained movement when starting off. When controlling the boat, we'll immediately jump to MAX_SPEED, following the initial first step. There is little need for such fine control when we're in the middle of open water, so moving as fast as possible is preferrable. It also helps to give the impression that the boat can move much faster than the robot. Finally, we've made some changes to moveOverworld:
Before, we were restricting the player movement to the shallows and land, forbidding the player from moving into the sea, forest, and mountains. This remains, of course, but now we have the ability to move the boat we need to accomodate this. We therefore now check if the player is ET_ADVENTURER, and retain the existing logic. If they're a boat, however, we'll apply some additional logic. First, we'll check if we're moving into the sea. If so, our movement is permitted. If, however, we're moving into the shallows or land, we'll disembark the robot from the boat. To achieve this, we'll first look up the adventurer by use of the getEntityByType function, which will search the current map for the adventurer (note that we're assuming exactly one result). We'll then set the returned entity's `x` and `y` values to those the boat was trying to move into (i.e. land or shallows). We then make the player visible again, by settings its `hidden` flag to 0, and re-assign the Map's `player` pointer to the entity (`e`), to regain control of the robot. We also set speed to MIN_SPEED, so the robot doesn't leave the boat at top speed..! And that's all there is to it! Very simple, as you can see. Based on interactions with the boat or environment, we're swapping out what the user is controlling. There's nothing more to it.
So, we can now explore islands and sail boats around. What we need next is the ability to visit settlements on these islands. Adding in towns and such will give the sense that the world is a little more alive, and there are further discoveries to be made. Therefore, in the next part we're going to be adding in towns to the overworld. This will get a little interesting, as you will see. 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 |