Lesson 04
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
- Define Entrance & Exit: Determine starting and ending points of the labyrinth according to the game map.
- Modify Game Map Format: Update
gamemap.txt
to include coordinates for the entrance and exit. - Visual Representation: Use colors (green for entrance and red for exit) to visually indicate these points on the screen.
- 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: