Loading
Lesson 04
Courses / Build a Game with SDL - Make a Labyrinth with C++ from Scratch - Beginner Tutorial
Defining the Entrance and Exit Position for the Labyrinth Game in SDL

Summary

SDL Labyrinth Game Development Summary

Overview

In this lesson, we aim to enhance the SDL-based labyrinth game by implementing an entrance and exit for the player. The current setup allows for movement and wall collision detection, but does not yet define a start and finish point.

Objectives

  1. Define Entrance & Exit: Determine starting and ending points of the labyrinth according to the game map.
  2. Modify Game Map Format: Update gamemap.txt to include coordinates for the entrance and exit.
  3. Visual Representation: Use colors (green for entrance and red for exit) to visually indicate these points on the screen.
  4. Game Logic: Check for player movement into the exit tile to win the game and provide options for restarting.

Implementation Steps

1. Update Game Map Format

  • Modify the gamemap.txt to include two lines at the beginning for entrance (X, Y) and exit (X, Y) coordinates.
  • Convert these coordinates into tile indices.

2. Code Adjustments

  • Update main.cpp to read the new format and store entrance and exit positions using SDL Rect.

3. Drawing Entrance & Exit

  • Implement functions to paint the entrance and exit within the game window:
    • Paint Entrance: Draw a filled rectangle at the entrance coordinates with the specified color.
    • Paint Exit: Do the same for the exit.
  • Ensure that the drawing operations are called after loading the game map.

4. Player Movement Logic

  • Implement logic to check if the player has reached the exit tile. If so, display a win message and prevent further movement until the player decides to restart.

5. Debugging and Testing

  • Validate that the entrance and exit coordinates are correctly parsed and displayed.
  • Ensure that the painting functions do not overlap or erase previous drawings (like the player).

Challenges Faced

  • Identifying and correcting coordinate indexing (X as column, Y as row).
  • Properly handling SDL functions to ensure that colors and rectangles are drawn correctly without overwriting other components.
  • Adding visual feedback for progress and winning conditions.

Conclusion

In this session, we've set up the foundation for a labyrinth game, creating a clear start and finish with visual indicators. Future lessons will cover enhancing visual feedback to indicate game states, like winning and restarting the game.


Feel free to continue to the next lesson where we will add more features to improve user interaction and feedback within the game.

Video Transcript

Welcome to another lesson of SDL. Let's get started. Here I have the current game as is right now. We can move and there's collision if you try to move into a wall. Now on the right hand side I have a picture. I have a green tile at the top left and I have a red tile here at the mid right hand side. Now the goal of the labyrinth is to go from one point to the other. Let's call the starting point the entrance. Let's call the end point the exit of the labyrinth. Our goal is to implement the entrance that is the starting point and the exit. Now the entrance and the exit will be determined by the game map. The game map will set the starting point, the game map will set the ending point for the player with the exit of the labyrinth. The screenshot here on the right hand side is an arbitrary location for starting and ending point. It could be anywhere you want. That will be set by the game map. So what we're going to do is the following. We are going to change the game map.txt format to include information about the starting point and the end point for the player. Then we are going to perhaps make it more obvious to the player where those points are. Maybe we can color them in green and red like it's shown in the screenshot on the right hand side. So essentially what is going to happen is whenever the player moves we are going to check. Did the player move into the labyrinth exit tile? If that is the case then it's game over and the player wins. Otherwise we continue the game. Now if the game is already over we will prevent the player from moving further. So there will be nothing else left to do. The player will have the option of starting a new game after pressing a key. Let's call the key perhaps the R key for restart. Later on we will learn how to add a text to the screen using SDLTTF. We'll look into that later on. Alright so let's get started. First let's change the game map format. So going to gamemap.txt we already have this format where each number, each integer represents the ID of the tile that is drawn on the screen. Each line corresponds or maps exactly to the line on the screen. So the first line will be the first line of tiles, second line will be the second line of tiles on the screen and so on. Same thing for the column. They'll map exactly. Now what we can do is before all of that I can include information about the starting point and the end point. I'm going to do it in the following way. For the starting point I need the X and the Y. Now I could use a raw position with for example 0, 32, 64, 96, something like that or I could simply specify the line and column at which the player will start. That way in the program it will automatically map those to an actual coordinate X, Y. So let's say I want to start the player. Right now the player starts, if I rerun the program here, right now the player starts at the very top left, right? The position is 0 for X, 0 for Y. There'll be the first line, first column. Let's say we want to start in, let's say the fourth line, the first line, one, two, three, fourth line, first column. That would mean I have to walk zero steps in the X. So that would be index zero for X, space, zero, one, two, three, index three, four, Y. Right? Because we start counting from zero, if it's the fourth column that means it's four minus one, which is three, index three. So let's consider that the starting position. Now for the ending position, let's say we want to end up in, what can we do right now? Let's see. It's, let's say it's the, let's count, let's count. For X, I am going to do zero, one, two, three, four, five, six, seven, eight, nine, ten, eleven, twelve, thirteen, fourteen, fifteen, sixteen, seventeen, eighteen, nineteen. That's correct, twenty minus one. Right? So let's do X, nineteen, the last column. Now for the row, let's say zero, one, two, three, four, five, six. Let's call it the seventh row, which is index six. Now we immediately, if you can project this to the left, it would be under immediately on the line before this blob here with two Y tiles. Okay? So that's what we expect to be the ending. So now we have zero comma three for the starting point, 19 comma six for the ending point. Now with that, we have to change our code, right? Because right now our code expects only the lines and columns that were there before. It doesn't expect this very first line of the starting at any point. So go to main.cpp, wherever the map is being parsed or loaded, right? Now we have something else to do. Right here, we have, we open the file, we have an IF stream and we are doing a loop and then we close the file. Now what's going to happen before that is we have to capture the positions. Now let's call the entrance, labyrinth entrance and the labyrinth exit positions. So assume there is a SDL rack for the entrance position. Okay. And there is an SDL rack for the exit position. We are going to do the following. Let me fix the screen. Okay. So we are going to get, since we just opened the file, we are in the very first line, the very first thing that we can see in, okay, we're going to see in, that is, we already have the stream. So game map file instead of seeing. We are going to add to the position x first and then later you are going to get the entrance position y. Then you do game map file, the same thing. Now instead of entrance, it's going to be exit position x, then grab exit position y and no dot there. What this is doing is for the very assume that this is an SDL rack and this is going to be an integer, right? Some kind of integer. It's going to grab the first one zero and place in entrance position dot x. It's going to grab the number immediately after that, which is three, and put it inside entrance position dot y. Then later exit position dot x, exit position dot y. And then it goes on to do whatever it was doing before. Now we need to pass these positions. So let's add here as a variable. Let's call it SDL rack, entrance position, SDL rack, exit position. Now the thing is we are modifying the value of entrance position and exit position. The way it's written right here, the arguments would be passed by value. That is, a copy of them would be reflected here, but changes inside this function would not be reflected outside to the callee. So we should either make this a pointer or a reference. I'm going to use the n percent to make it a reference. So whenever we change it inside this function, it will reflect outside to whoever called it, the scope of whoever called it. Now go to the call to load game app. Now we have to pass those very, those new variables. So I'm going to call us the our rack entrance position. And I'm going to declare not as the L rack for the exit position. And I'm going to pass them here. Exit position. All right. Now if you want to debug that, we already have this debug for the game app, we can also pass those in to make a debug statement. Okay, just see if everything actually was parsed correctly. And all it's going to do is we can say before this loop, std, cout, entrance. Let's call it parentheses, intrants position dot x, comma, entrance position dot y. And I'm going to put a closing parentheses, and that's the end line. Now with that, I need to add here to SDL rack, entrance position, I don't need to make it a reference here with the ampersand because I'm not changing entrance position at all. I'm just displaying the value. It's a read only operation for this function. The same thing can be done. I can just copy and paste for the exit. So instead of entrance to say exit, and it's going to display the x comma y inside parentheses. So here I'm going to say exit position instead of entrance position. Let's try it out with the new map format. Seems like we have some errors. Let's address those. I forgot to pass to declare the third parameter as the erect exit position. Try it again. Now we got that. Now it's saying that the starting position that was parsed is zero comma three. That's correct here on the left hand side is what it got. On the right hand side is the actual value that's correct and matches. Now for the exit would be 19 comma six, we have 19 comma six inside the game. So everything is working fine. Now that's awesome. But it doesn't start in zero comma three. So we have to change the player initial position. Let's do that. Here whatever we declare the player position and the main function we can do. Where's the player position here? This is where player position is. Now the problem is we need, we only get the entrance after loading the game map. So we have the entrance position. We load the game map. We got the entrance from line 79 and down. We do have the entrance position. So we can take that into account when we make the player position. So we can say for the x for the player instead of zero, we can say entrance position dot x for the y comma entrance position dot y. Let's try it out. Recompile and run and something is not right. What happened? Well, x right now is what is zero and y is three. So actually we didn't translate, right? Remember we had talked about instead of passing the actual coordinate instead of defining the actual coordinate in the game map, we just passed the line number, actually not the line number, the index. The line index followed by the column index. So we need to multiply that by the tile size, which is 32 to be able to get the correct position here, right? So if you take three, multiply by 32, right? We got 32, 64, right? 96. So that's what we need to do. So whatever you have low game map, let's go back. So the entrance position x and y, we have that. Now that's not correct, right? How can we do that here? Let's do the following. If I take int entrance line and do game map file x here, not that sorry, I meant to do this like that. So we have int entrance line. And then we do game map file to entrance line. And then finally, entrance position not x would be entrance line times the tile size. We have, do we have a constant for that? That's 32, but we can use the constant. We don't have a constant globally, but let's see, did we declare that anywhere? We hard color them. Usually we want to make a constant. So I'll make a constant here. And I'm going to call it tile size of 32. Since our tiles have the same width and height, I would just consider one variable. If your game had tiles that had variable size, then you would have to split this into two different variables, one for the width of the tile, another for the height. So with this global variable, let's reference that in the function here, tile size. So now we have, we have this variable entrance line. Then we parse the very first integer in the map file. And then we multiply that by 32 to obtain the entrance position x. Do the same for y. So we can do make another variable here, int exit, entrance column, actually. And then you do game map file, parse that into entrance column, that will give you the column index, right? You can call it entrance column index. And then we can do inference position dot y would be the entrance column times tile size. Okay, of course, you could make 78 79 one line and so on. You can make this code better if you want, I'll leave us this. So the same thing for the other one, if you want to try out for yourself pause the video and try it out and then we do together later. So how did it go? Let's keep going. So this time would be the exit, right? So essentially, it's the same thing. So we would have a variable to hold the index for the line and column of the exit. So I'll call it exit line. Exit column, you can put one line if you want to game map file, you can do like this to entrance. Sorry, exit line and you can do exit column equivalent same thing. That will be mapped consecutively. And then you can do entrance position. Sorry, exit position x equals exit line. Oops, I actually made a mistake here. So I swapped the variables. So line is actually y, right? So if you didn't catch that before, this is a very common mistake we can make when you're working with x and y and liners and columns line actually is the y position. So let's fix that. So here what where I have interest position dot x interest line that's actually entrance column, where I have the y is actually entrance line, right? Because x goes from left to right. So that would be the column, right? And y goes from bottom to some top to bottom. So that'll be the lines. Okay, so let's continue. We were in exit position x would be the exit. What column times the tile size exit position y would be the exit line index times the tile size. Okay. Let's try it out to see if we didn't break anything. So let's take a look. Line zero means y equals zero 96 comma y zero correct. Column three means three times 32 x equals 96. Correct. Now check the exit. x would be corresponding with the column six. Six times 32 would be what five 10 times 32 320 by by two that would be 160 160 minus 32 160 130 120 128 so you add 128 to the half of 320 160 plus plus sorry yeah 160 plus 32 192. Now for the other one would be 19 times 32 would be 608 is that correct? If you take 20 times 32 would be 604 minus 32 608 that's correct. Okay. Now let's keep going. We got that parsed and let's see seems like we jumped we started and so we want to start at the very first line and the third column is that correct is the great tile there let's see we are in the very first line one two three four so index three is a fourth column so that's correct we are starting there so that worked fine congratulations on reaching this point. Now let's let's try to you see if I get out I don't know where I started anymore so maybe we want to paint that starting place with a different color so let's go here wherever we paint remember we have the little game loop. Let's think about this we don't do we have to yeah we have to I'm thinking that we have to paint that starting point every time well I don't think so we can do it only once if you have the map texture already there or the surface let's see load print create game map surface. Of course the player always has to be redrawn because the player is a moving thing but the starting point does not move ever in this case so we could just incorporate that into the game map surface if we wanted or we keep paint as in a separate function here and we do that before the game loop where it keeps drawing stuff. You can see the code to paint the player is here in line 216 and 217 we would do the same a similar thing to paint the starting point. I'm just gonna copy that we can do after creating the game map you can make a function here if you want and you can say let's say paint or starting or entrance let's say paint entrance and let's move this code to that function let's create paint entrance outside void paint entrance paste the code and let's figure out what we need as arguments as the input and possibly the output. First you have to pick the color for the entrance let's call it just color it's a type un32 call sdl map rgb give the surface format right we need a surface format so probably want to pass as argument the window surface I'm going to pass a surface pointer here I forgot sdl surface pointer window surface 128 for r well we had used green so maybe we want some rgb so g would be green we could try 255 for the value here for green and last on the red and blue to see what it looks like so finally you call fill rect in the window surface you need to tell it where on the window surface to paint so that would be the entrance position so we need that as one other parameter that's sdl rect we don't have to pass by reference because we're not changing it but since we're doing the the pointer here right because this is this argument to sdl for rect is a pointer so maybe you could use the pointer here but I'll leave it as is it's okay and I'll change the name of the third argument so we just call it because we changed it here it returns nothing I don't know as fill rect has any return value of error or not you can make you can do your own research there and handle any errors accordingly that's an exercise for you now we have paint entrance the callee needs to pass the arguments first is the window surface second would be the entrance position and we have it in the same of the same name here here's the entrance position here's the window surface let's try it out I have a problem because line 164 error player position was not declared in this scope okay I call the variable a different name it should be called the argument is entrance position not player position the second argument pass to sdl fill rect on line 164 let's get out oh nothing happened okay why didn't that work let's think thing fill rect update window surface do we need to update the window surface I wonder let me just copy this after line 200 oops that's not the issue let's see I reverted that game map surface okay oh I see maybe let's see we have the window surface surface what we're doing from line 188 get the window surface load the game map create map game surface pass the tiles now this surface here for the game map is not yet painted on the actually that is always painted on the window so I think the problem here is you have the window you created the game map surface then you paint on the window and then later here you are blitting the game map surface over the window surface so that will cover the green that we already have so actually I did it what we should not paint the window surface we have to paint the game map surface because that will always be painted over the window surface so let's move not move but change the argument here for paint entrance that's not the window surface that would be the game map surface here and let's change the parameter name because it's not really right we can just call it surface actually to generalize the painting of the entrance in any kind of surface so I changed the name of the parameter now let's trade out oh no what is going on that's awful well that's not good everything now is green to the right hand side there let's see what we can do well let's go to it again so we take the game map surface and paint the entrance position entrance position here would be 96 common zero oh that's it now we didn't set the width and height for the sdl rack for entrance position that's why it covered the whole thing there so we need to limit the width and height to 32 so in the sdl rack for entrance position let's initialize that with an x of zero y of zero and then width of 32 which is the tile size height of 32 which is the tile size that way we have some initial value okay and then the there will be there won't be any more problems there now you can see that the square only covers 32 by 32 of area okay we're likely going to face the same problem with exit position so i'm just going to take this opportunity to initialize exit position x to zero y to zero the entire size 32 and 32 for width and height respectively that way it has some initial value to fall back to for the case of x and y and it has the limit width bounded to 32 by 32 for width and height now that's looking great now we know where we started with that green tile here in the very first line fourth column now we since we did that i want you to go ahead and paint the exit using the same approach all right all right so let's go well we could copy and paste the same very paint entrance function that's one way you can certainly generalize this to any kind of tile but that's okay we are going to make paint exit we're going to take any surface pointer to a surface and the SDL rack of the position i'm going to call it exit position define the color u in 32 color equals SDL underscore map RGB take the format of the surface surface hyphen greater than format the color we had used a red some kind of red so maybe i only use 255 here and 128 128 for green and blue now take that color SDL fail wreck the surface comma the ampersand is the address of exit position as the erect and then finally the color and finally let's call paint exit from where we called paint entrance same thing past the game map surface exit position let's try it out i that didn't work did it what happened did i save paint exit game map surface exit position exit position right here zero zero exit position is set in load game map i hope it's at 192 608 that would be where around 192 here 19 here huh remember i think we had set that too okay i think if you take x 192 and y 608 did we do something wrong here i think we did i think we swapped the thing again what happened because there's no way you can have y grid and 480 right because the screen height is 480 so i think we flipped this let's let's check it out so so if this is the line that's correct 19 is the line wait 19 how many lines do we have 480 divided by 32 would be 15 so that's actually wrong we cannot have more than 15 here so i messed up i think i meant to say 6 and 19 so this would be the line right the sixth line 1 2 3 right 1 2 3 4 5 6 hold on hold on i meant i think i meant it to be here so that'll be 1 2 3 4 5 6 7 7 line 7 minus 1 is index 6 correct now i would meant it to be at 19 so 20 across 20 tiles minus 1 19 is the index correct so i had swapped my lining column here in the game map all these things happens trial and error now you can finally see the rad square here in the very middle point at the right hand side that's where i meant it to be and that's the exit that we have to go to to finish the game and win of course nothing happens now to indicate we want that's something we're going to do later okay i think it's a good time for us to take a break and i see you in the next one
No comments yet (loading...)
No comments yet (loading...)
Did you like the lesson? 😆👍
Consider a donation to support our work: