• 2D shoot 'em up
SDL2 isometric tutorial
SDL2 turn-based strategy tutorial
Water Closet ported to PlayStation Vita
The Legend of Edgar 1.35
— An old-school isometric game —
Now that we can render our map, the next step is to be able to select tiles, using the mouse. In our game, we'll be selecting tiles for the main character to move to. Picking tiles is fairly straightforward and really just requires some reverse calculations from our isometric projection.
Extract the archive, run cmake CMakeLists.txt, followed by make, and then use ./isometric02 to run the code. You will see a window open like the one above. Move the mouse cursor around the map to highlight tiles. The tile's x and z values are shown in the top-left. Note that we can only highlight ground tiles (the green ones); moving the cursor over a water tile (blue ones) won't highlight it (but the indexes will still update on screen). Once you're finished, close the window to exit.
Inspecting the code
Selecting tiles isn't too hard, thankfully, so this is a short part. In fact, things will be getting easier from here on out, compared to part 1.
Let's look at structs.h first, where we've updated the World struct:
We've added in an anonymous struct called `cursor`, that will hold our selected `x and `z` values.
Nothing else to do here, so let's move onto world.c, where we've made a few changes. Starting with `logic`:
We're now calling a function named doCursor, that we can see below:
This function is responsible for converting our mouse's `x` and `y` coordinates into a tile index. Basically, a reverse toISO.
First off, we want to substract half our tile's width and height from our mouse's `x` and `y` values, so that we're handling the tile from the middle, and assigning the results to `sx` and `sy`. Next, we need to substract our map rendering offsets. If we don't do this, our tile selection will be off by about half a screen in both directions. With this, we have a screen coordinate that aligns with the middle of a tile.
Finally, we're dividing `sx` and `sy` by TILE_WIDTH and TILE_HEIGHT, and doing some addition and subtraction, and assigning the final results to World's cursor's `x` and `z`. Notice how we're using doubles for `sx` and `sy`, and rounding the result. Integer maths will fail us here, due to us needing to round half up to correctly match our tile. We want, for example, a value of 1.67 to be rounded up to 2. A value of 1.42 would remain as 1. One can see this in action by removing the round function call. Notice how when this is removed the tile selection is off by about half a tile.
There are plenty of other ways to figure out screen coordinates to isometric coordinates, this being just one of them.
We now have our selected tile index stored, so we can render it. Before we leave world.c, just note we've also updated the `draw` function:
We're calling a function named drawHud, that we'll see towards the end of this part. For now, let's head over to map.c, where we've made a couple of updates.
To begin with, we've tweaked drawMap:
Now, after testing if `n` is greater than 0, we're testing if it falls between 10 and 19, and also if `x` and `z` are equal to World's cursor's `x` and `z`. This will mean that the current rendered tile is our selected tile. If so, we're calling addISOObject, but passing over a new texture called selectedTileTexture. Our test for `n` being between 10 and 19 means that this will only affect ground tiles. If the cursor is over a water tile, we'll render the water tile as normal. Note that this piece of logic is temporary for our game; we'll be stripping it out in a later part and replacing it with something that adheres more to the structure we'll be introducing.
We've also updated loadTiles:
We've added a single line, to load selectedTileTexture (notice how we're making use of an image called exit.png, that we'll be using properly in a later part).
Nice and simple. Before we finish up, let's look at hud.c. This is a new file that will ultimately be used to display useful information to the player.
First up is drawHud:
We're simply calling a function named drawInfo:
drawInfo itself a simple function - we're formatting a string called `text`, to include World's cursor's `x` and `z` values, and then passing those to our drawText function (defined in text.c).
And that's it! We can now select tiles by moving the mouse cursor over them. We've now made it to two major milestones in our game, giving our a solid foundation to work with in future parts. In the next part, we're going to introduce entities, to show how we can handle layered rendering.
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:
If you do not wish to create an itch.io account, you can also purchase the tutorial bundle using PayPal, and then download the tutorials directly from the main tutorials page.