In this video you'll be building eight unique games using Python and py game now not only is this going to be super fun and give you some awesome games that you can share with your friends and family but it's going to teach you a significant amount about Python and about building larger projects in general we've got games like entire platformer games we're building out different physics components we've got Things like a car racing game making the classic game of pong 2048 we've got Checkers with AI we've got all kinds of stuff even like Space Invaders
and the way that I've set this up is we're going to go from the easiest project to the hardest so we're slowly going to build our way up and if there's one project that interests you more than others check the video player for all of the timestamps for these different projects with that in mind stick with me for some Important information all of the resources that you'll need for these projects is available from the description so if you need an image or a sound effect you want to reference the finished code all of that will
be available from the description it'll be titled under the project name itself so if you're working on the platformer for example and you need those images go find the platformer and beneath that I'm going to have all of the different Resources for that project now I absolutely love py game and that's the module we'll be using to build out all of these games and you'll see on my Channel that I have tons of tutorials just covering py game so what I did here is I combined some of my best videos ordered them so they're easy
to follow along with and combine them into this video so you guys have one resource that can contains really everything you need to know to get really good at Python and Build some awesome projects now if you appreciate this teaching style if you want to learn more if you want to become a software developer I do have a program with course careers now this is not just any other course this actually is designed to specifically get you a job and we walk you through everything from building your resume applying to different companies we have a
Discord group you can join where we have coaches obviously I'm in there some other expert Software engineers and we guide you every step of the way to really accelerate that process and get you to your goal of Landing a job and becoming a software developer as quickly as possible we've already had success in the program Landing students jobs and if you want to be one of those check it out from the link below we also have a free intro course 14-day money back guarantee really we want to make this the lowest risk investment it possibly
can be and You can go check the reviews five stars across pretty much every platform anyways I know this is going to give you guys a lot of value that's why I'm promoting it so heavily I really think this is the best program out there and it's very affordable compared to some of the other boot camps that you'll see online anyways with that said let's get into this enjoy let me know in the comments what your favorite project is and now let's build some [Music] games in this video I'll give you an introduction to python
game development by walking you through creating a simple fun yet extensible game we'll make this game using the pame module which is a simple 2D Graphics library in Python that allows you to create a variety of games in case you're curious I have tons of different pame tutorials on this channel and a recent one I posted actually shows you how to build an Entire platformer game here we'll make something much more simple just to get through the basics and get you up and started as fast as possible let me show you a demo of what
we're going to build so on the screen here you can see our game again this is fairly straightforward we have a background we have a rectangle that you could change to some kind of Sprite or character if you wanted to and then we have projectiles that are falling on the Screen as we progress further these projectiles will get faster and more of them will fall and eventually if we are to collide with one of these rectangles then it will tell us that we lost obviously you could go and add lives you can make different levels
you can make this game really completely your own but I wanted to show you the basics covering things like movement collisions projectiles backgrounds and all of that kind of fundamental stuff that once you Know you can make a ton of different games with so with that said let's get into the video so the first thing we need to do when we're going to be working with this pame module is we need to install pame now to do that you're going to open up a command prompt or a terminal and type the following command which is
PIP install py game now for some reason this command does not work for you you can try to run the command pip 3 install py game and if neither of Those work for you I will leave two videos in the description and I'll kind of throw the thumbnails up on the screen that explain to you how to install P game all right so now that P game is installed we can start using this live library now I've used this a ton of times but I'm going to walk you through step byep how we set everything
up so the first thing to do is go into a new python file you can see I'm in one here in vs code you can work in any editor That you like and import the pame module now while we're up here we're going to import a few other modules we're going to use for this game so we're going to import time and we are going to import random like that perfect all right next thing we're going to do here is set up our pame window now the first thing you need whenever you're working in pame
is some kind of window this is really the place where you can draw different objects and actually have your Game running now for your window you need a width and a height so I like to Define my width and height at the top of my program in all capitals just so that it's clear that these are constant values and they're not going to change so for the width I'm going to make this 1,000 and for the height I'm going to make this 800 and that is in pixels now if you are working on a small
display chances are this will be too large for you so you can make these values smaller So that the window will actually fit on on your screen okay now that we have the width and the height we're going to say when standing for our window is equal to P game do display do setor mode and inside of here we're going to pass a topple with the width and the height make sure you have two sets of parentheses here and inside of this inter set you have your width and then your height and make sure you
spell the width correctly okay the next thing we Can do is set a caption for our window this is going to be the name at the top of the window to do that we can say py game. display. setor caption and then we're going to pass a string here and I'll just call this something like space Dodge you can call this whatever you want all right before we go any further let's run our code here so I'm going to go and type Python and then main.py whatever editor You're working in I assume you know how
to run your python script and vs code you can also press this button okay so when I do that you'll notice that a window kind of popped up and then it disappeared immediately that's because we don't have any Loop kind of running that keeps our program alive you can see again when I run this window pops up and then it closes in a minute we'll make sure that window stays alive and I'll show you how to do that perfect so now That we have our uh window here our width and our height we need to
set up what's known as the main game Loop now whenever you're working in P game you need a loop typically a w Loop that is going to run while the game runs right so that actually keeps it alive the while loop will do things like check for Collision check for movements or key presses and then adjust what's being displayed on the screen so what we're going to do is create a function called Main this is really where the main game logic is going to exist for now we're going to create a variable called run and
we're going to say this is equal to true and we're going to say while run and then inside of here is going to be our main game Loop so the first thing that I always do inside of my game Loop is I check to see if the user pressed the x button on the window if they did that then I want to close the window it's not automatically programmed in you Need to handle that key press yourself so to to do that I'm going to say for event in py game. event. getet and this is
essentially a list that contains all of the different events that have occurred in the last um what do you call it kind of iteration of this Loop then what we do is check for the x button event so we're going to say if event. type is equal to pame Dot and then in all capitals quit what we are going to do is say run is equal to false which Will then end this wall Loop and we are going to break out of the for Loop because there's no reason to continue checking the events if you've
hit the quit button then at the very end of our function here we're going to say pame do quit and py game. quit will just close the pame window for us all right so very quick recap of what we've done here we've said run is equal to True while the variable run is equal to true we're going to check all of the different Events that are occurring this again will give us events like key presses Mouse being moved uh all that kind of stuff as well as if we hit the button in top right hand
corner that x button which is the event. type equal to pame do quit that's if that's the case sorry we're going to say run equals to false we're going to break out of this for Loop and then that will force us to have this statement here which will quit the pame window now what we need to do is Call this main function so we can test this out we're going to say if uncore uncore name is equal toore uncore main like that then we are going to call the main function now what this statement is
doing right here is making sure that we are directly running this python file so we're running the file itself we're not importing it because if we were to import it or if we were to not have this line for example and we were to import this file from another python file it Would start running our game when we only want to do that if we directly run this python file so hopefully that makes a bit of sense but this is just checking if you've run this file directly whereas if you were to import it this
is going to be false okay so now let's run our code python main.py notice the window appears and it has space Dodge as the caption then if I press this x button we can close out of it that only works because of the code that we've written Here fantastic so the next thing I want to do is have a background image and then I want to have a character that can move around on the screen so let's start with a background image well for our background image we need some image that we're going to display
on the screen now notice here that I actually have one bg. jpeg now this is a largish image uh which is just a space background all of this code will be available from my GitHub including the image so if you Want to download this exact image you can do that by going to the link in the description if you don't want this image and you just want your own background image then just save an image you can call it whatever you want but put it in the same directory as your python script and then I'll
show you how we can use that image as a background so at the top of our program here we're going to say BG standing for background is equal to pame do image. load and then we are Going to load the name of our file which in my case is bg. jpeg like that that's all you need to do to actually load this image into piking now if you named your something else obviously you're going to change the name to match that and if you had it for example inside of a directory then you would do
something like SL images SL and then bg. jpic there's a few other ways to go about doing that but in this case we're just going to load directly from the same directory That this python script isn't okay now that we have our background image we actually need to put that on the screen now I like to do all of my drawing in a separate function just to keep it very clear and kind of organized so I'm going to create a function here called Draw inside of this function for now I'm going to draw this background
image onto the screen to do that we're going to use our window which is this capital win variable and we're going to say win. Blit now blit is a special method that you use when you want to draw an image or a surface that's what it's referred to in Python onto the screen so we are going to blit the background image and then we need to pass the coordinates of the top leftand corner of this image so in P game when we're talking about our coordinate system 0 0 is the top left hand corner of
the screen so if I run my code here uh this should still be okay oops that's not working let's do this You can see that where my mouse is this is 0 0 if I go all the way over to the right here now we are at whatever the width of the screen is which is a th000 and then the y-coordinate of zero if I were to go down down here now we are at the width of the screen which is 1,000 and then the height of 800 or the height of whatever our screen is
because that's kind of how the Y is incremented so rather than y going up the Y actually goes down zero is the top and as you go Down to the bottom you increase your y value X is the same as normal starts at zero and as you go to the right it increases meaning down here we have an X of zero and we have a y of the height of the screen okay so that's the coordinate system now I want my background image to fill the entire scen screen so I'm going to put 0 0
as the coordinate of where the top left hand corner of this background image should be placed then the width and the height will fill the Screen lastly we need to say p name. display. update this is going to refresh the display which means any draws that we've done this is a drawing event will actually be applied and put onto the screen every time you update it takes all the draws and applies it if you don't have an update then nothing's going to happen on the screen fantastic so now before we exit our wall Loop here
we're going to call this draw function so now every single frame we're going to Call the draw function and it's going to continue to draw this on the screen let's go ahead and run our code okay so when we run it you can see that we get our space image appearing now in my case my space image is quite large so it actually fills the entire screen for some of you your image might be a little bit smaller and you might want to scale it up or make it larger so that it fills the screen
now to scale your image you can do the following you Can write py game. transform if we can spell that correctly do scale and then you can pass the image which in this case is the image that we want to load and then the size that you want to scale this image to so in my case I want to scale my image to be width height so it's going to be this now when you do this type of scaling it is not going to preserve the aspect ratio but there is different transform Functions that'll allow
you to look up from the documentation that let you actually scale it um based on a factors you can scale by 2x 3x 4X Etc rather than scaling using kind of this uh what do you call it width height system hopefully that makes a bit of sense but this will not preserve your aspect ratio if you use a different scale function it will there's one that I believe is scale 2x which just takes the image and scales it up two times the size okay so now This should scale our image to be the width and
the height let's quickly test this out and let me just select this interpreter so this will keep working now so now you can see our image looks a little bit better we've kind of uh made it the exact size of our screen rather than having it be too large and overflow the screen okay so now we have our background image and we have our main event Loop we have kind of the screen appearing the next thing we want to do Is create a character that can move around so let's do that so for our character
we're going to go inside of our main Loop here and we're going to say player is equal to a p game. rectangle with a capital R and this just going to be wrecked and then we're going to pass the X position y position width and height of our player so before I go here I'm going to create two variables one which is the player width which will make equal to 40 and another which is The player height which will be equal to 60 I like to declare all my constant variables in capitals at the top
of my program so I can easily change them and update all of my code by just changing one variable here so now I'm going to go to my player which is P game. rectangle and we're going to pick a starting X and a starting y position for our character now remember that this is going to be the top leftand corner of where we are drawing the player so we can pick any x Coordinate we want I'm going to pick 200 and then for the y-coordinate we want this player to be at the bottom of the
screen so to do this dynamically we're going to take the height of the screen and we're going to subtract the height of the player so we take height minus player height that gives us the top leftand corner where we draw this player so that means that since our height is 8800 and our player height is 60 we're going to draw this at 740 meaning the Bottom of the player will be directly at the bottom of the screen you'll see what I mean when we draw this but that's why I'm using this math here next we're
going to pass the player width and the player height so it goes X Y width height whenever you're using a rectangle in pame okay so now that we have our player we want to draw this player onto the screen screen so I'm going to pass this player rectangle to my draw function and then I'm going to go to Draw and I'm going to accept my player rectangle now I'm going to draw it to draw my rectangle I'm going to say pame dot draw. rect and then the first thing I'm going to pass is where I
want to draw a rectangle well I want to draw a rectangle on my window so I pass window the next thing I pass is the color that I want my rectangle to be in this case I'm going to use red now in the newest version of P game which most of you will Be using you can just use string uh colors so red white black orange any color you would know or you can use RGB so if I use RGB then that would be something like 255 0 0 where I have 255 red uh Z
blue and zero green RGB I think I read it in the in the wrong order red green blue yeah sorry so zero green and zero blue but you get the idea you can use an RGB color code or for Simplicity you can just write the color in which in this case is red okay next we are going To put the rectangle that we want to draw and that rectangle is our player so our player is a pame rectangle which is an accepted argument to this method here so we say we're drawing it on the window
it's a red rectangle and this is actually the coordinates of the rectangle right so it's at 200 it's at this height and it has this width and this height perfect now that we have that we should see a red rectangle appearing when we run our code there you Go we have our rectangle showing up on the screen fantastic now that we have a rectangle we want to move it around now to move the rectangle is as easy as adjusting the x coordinate of this rectangle so let's have a look at how we do that the
first thing we need to do is listen for different key presses so if the user presses the left Arrow key I want to move to the left which would be reducing its x value if they press the right arrow key I want to move to the Right so I'm going to say keys is equal to py game. key. getor pressed now this will give you a list of all of the keys that the user has pressed and tell you well if they press them or not so what I can do here is say the following
I can say if keys and sorry I said list I mean dictionary and then I can say py game. Kore left which is the code for the left Arrow key if that's the case then I can take my player dox and I can Subtract ract from that the player velocity which is a variable that we're going to Define now at the top of our program so we're going to say player player velor is equal to 5 let me just move this down Okay so we're saying if Keys py game. Kore left you may be wondering
how I found this I just know it because I've used it many many times before but this is the uh kind of what do you call it code for the left Arrow key if you wanted for example the a key Then it would be kcore a or Kore B or C ET Etc if you wanted like the shift key it's Kore shift there's a whole um kind of documentation where you can look up all of the key codes from the pame website you can also just look up pame key codes and you'll probably find a
big list that tells you but the common ones are going to be like space shift c a w Etc or left right so on okay so if they are pressing the left Arrow key then we're going to subtract The Y the reason we subtract Sor not the Y the x is because we want to move them left so by subtracting their x coordinate we move them closer to the 0 0 position so to the left that's why we're doing this subtraction now we have the player velocity set at five which means every time that you
press this key we're going to go five pixels backwards you can adjust that velocity if you want the character to move faster or slower now of course we're going to do the same Thing for the other Arrow key so py game. Kore right and then we say if I can get rid of that crazy autocomplete player X plus equals the player velocity one thing to note here when I use x that's simply adjusting the first value here so we start at 200 then we go back by the velocity or forward by the velocity right that's
how you access that you can also access the width property and the Y property as well as the height property And that corresponds with the values up here okay fantastic so now we should be able to move our player because we have this movement code so let's run and see if we can do that and using my arrow keys you can see that I can move my player however it's moving extremely fast now the reason for this is that we haven't set up a clock or kind of a timer that regulates how fast our pame
Loop is running now for some of you if you're on a slower computer you're going To run that and be like oh the speed is fine it works okay the issue is that the speed that this while loop runs at is what determines how quickly our character is moving if I'm holding down the key and this wall Loop is running really really fast I'm going to move fast if it's running very slow say you're on a slow computer then this is going to move slow we don't want that we want this Loop to always run
at the exact same speed so that no matter what Computer you're on it's going to run at the same pace and your character is always going to move at the same speed to do that we need to set up a clock object so we're going to say clock is equal to py game. time. Capital C clock then we're going to go here we're going to say clock. tick and then we're going to put 60 which is the maximum number of frames per second or number of times that you want want this wall Loop to be
running so you create a clock object Here and then inside of your wall Loop you have clock. tick this is essentially going to delay the wall Loop such that it will only run a maximum of 60 times per second if you wanted it to run faster obviously you would adjust this value to be whatever the fixed FPS value is that you would like okay now that we have clock. tick you'll notice that when I run my code my character now moves a lot slower so again you could speed this up by increasing the velocity and
then No matter what computer you're on it's going to be moving at a similar or the exact same speed okay so we're moving but notice here that I can actually move completely off the screen we obviously don't want that for our game otherwise you can just dodge by going off the screen so we need to make it so you can't move if you're hitting the edges of the screen to do that we just need to come here to our conditions where we're checking if you're pressing the left Arrow key and right arrow key and add
a guard Clause uh that makes such that you cannot move if you're going to be moving off the screen so the way we do this is we add another condition here with and we say if Keys P game. Kore left and we have the player doy minus the player uncore velocity is greater than or equal to zero now the reason we're putting this here is we're saying okay we're about to subtract the player velocity from the x coordinate so if when we Subtract this the player is still uh above zero or greater than zero so
their x coordinate is greater than zero then that's okay we can subtract this but if it's not so if we're going to be like negative 1 -2 neg3 Etc don't let them move hopefully that's clear why we're doing that that's why we have this code here now let's copy this and put the same thing here except now we need to change this a little bit because we're adding to the velocity or we're adding To the x coordinate sorry so we have player do X apologies Plus plus player dovel and then we're going to say plus
player. width and this is actually going to be less than or equal to the width of the screen now this one is a little bit longer because we have to account for the fact that player dox is the top leftand corner of our player so we need to add the velocity kind of like we did here but in the opposite direction because we're increasing it not Decreasing it and we also need to account for the width again this is the top leftand Corner then we have a width of in this case 40 pixels so we
need to make sure the x coordinate plus the width plus the velocity is going to be less than the width of the screen before we allow the character to move to the right okay now let's run this and see if it works and notice when I go to the right here I can't move any further than the very edge of the screen and same With the left hand side okay we now have a character that is moving around the next thing we need to do is keep track of the amount of time that has elapsed
we then need to create some projectiles that are coming down on the screen and then check for collision with those projectiles currently we're about halfway done if you're still following along at this point congratulations give yourself a pad on the back believe it or not most people do not make it this far All right so there's a few different kind of directions we can go in here in terms of what we want to write next but I think the easiest is going to be to handle the time so we know how much time has elapsed
to do that we are going to create a variable here called start time start time is going to be equal to time.time time.time is going to give us the current time so we're going to grab the current time when the game started and then we're going to create another Variable here called elps uncore time and make this equal to zero then beneath our clock. tick we're going to say elapsed uncore time and this is going to be equal to time.time minus the start time so we're essentially storing what time we started the wall loop at
then every time we iterate we're getting what the current time is and subtracting that from the start time which will give us the number Of seconds that have elapsed since we started the wall Looper since we started the game now that we have the elapsed time we can pass that to our draw function and we can draw the elapsed time on the screen so we're going to go to our draw function we're going to take elapsed undor time as another parameter here and then we're going to draw this now to draw this we actually need
to use a font because we're going to have text on the screen that says time you know 2 Seconds 3 seconds Etc so what we need to do is initialize our font module create a font object and then use that font to render some text on the screen so at the top of our code we're going to say pame do font do AIT we just need to initialize the font module don't ask me why we need to do this it's a requirement from pame we just do that at the top of our program then we're
going to come down here and we're going to say font is Equal to p game. font. s font with this capitalization and then we can pass any of our system fonts in this case I like to use comic Sands and the size of our font which I will choose as 30 you can change this to be whatever you want there's different types of fonts you can put in here you know Times New Roman aial uh Etc and then whatever the size is I'm just going to make it 30 so again the procedure is initialize the
font module create a font object here and Then use the font object to create some text which you can render on the screen so to do that I'm going to say my _ text inside of my draw function is equal to font. render and then I'm going to pass the text I want to render now in this case I'm going to say time colon and then inside of my F string here I'm going to say round and then a lapsed uncore time and then I'm going to put an S here then I'm going to put
a one and I'm going to put The color which is white don't worry I'll go through this slower I know that was pretty fast so we have render the first thing we do is pass the string or the text that we want to render on the screen now I'm using an F string available in Python 3.7 and above and this allows me to embed a variable directly inside of the string and have it rendered as a string so I'm saying time colon and then I am rounding the elapsed time to the nearest Second and I
Put this inside my curly braces so that I can directly use this variable in this round function then I put an S so that I have you know three four five whatever seconds next next I put one one stands for anti-aliasing don't worry about this too much but it just looks makes your text look a little bit better and then you pass the color that you want this text to be in this case I want white okay now that we have our text we need to render this on the screen so we're Going to say
win do blit and then we're going to blit the _ text and the position we're going to blit it at is 101 so just so we have a little bit of padding from the top left hand corner of the screen 10 pixels x 10 pixels y just moves us a little bit off the edge of the screen so it looks a little bit better all right now we should be rendering the uh time so let's see if that works by running our code and notice that we have our time it is Counting up uh and
it will keep displaying whatever the current time is awesome so now that we have our time the next thing we need to do is generate some projectiles now we're going to generate our projectiles on kind of a counting increment where the increment at which we generate that gets shorter and shorter meaning we kind of generate more of them uh more quickly as the time progresses making the game a little bit more difficult obviously you can mess With this mechanic however you'd like but I wanted to show you how we do some kind of dynamic rendering
here so we're not just putting one on the screen and say every one second it gets a little bit more complicated than that all right so to do this we need to have a few variables we're going to say star I'm going to call those little projectiles stars even though I know they don't really look like them I'm going to say star add incret is equal to 2,000 Milliseconds which means the first star that we add will be added in 2,000 milliseconds then we are going to have starcore count equal to zero and this is
actually just going to be a variable that tells us when we should add the next star I know it's a little bit misleading it's not telling us how many stars we have it's going to be counting so that we know when we get to this increment and when we should add another star to the Screen okay then we're going to have an array here called stars or a list sorry and this is where we're going to store all of our different stars that are currently on the screen then we'll draw all of them that are
inside of this list onto the screen okay so at the top of our code here although it doesn't really matter where you put this we're going to generate some of our stars so we're going to actually say that our starcore count plus equals clock. tick now I know This seems a little bit weird but what clock. tick does is we turn the number of milliseconds since the last clock tick so you need to actually do it in this way to keep track of the time accurately in my case it's about 16 or 17 milliseconds between
every clock tick but for you it could be slightly different so we say star count plus equals clock. tick and what this is doing is essentially counting how many milliseconds have occurred since again The last clock tick you could use this elapsed time variable but it gets a little bit more complicated based on how we're kind of keeping track of the time with this variable I know that I'm probably confusing you a little bit again this is just returning number of milliseconds since last tick so you do that um to keep track of kind of
the precise time in this variable all right now we're going to say if the star count is greater Than the star add increment then we're going to add stars to the screen so hopefully you see what I'm doing here this is 2,000 the star count is zero as soon as we have 2,000 milliseconds that have elapsed then we trigger this and then we add a star now I'm actually going to add three stars at a time but you could add a random number you could add 20 Stars you could add one star you can add
as many as you want to the screen so I'm going to say 4core in Range three because I want to add three stars and by the way the a placeholder variable that you use when you don't want to have an increment variable like I I don't actually care about the iteration count I just want to do something three times so I say 4core in range three okay now I'm going to generate the X position of my star because I want to randomly position them on the screen so I'm going to pick a valid x coordinate
and then We'll choose a y-coordinate and place the star on the screen so starx is equal to random do Rand in and then zero width minus the starcore width which is a variable that I don't believe we've defined yet so let's add that variable to the top of our screen here and make that that equal to let's go with 10 okay so again starcore X is equal to random. randint 0 with minus star width now the reason we're doing this is Because we want to pick a random integer in the range of zero and width
again minus star width which is a valid position for the x coordinate of the star that we are generating okay we can do this because we imported the random module at the top of our program we're then going to say star is equal to pame do rect and we're going to place this at the starx and at the negative starcore height which is another variable that we Need to Define so let's go here and make this equal to 20 okay now the reason I'm doing this is I want my star to start off of the
screen and then move down so when I do negative star height that means I'm going to get a negative y coordinate so my star starts not at the top of the screen a little bit above the top of the screen and then as we move it down it looks like it enters the screen if instead you were to put zero here then You would see the star kind of appear right at the top of the screen and then start moving down instead we want to see it slowly enter the screen so we do that by
giving it a negative height to start okay next we pass the star width and the starcore height and now we add this star to our Stars list so we say stars. append star like that okay so this now generates three random stars for us now that we have that we want to adjust our star add increment and we Want to set our star count back to zero so we say star count equal to zero and before that we're going to adjust this increment so it's slightly less than what it currently is so that we generate
Stars faster to do that we say star add increment is equal to the maximum of 200 and the star add increment minus 50 okay so let's just quickly go through what I did here I'm essentially saying with this maximum function pick the maximum value out of this and 200 now this makes It so that the minimum Star ad increment I ever have is 200 right so if star at increment is equal to 200 rather than setting it equal to 150 then 50 then 0 then netive 50 we always keep it at 200 okay so this
is just the minimum value that's what I'm setting here then in most cases what will happen is since star at increment is going to be much larger than 200 in the starting case equal to 2,000 we're going to subtract 50 Mills so that every time that this Runs 50 milliseconds kind of faster we generate another star hopefully that makes a little bit of sense but we go from 2000 to 1950 to 1900 Etc and it gets faster and faster F and faster the time in which we're incrementing a star and you can obviously adjust this
and change it to be whatever you want okay so that will generate Our Stars for us however if we want to see our stars then we actually need to draw them on the screen and we need to move them Downwards so we're going to do both of those steps before unfortunately we can see what's going to happen here so now after we generate Our Stars after we do our events and after we do our movements we're going to move our Stars so we're going to say four star in stars and then we're actually going to
make a copy of this Stars list the reason I'm making a copy of the Stars list is that I'm going to be removing stars from this list that have hit the bottom of the screen or That have hit our player if that happens if they hit our player hit the bottom of the screen we want to get rid of them because we don't want to be rendering them and uh moving them when they're not on the screen that's a waste of resources so I need to make a copy of this list because if I'm modifying
the list while I'm working on it I can get all kinds of weird errors so rather than doing that I make a copy of it so that I'm looping through the copy and then I Can adjust or mutate the original list as I go through this for Loop so I'm going to say star. y plus equal the star velocity okay so this moves the star downwards uh in the y direction by this velocity because we're adding to it meaning it goes down then I'm going to say if the star doy is greater than the height
of the screen then what I want to do is remove the star so I'm going to say stars. remove and then I remove the star which will remove the first Instance of this or really the only instance of it from the original Stars list nice next we're going to say l if star doy is greater than or equal to the player doy and the star. CID wct player then we are going to remove the star again so Stars do remove star and we're going to say hit is equal to true and we are going to
break out of this Loop okay you'll see why I'm doing this in a minute but essentially what We're doing with the second LF statement here is we're saying okay if the star. Y was not greater than the height then we're going to check if the star. Y is greater than or equal to the player doy now the reason we're doing this check here is because I only want to check to see if this star is colliding with the player if the star is at the bottom portion of the screen so if it's in the same
y kind of plane as our player if it's not there's no point in me checking Uh if the star has collided with the player right that just doesn't make any sense because if it's way above the player I don't need to check for Collision because I know it can't be colliding and in fact I need to add something here star. y plus star. height because again we need to account for the fact that the star has a height uh not just a y-coordinate okay so we say star star. y plus star. height if that is
greater than or equal to the player. Y Then we're going to check if the star has collided with the player so since both of these are P game rectangle objects that allows us to use this fancy function called Collide rect which just tells us if two rectangles have collided so if they've collided then I want to remove this star because it hit our player and I'm going to set a variable hit equal to true because we'll then look at that variable later on to see if our player has been hit by a star okay Now
we just want to go up here and say hit is equal to false just so that if we do end up checking this variable later on we don't get an error where it's undefined okay so I know I've done a lot there but we started by generating all of our stars we then moved all of the stars now we need to draw all of the stars so I'm going to pass my stars to this draw function I'm going to go to my draw function and I'm going to start drawing them now it doesn't really Matter
where you draw them but if you draw them after the player they'll appear on top of them if you draw them before the player they'll appear behind the player so pick where you want to draw them I'm going to do it after so you can see it on top of the player okay so fairly straightforward here we're going to say four star in Stars P game do draw do rectangle on the window with the color white r star okay Straightforward same as our player we're just doing it for every single star all right so that's
going to be a majority of the game done let's run it make sure it works and then we'll handle showing something on the screen when the player gets hit by a star okay so let's run and you should see that we get some stuff appearing on the screen but it looks like we got an error so what is our error here it actually didn't show up for me so let me run this one more time And we'll wait for the error message and it says star velocity is not defined okay so that's a variable that
we need to Define so let's say starv is equal to three again feel free to adjust that to be whatever you want okay now let's try it and see if our Stars start moving and there you go three stars are generated and they start moving on the screen perfect and notice that they kind of disappear when they hit the player or when they hit the bottom of the screen Okay fantastic so now the last thing we need to do is just put something on the screen that says hey you collided with a star you lost
the game and that will be finished okay great so to do that we're going to go down to the bottom of our wall Loop here here and before our draw statement we're going to check if the player was hit by a star so we're going to say if hit then we're going to do something now really all we're going to do is just generate some text that says You lost put it on the screen kind of delay for a few seconds and that'll be it and if you want to adjust this game and kind of
make it longer add levels you can do that from here so we're going to say lore text is equal to our font. render you can make a different font if you want I'm just going to use the same one I'm going to say you lost exclamation point and then one and then the color of white okay now I'm going to draw this on the screen so I'm going to Say win do blit the lore text and I'm going to draw this in the center of the screen to draw this in the center of the screen
we do the following we say width / two minus the lore text. getor width which is a uh method you can use to get the width of your text object divid by two and then do the same for the height so we say height divid 2 minus lore text doget uncore height / by two okay so let me just quickly explain why we're doing this we Want this in the middle of the screen but we need to pick the top left hand position of the text that puts it in the middle of the screen so
you might naively think that you can just do width over two because that's the middle position of the screen but you can't you actually have to get the full width of the text object and then divide that by two and subtract that that from width over two right so if we have um can I kind of run this let's run this and see So let's say 500 is where my mouse is right if I draw my text it's going to go this direction from my mouse so I need to shift it back half the width
of the text and then draw it so that it fills the screen completely in the middle and then obviously the same goes for the height okay hopefully that's clear uh that's why we're doing that all right so now that we've blit this on the screen we need to update the screen so pame do Display. update then we are simply going to pause so we're going to say pame time. delay I'm going to delay for 4,000 milliseconds which is 4 seconds and then I'm going to break which will break this wall Loop and will end the
game okay so let me quickly run through we generate the text we draw it onto the screen now since I'm not doing this in the draw function I need to manually update the display we actually see that appearing then we just freeze the game so this is Just delaying everything for 4 seconds just so you can see the text and then we break and the game ends if you wanted to you could call the main function again or you could have the game Run a second time you can do whatever you want here you could
say how long you've lasted whatever you can add a scoreboard but this is where I'm going to leave it for now so let's just run make sure this is working and then that's pretty much going to wrap up this tutorial okay so Let's just see if we can Collide here and we do and notice it says you lost and and then the game is going to end and we can run it again okay fantastic so let me zoom out a bit here so you guys can read some more of the code I'll kind of scroll
through it slowly obviously all of this code will be available from the link in the description at my GitHub but that was an introduction to python game development hello everybody and welcome to another YouTube video so in today's video what I'm going to be doing is going over Pi game for beginners so as you can already see here I have a little game on my screen the purpose of this video is going to be to introduce you to the module called P game in Python I'm going to cover a lot of stuff in this video
including sound effects images moving objects Collision most of the fundamental and main things you need to know to actually create a game and we to Give you an idea of what we're going to be building it's nothing complex this isn't meant to be fancy again it's just meant to teach you how to work with this module and I figured we could do this kind of really simple two-player game to give you an idea of how everything works in pi game so you can see we kind of have two spaceships here they can move around the
screen and I'm moving these with the same keyboard so I have WD moving the one on the left and I have The arrow keys moving the one on the right and when I press the left or right control key that is actually firing bullets now there is sound effects I don't know if you guys can hear them I'll stop talking and hit it for a second so you might be able to hear that either way there is sound effects we'll be adding that in there and we'll show you how this works and you can see
that once uh one of the enemies is lose es so they run out of Health you can see that At the top it says boom yellow wins and even though I have these on the wrong side um we'll fix that in in the original video anyways you get the idea this is the yellow spaceship this is the red spaceship really they should be on opposite sides for the tutorial we'll fix that so the first thing we need to do when we're going to be working with the module called pame is we need to install it
on our computer now for some people this can be tricky it really Shouldn't be that difficult but what you need to do is open your command prompt or open some terminal window depending on what operating system you're on if you're on Windows you're going to open command prompt if you're on Mac or Linux you're going to open your terminal now this command may vary based on your operating system I'll go through all of the different variations but the first thing you want to type inside of your command prompt doesn't matter what Directory you're in is
PIP install and then simply the module pame go ahead and press enter that should install pame in your python interpreter and your python environment then you should be good to go now for some reason this isn't working or when we get to the next step which is just testing our code and importing P game you don't see anything happening try the following command pip three install py game so just add a three to the end of pip there uh oops I Didn't mean to delete the three uh but pip three install py game hopefully that
one should work for you and if neither of those work for you then try the following python hyphen M pip install and then py game like that and if this one doesn't work either then do the same variation so add Python 3 hyphen M pip install py game if none of those four commands work for you and you can't uh install a p game I'll leave links to videos in the description that show you How to fix your pip they're not directly called that but actually this will be perfect for this because they are how
to install pame on Mac and windows respectively anyways let's continue now we have pame installed we're going to head to some environment that we're going to write code in you can do this in the default idle um so the thing that just comes with the basic python installation or you can use something like VSS code Sublime Text whatever you Want so I'm going to be using vs code code uh this just makes it easy for me for me to run my code by pressing the Run button up here but again feel free to use whatever
you want you don't need to use vs code it doesn't matter what you use we're just going to do everything in one file anyways now that reminds me that before we actually jump in we need to download some assets for this game so you saw I had a background I have those spaceships all of the stuff Including the code for this tutorial is going to be available on GitHub so I will leave a link in the description what you're going to need to do is download this assets folder mainly you can download the code file
as well which will be uploaded here with the entire code for this video afterwards but to do that you're just going to press the link it should bring you to a page that looks like this you're going to press code and then download zip now if you understand How to use GitHub uh obviously I don't need to tell you how to do this but downloading the zip file so let's actually just do it on here to make sure everything's going to be all good so I'll put that into my downloads then you're going to open
up the zip folder you're going to go inside the interior folder you're going to grab the assets folder on uh windows I usually like to just uh cut it so CR X you can also copy it and you're going to paste it beside Wherever your python file is so if you have your python file on your desktop I would recommend first of all you put it in a folder called you know pame for beginners or whatever then just put this file beside it so that you have the assets folder and then whatever your main python
file is is in the same directory that's really important so anyways do that and then we can go ahead and continue all right so apologize for the intro but let's get into this the First thing we're going to do now and notice that I have pame tutorial and then I have my assets in my main.py file file obviously create a new python file and inside of that file you're going to type import py game this is just to make sure that this is working so we're going to import py game then we're going to run
the code you can see it kind of pops up a little terminal right here and notice it says module not found no module named pame now I'll fix that on My end but make sure you guys don't get this message if you get hey welcome to pame or some little text like that you're good to go and you're ready to continue so I'll be back after I fix this for myself all right so I'm back you can see I'm now getting the message p G 1.9.6 doesn't matter what version you're using hello from the pame
community and we're all good to go and uh get started now one last note here I'm just trying to cover all of the Issues that happen do not name your python file py game if you do that it will not work so just name it anything other than Pi game very important okay now that we have that let's get started so first of all what is pi game well Pi game is a 2d Graphics library that lets you make little games it's actually really powerful I've created a ton of awesome projects using pame and well
it's pretty simple to actually set up the first thing that we need to do Whenever we kind of start making a game in P game is we need to make the main surface now I usually just refer to this as the window again you can call it whatever you want but in pi game everything that we're working with is usually referred to as a surface so you might hear me use that term but anyways I'm going to start in in all capitals I'll tell you why in a second I'm going to say win equals py
game. display. setor mode and then inside of Here we're going to put a topple and we're going to put the width and the height that we want the window to be so it's usually good practice to Define two variables Above This that says width comma height and then is equal to whatever you want the width and the height of this game to be now I'm going to make mine 900 by 500 if you're on a really low resolution display this might take up like a large chunk of the display so feel free to scale these
Numbers down it doesn't really matter what you make the width and the height but it might affect what you want to make the dimensions of say the background or the images later on anyways we're going to say width height equal 9500 wind equals py game. display. setor mode and then inside of here I'm going to say in all capitals width height so I'm pretty much telling pame hey let's make a new window that is of this width and this height and I've Defined those both above the reason I'm using all capitals here is usually it's
just good convention to Define all of your constant values in capitals so our window even though it may potentially change uh is fine to be in all capitals and our width and height those are constant they're not going to change so I'm making them all capital values all right so now that we have that uh let's actually start creating our first like P game event Loop and and having something Pop up on the screen so usually what I like to do is I like to define a main function and inside of this function I'm going
to put all of the code that kind of handles the main game Loop in pi game so usually when you create a game you have a loop and this Loop is doing things like redrawing the window checking for collisions updating the score whatever it may be and anyways we're going to put that inside of this main function right here so the first Thing that we need to do is set up a while loop this while loop will be the game Loop and this will actually let our game not just instantly open and then close so
think of it as like an infinite Loop and then we'll terminate it whenever the game ends so I'm just going to make a variable I'm going to say this is run it's equal to true then I'm going to say while run so until we set run equal to false or we break out of this Loop this Loop will keep running the First thing that you always do inside of your event Loop in P game is the following you say for event in pi game do event like that and then do getet and inside of here
is where you check for the different events that are occurring in pame so don't worry about the fancy syntax but this is just getting us a list of all of the different events We're looping through them and then we can check what these events were and based on what they were that we can we Can do something different so the first event that you usually check for is if the user quit the window so again I'll show you all this works later and we'll go into more detail but just to get right into it we're
going to say if event. type equals equals and then py game. quit in all capitals what we're going to do is we're going to say run equals false like that and what this will do is end this while loop so effectively quit the game now at the Very end of this while loop what we're going to do is say py game. quit and this will quit P game for us and close the window so hopefully this is clear so far but that's all this is doing we're getting all the events if quit is an event
that occurs then we'll exit the W Loop and we will quit now I'll show you what that event is in one second but let's continue so now that we have that uh let's actually go down to the bottom of our program and let's say if uncore Name uncore uncore equals uncore uncore maincore uncore then we're going to call the main function now what this is doing for anyone who's confused is just making sure that when we run this file we didn't it's it's hard to describe this but it's making sure that we're only going to
actually run this main function if we ran this file directly so in Python if you're not aware you can import modules right so let's say I imported this file from another file Well if I did that and I didn't have this if name equals equals main thing and I just had the main function you know in the main line like this then it would automatically call this uh and start running the game now we might not want that to happen and I only want to run the game if we run this file directly not if
this file is imported from somewhere else so that's why I'm doing this um you don't have to really understand what this means but the name Is simply the name of the file and main is telling us hey this was the main file that was run that best way I can explain it that going into too much depth but anyways enough of this we haven't seen anything yet so let's run it and and see if anything pops up so we're going to run and there we go we get some window like this right black window nothing
just says P game at the top now the quit event is when we press the X on this window so when I press that notice that Boom we quit we're all good because we handled this quit event if we didn't do that it wouldn't have quit the window we would have had to force quit this application which obviously we don't really want to have to do so there we go we've got our first pame window popping up but that was kind of boring now I want to show you how we can draw stuff onto the
screen and how we can change the name of that window so usually what I like to do is I like to go up to the Top of my program and say p game. display. setor caption and I like to give it some name so here this will set that little name caption that you saw that said pame window or whatever it was so you can set this to whatever you want for Simplicity I'm just going to say first game like that I'm going to save going to go ahead and run this and notice that now
it says first game where my mouse is here at the top left hand corner all right so now that we've got That let's start drawing some some stuff onto the screen and doing some more uh advanced stuff so the first thing I'm going to show you is how we can fill the screen with a specific color then we'll start drawing some rectangles and all of that and getting into the game so to fill the screen with a specific color this is pretty straightforward you're going to use the window so you're going to say wi like
that and then you're going to say do fill and then you give This a color and it will fill the screen with this color now the question is how do we actually give this a color what do we type in for the color well in P game all of the colors are RGB meaning red green blue so what you need to pass is a tupple with three values one value for red one value for green one value for blue if you're not aware of RGB the ranges of numbers that you can pass in here are
between 0 and 255 inclusive so that means you can include 0 or 255 so I Can say something 255 255 255 funny enough this is actually white when you look at RGB because you have the most red uh the most green and the most blue so anyways I'm not going to actually pass in a tupple like this because this is kind of hard to understand that this is white I'm going to make a variable at the top of my program here in all capitals I'm going to call it white and I'm going to set that
equal to 255 255 255 now instead of passing that I'm Simply going to pass white inside of here so this way if someone else is reading my code they know that hey this is the white color that's what we're filling the screen with so let's test this out going to run the program and why is it not working well the reason this isn't working right now is because we did not update the display so in P game the way it works is we can draw a bunch of stuff onto the screen and and you'll see
that when we start doing that We draw all these different things but the display will not be updated it won't show the most recent things that we drew unless we manually update it so what we need to do is say pame like this do display do update so now when we update the display after we fill the display it will update and it will show us the white so let's have a look there we go now we are getting a nice white background you're welcome to mess around With the color and you'll see different colored
backgrounds all right so there we go we have white awesome we are making good progress now the thing is I usually don't like to do all of my drawing inside of this kind of main game loop I usually like to have the main game Loop handling like all of the collisions of the logic in the game and then having some functions outside of that that handle specific things that I can easily call so what I'm going to do Just to clean this up and make it easier because we're going to be drawing a lot more
stuff than than just this is say Define draw undor window now inside of here what I'm going to do is just take as an argument whatever I want to draw now in this case we don't really have anything specific that we want to put on the screen we're just filling it with a background color so I'm not going to take any arguments I'm going to take these two lines of code right here Place them inside of this function so let's do that and now right before uh inside this W Loop before the py game. quit
I'm just going to call this function so now every time I Loop through this Loop here I'm calling draw window and well this will draw stuff onto the screen so let's run this and there we go we get the same thing it is still indeed working awesome so that is great now the next thing we need to talk about is frame rate or essentially how Do we control how much this is refreshing because if we have a look at this right now we have an infinite Loop we have some event Loop going on right here
and then every time in the loop we're just drawing something onto the screen that's fine but right now we are drawing this white background as many times as we possibly can per second onto the screen it's it's solely based on the speed of our computer right on my computer I have a pretty fast machine This is drawing probably hundreds of times per second in fact we could measure it but I would guarantee it's hundreds of times per second or even thousands now we obviously don't want that because that means on different computer computers our game
is going to run at a different speed because it's based on how quickly this while loop is running so to control this we need to implement something called FPS or frames per second so I'm going to Define a Variable up here I'm going to say FPS I'm make it equal to 60 and this pretty much will Define how quickly or how many frames per second we want our game to update at now most standard games that are not like your big AAA games are running at 60 FPS so we're going to go ahead and just
Implement a hard-coded FPS of 60 so now what I'm going to do is I'm going to define a clock object in my uh main function here I'll discuss what this is in a second but I'm going to say Clock is equal to P game. time. clock and inside of my w Loop I'm going to say clock. tick and then I'm going to put FPS now what this is going to do is control the speed of this W Loop so this will make sure that we are going to run this wall Loop right here 60 times
per second no matter what unless our computer can't keep up with that speed in which case it will run as fast as it can so clock. tick is just ensuring that we never go over this capped frame rate Of 60 which is good that's what we want it makes our game controllable and we know it's consistent on different computers so now if we run this uh actually let's just go up here you notice that nothing's going to change except just internally it's only running at 60 FPS okay so that's great but our game is pretty
boring right now we have nothing on the screen so let's actually go ahead and Implement some characters so I want to have two spaceships one on The left hand side of the screen one on the right hand side of the screen I want them to face each other and I want them to be able to move so let's tackle that next so what I'm going to do is I'm going to start importing the images that I'm going to use for these spaceships so I'm going to start by just saying yellow spaceship image and this is
going to be equal to pame do image. loadad and inside of here we're going to load the yellow spaceship Image so if we go inside of assets we can see that we have five things we have spaceship yellow spaceship red space PNG that's the background and then two sound effects which we'll get to later again you can download this from the link in the description it's the GitHub link so what we need to do is import uh these images right here so the red spaceship and the yellow spaceship we need to load them into pame
so we can draw them onto the screen so what I'm going to do at The top of my program is I'm going to import OS the reason I'm importing OS is because I'm going to use OS which is operating system to help me Define the path to these images so these images are inside of the asset folder the assets folder is in the same dire as our python file remember that's very important and then what we're going to do is we're going to look inside the assets folder and then look for these specific images so
to do this we're going to say os. Path. jooy this is just a thing that you can do in Python the reason I'm doing this rather than just separating things with slashes is because depending on what operating system you're on the directory separator might be different so this will handle that for us but os. path. jooin and I'm going to join the path to the folder assets with the path to the the image so I'm going to say assets and then spaceship like that underscore and I guess we're doing Yellow first. PNG so I apologize
that it's hard to read let's actually just zoom out a bit so you can see this we get yellow spaceship image go py game. image. load os. path. jooy assets spaceship yellow.png so let's copy that line and I'm going to do the same thing now except instead of yellow we're going to do red so red spaceship image and now all we have to do is just change this to red because we have the red image right there so now we have our two spaceship Images my formatters help me out here by putting them in a
way that we can read them now what we want to do is draw these onto the screen so we can actually see them so before I get too complicated and talk about anything more let's just show these up on the screen or Draw them on the screen and see what they look like so we'll say wind. fill white remember I'm doing all my drawing from inside of this draw window and now I'm going to say win. Blitz now you use Blitz when you want to draw a surface onto the screen so technically these images when
they get loaded in by py game are known as surfaces so we have to use blit to blit them onto the screen now that's kind of a misleading explanation but you can kind of imagine that anytime you have text or images you're going to use blit to put them onto the screen but I'll go through that later so anyways wind. blit we're going to say yellow spaceship image because That's our image right here and then I'm going to define the position on the screen in which I want to draw these images so remember that our
screen is 900 by 500 so 900 width 500 height which means that I really should be drawing my spaceship within those Dimensions so it shows up on the screen now I can draw it off the screen at like a negative coordinate or something but obviously that doesn't make much sense to do now another thing to note in P game is that When you draw something onto the screen it draws from the top leftand Corner in fact it's probably a good uh point in time now to talk about the P game coordinate system so excuse me
because I'm on a mouse this is going to be really rough drawing but let's imagine this is our P game window you know traditionally when we look at like an axis right or we look at a graph you would say that 0 0 is right here in the middle of the window now in pi game that Is not the case we don't have that because we don't have these uh kind of coordinate systems so in pi game the top left or 0 0 is the top left sorry so 0 0 trying to do two zeros
here with the mouse is the top leftand Corner which means as you increase your X you're going further to the right and as you increase your y you're going further down of course y being you know vertical and X being horizontal so if I wanted to be at the bottom of the screen and my Height was 500 I would draw somewhere like 400 right and maybe that would put me you know like somewhere around here so just keep that in mind uh this is the coordinate system for p game and when we draw an object
in uh in P game we draw it from its top left so it's consistent if I draw an image at let's say what would this be reasonably like you know 500 by 200 or something like that we will start drawing it from the top left so the uh the width of the object or the Width of the surface will you know be going to the right if that makes sense then the height will be going down so even though it's at this position we're not drawing it from the center we're drawing it from the top
left of the image so keep that in mind okay now we went through that so let's draw this image so we want to draw the top left of the spaceship or we're picking where we want to put the top left of the spaceship so in this case let's just put It at like 3001 100 just to see what it looks like and then in fact for now let's just draw the yellow one so we're going to go ahead and draw this and that's great okay so it's taking up a good chunk of the screen this
is obviously too big we're going to have to shrink this down but there you go you can see the spaceship showing up on the screen awesome now keep in mind though if I were to draw this spaceship before I were to fill the screen so if I do Something like this then what do you think is going to happen so I go ahead I draw the spaceship then I fill the screen with white and then I update what do you think's going to happen I'm G to run and we don't see the spaceship the reason
we don't see the spaceship is because uh we drew the spaceship before we filled the screen so the order in which we draw things matters and we can draw over top of something that that's totally valid that happens all the time Okay so just keep that in mind so now we have the yellow spaceship uh and what we want to do now is resize this spaceship so it's a bit smaller so we should pick the dimensions we want to resize it to then we also should rotate this spaceship so it's facing the correct direction so
actually going to start by um resizing this image and then I will rotate it so I'm going to say yellow undor spaceship like this and this is going to be equal to and then I'm going To uh resize and rotate this image in the same line I'll show you how to do both of them so in pame to resize something you're going to say pame dot not image sorry dot trans nope dot transform like that dot and then scale and inside of here you're going to pass the image that you want to Res size so
we're going to pass yellow spaceship image like that and then you're going to pass the dimensions that you want to resize this to so our spaceship was Pretty wide it wasn't that tall we could look at the aspect ratio to determine what we want to resize this to but I'm going to go with 55 by 40 so 55 width and 40 height if we consider that the dimensions of our screen are are what are they here 900 by 500 that seems like a reasonable size to make our spaceship but feel free to make this larger
feel free to make it smaller feel free to make it square mess around with it and see what you get but anyways that's Going to scale our spaceship now uh so it'll be much smaller so let's do the same thing for the red spaceship so let's say redcore spaceship like that is equal to py game. transform. scale and then red spaceship image we're going to resize it to the same thing 55x 40 now since I'm using these numbers multiple times and I might use them later on makes sense just throw them in a variable so
I'm just going to say um you know Space ship underscore width and then spaceship like that underscore height is equal to and then 55 by 40 and now I'll just replace these values just in case we ever want to change this it will work everywhere in the program so spaceship width and then spaceship height like that let's copy this and let's simply put it here okay so now that we have that before we rotate it let me actually just update this so instead of drawing a yellow spaceship image I'm just drawing Yellow spaceship because yellow
spaceship I know it's kind of messy to see here uh is now the one that is scaled down so let's go ahead and run this and see what we get and now we get a much smaller spaceship that looks much better to Me Maybe needs to be a bit taller but honestly totally fine so let's leave it at that okay so now we need to rotate this image so to rotate it I'm actually going to go and find yellow spaceship and in fact let's Separate these to make it easier to see and I'm going to
wrap this scale within a uh a rotate so you'll see how it works but let's go pame do image. rotate oops like that okay and now I know it's confusing with the brackets I'll go through it we're going to pick the angle that we want to rotate this at so I'm pretty much saying py game. image. rotate this is the ending bracket at the Very end there we're plugging in this as the thing that we want to rotate which is the scaled uh down yellow spaceship and we pick how much we want to rotate it
so rotate it I want to rotate to the right and I want to rotate it 90° now let's see if that's correct we might have to rotate it 270 I forgot which way it was facing originally but let's see if this actually gives us the rotation so let's run uh and there's no pame oops sorry guys uh this is not py game. Image. rotate I just got an error there this is py game. transform. rotate so make that uh fix there on line 15 okay so run now and there we go we can see it's
facing the correct direction Okay so we've done that successfully now with the yellow spaceship now we want to take the red spaceship and rotate it but so it's facing the other way so let's copy py game. transform. rotate let's wrap this here again and then let's go comma and let's rotate this one 270° because We want it to face the other way so now we can draw the red spaceship as well so let's go down here and let's say wind. blit oops didn't mean to open that uh win. blit let's blit the red spaceship and
let's put a little bit further away let's put at 100 100 or actually let's put at 70000 okay so take a quick look at this make sure your code matches now let's run and there we go we have our two spaceships facing each other all is Looking good okay so now we have the spaceships now I want to show us how we can move these spaceships around so to move these spaceships um is not actually super complicated but we need a way to keep track of their X and Y position um I guess as well
as their width and height and then to change that position and pretty much just change where we're drawing them to be at their X and Y position so what I'm going to do now is I'm going to write a little bit of code I'm going to go a bit faster than I've been going and then of course we'll stop and go over everything to make sure that you guys understand let's go down into our main function and now what I want to do is I want to Define two rectangles which are going to represent my
yellow spaceship and my red spaceship so I can control where they're moving to so just follow along and then uh we'll explain what it is so red equals and I'm going to say red this is going to represent Our red player is equal to pame do rect like that and inside of here what I'm going to do is simply Define the position uh or a rectangle that represents this red spaceship now you'll see why we're doing this but the POS or the arguments sorry for the rectangle are X Y width and height so I Define
the X position the Y position and the width and height that I want my red player to be at so we already know what the width and the height are going to be because That's going to be equal to whatever we scaled our uh spaceship to right which was spaceship width and spaceship height good thing we stored that in a variable but the X and Y we can pick now we want the red spaceship I mean we can decide this but let's say we'll put it on the leand side of the screen so in that
case let's make its X and Y something like this so we'll make its exp position 100 and let's make its y position 300 and then for its width and height we already Already know what this should be spaceship width and spaceship height okay so now we're going to do the exact same thing for the yellow uh player here so let's instead of red let's change this yellow and then let's just change its X position so it's over near 700 so they're far away all right so now we have red and we have a yellow rectangle
all I'm going to do now is I'm going to pass this rectangle so actually both of these rectangles red And yellow over to my draw window function so now inside of draw window I'm simply going to take red and I'm going to take yellow and rather than drawing my yellow spaceship and my red spaceship at a kind of predefined position I'm going to draw it at whatever position my red and yellow argument are at this way I can modify red and yellow and when I pass it to draw window it will change where we're drawing
these rectangles so uh let's or These spaceships sorry rectangles just cuz we're representing them with rectangles but for our yellow spaceship we're going to draw this at yellow dox and yellowy now the reason we have access tox Andy is because yellow is a p game rectangle and it defines that the x is this and the Y is this so it just makes it really nice for us to use so yellow dox yellow doy now for red we're going to say red dox and red doy like that so now we draw a red in our yellow
Spaceship now to show you how this would actually move around let's just do something really simple every single Loop I'm going to move my yellow uh spaceship one pixel just so you guys can see it moving on the screen so I'm going to say yellow dox plus equal 1 all this is going to do is add one to the yellow X position and move it in fact let's actually change this to Red uh because red will have more time to move so this will move 60 pixels per second because The clock is ticking at 60fps
and we're updating the exposition 60 times and adding one to it so hopefully that's clear but let's run this and now notice that we have a red spaceship moving in uh the incorrect Direction on the screen and I noticed that I actually put these spaceships on the wrong side because of the way that they're facing so we have two options we can change where they are so we can just change 700 100 or we can change their rotation I think it's Easier to just change uh this right here so let's change 70000 so they are
on the right side of the screen let's run this and now you can see it's moving backwards but they are on the correct side of the screen now the reason this is moving again it's cuz we're updating the exposition and we're drawing it at the exposition so as we change red here well we're pass ing that updated red over here and then it's it it's moving right so hopefully that's clear anyways That is how we would move it so now what we need to do is we need to actually change the X and Y position
when we press the arrow keys right so that we're moved based on the user input so we have two things that we need to check we need to check whether the red spaceship is moving or whether the yellow spaceship is moving now let me just run this one more time yellow spaceship is on our left red is on our right so we want to use WD for the left and the arrow keys For the right spaceship because because that just intuitively makes sense on the keyboard so let's start doing this I'm going to start doing
it for the WD Keys uh so for the spaceship on the left which I can never remember I think it's the yellow one yeah it is the yellow one and then I will show you how we can do it for the red and how we can kind of clean up the code a bit so there is multiple ways to do this in pi game you may have seen if you've watched other Pame tutorials of mine that I don't use the method I'm going to use here the reason I'm going to show you this method is
because this allows you to press multiple keys at the same time whereas the other method I've shown previously which I'm just not even going to bother showing here only lets you press one key at a time and actually we'll show it later in the video so I I can talk about it then uh but anyways what we're going to do is say Keysor press is equal to py game. Keys actually sorry just. key. getor pressed what this is going to do is every single time this wall Loop is running and we reach this line so
60 times a second it's going to tell us what keys are currently being pressed down this way we can just look at all of the keys check if the ones that we're looking for are pressed down and if they are respond to that press this also means that if the key stays pressed down it will still Register that it's being pressed so it's super useful and well you'll see as we get into this how this works but all we have to do is say if keysor pressed then inside of here py game. K underscore and
then the name of the key that we're checking for you can kind of see a list is popping up on my screen here out on how they work uh the ones that are special keys are in all capitals and the ones that are just letters or numbers are usually just lowercase although I Guess you can't really capitalize a uh a number but anyways we're going to start by checking up down no we'll go left right up down so the first key is going to be a so this would be left right so let's just leave
a little comment here let's say this is left so if we press the left key what should we do well we should move the spaceship to the left how do we do that well if we looked at the top left being 0 0 that means if we're going to the left we're moving Closer to 0 0 on the x-axis so let's subtract from our x value to move us backwards or to move us to the left right so closer to 0 0 so this since this is for the uh yellow spaceship we're going to say
yellow dox minus equals and then what should we minus here well how much we want them to move when they press down this key now since we're going to use this multiple times it makes sense to go to the top of our program right after FPS we can say Velocity or Vel is equal to and then I'm just going to set this equal to five feel free to change that around and make that whatever you want but let's make that five and now let's say yellow dox minus equals velocity now before we go any further
and get into more keys Let's test this and see if this is working so Keys pressed equal py game. key. getet Square pressed gives us a list of all the keys we check with this expression right here if the a key is being pressed If it is we modify the X so subtract values from it which will move us to the left so let's try this I'm going to press the a key and notice that I can move left obviously I can't go anywhere else there you go and now I'm off the screen so that's
something we're going to have to check as well uh if we're off the screen we're not going to have to let someone or we're going to have to disallow someone from moving if we're off the screen but for now that's fine We'll do that after so now let's handle the other keys so we can actually copy this line right here uh let's fix the indentation now instead of the a key let's do the right key which is going to be D so let's change this comment to right uh actually just want one space for my
comment here and now yellow dox since we're moving right rather than subtracting the X we want to add to the X so let's add to it like that and now let's try both these keys so now I can Move left and right but I cannot go up and down and keep in mind I can go off the screen in either direction so again something that we're going to have to check Okay so we've done that now now let's do the up and down key so we can copy this again and this uh modification will be
pretty easy so now for up that's going to be W for down that's going to be S so let's change this comment to be up let's change this comment to be down and now instead of the Y being modifi or Sorry instead of the X being modified I kind of spoiled it the Y is going to be modified so that's actually all we have to do but what this is doing now if we're moving up we need to subtract from the Y because the top left left is 0 0 so when we go down that's
adding to the Y so when we go down with s we add to the Y value and that will move us down so let's save that let's check this I'm going to run and now I can move up down left and right and kind of on diagonals Because I can press the same keys at once right so if I press down and left or I press up and right you can see that I'm moving diagonally so that's great um now what I want to do is actually take this and I want to put this in
a separate function because it's going to get kind of messy if I'm doing this twice inside of this Loop right here right so I'm just going to copy all of this code that I just wrote I'm going to write a function here I'm going to say Define yellow underscore movement like that now actually we could say yellow handle movement or something that makes more sense yeah yellow handle movement inside of here it's going to take an argument called keys and all I'm going to do is the exact same thing that I have before and actually
this argument is going to be called keysor pressed and I'm also going to take in yellow now it may seem that this is over complicating things But trust me it's going to be nicer when we do the other movement for the other character we're taking in that Keys press list we're also going to take in the yellow character our code doesn't change whatsoever we've just moved it so that it's kind of separate and it's easier to see so now what I'm going to do inside of this Loop is I'm going to call Yellow uncore uh
handle movement like that really I probably should have called it handle yellow movement but That's fine we're going to pass key keysor pressed and then we're going to pass yellow like that now what this will do is it will give the keys press list that we need and it will give our yellow character and then we'll just do everything we were doing before but inside of this function now you can probably guess how we're actually going to handle the right uh players or what am I saying the right players the red player all we need
to do is copy this Function we'll just do a paste like that and now we're going to do the exact same thing except instead of yellow it's going to be red instead of a uh DWS it's going to be up down left right or I guess left right up down so let's change this to Red let's change the name of this function to red as well and then we can just change all of these yellows uh to be red I'm just going to do them manually but if you're fancy you could use the find and
replace all right so Exact same thing now we're going to change our left right up and down the arrow keys are really easy it's literally just Kore left Kore right oops k kcore down and kcore oops well I did in the wrong order kcore down kcore up all right so that should be good we don't need to change anything else now all we need to do is call this so let's call this function uh redcore if we could do it in the right case redcore handle movement let's pass It the same thing keysor press like
that and then red now the red movement will be handled let's make sure this is all working so let's run this and you can see that I can move my left guy and now I can move my right guy and they move at the same time with no issues awesome so that is great we're making good progress but now we can move off the screen right so we need to handle this so that we can not so we can no longer move off of the screen but before we do that just Because it's going to
make this part easier and less repetitive let's handle the fact that in the middle of our screen we want a border right so I don't really want my red and yellow spaceship cuz you remember the game we made at the beginning to kind of be able to face like right beside each other I want them to have their own halves of the screen and not be able to cross over so let's make a rectangle that's kind of a border uh and divides the middle and then we'll Draw that on the screen and make it so
that our characters can't move past that border so let's go to the top of the program and we're just going to Define uh wherever we want doesn't really matter I'm going to say Border in all capitals and this is going to be equal to pame you guessed it. wct this is just going to be a Rec rectangle and we'll just draw this rectangle onto the screen so I need to pick where this is going to be so let's be clever about this where Should my rectangle be I need the X and Y position and then
the width and the height well the X position we'll need to figure out the Y position is obviously going to be at zero because we want to start at the top of the screen and go all the way down so we're going to say Y is equal to zero the width and the height so the width we can kind of pick what we want the width to be I'm just going to make it 10 the height needs to be the height of the screen cuz we're Starting at zero so it needs to fill the ENT
entire screen and then the x is what we need to figure out so I want this to be exactly in the middle of the screen which means I can say width over two that's going to give me 450 right to be in the middle but then since we have a width of 10 let's just uh go to paint here quickly I'll show you what happens if we do that so let's say we have our screen you know this is width over two and this is like right in the middle of The screen okay so this
is me trying to do a five with my mouse this is 450 okay uh now if I draw a rectangle here that has a width of 10 what's going to happen is I know this is like a really exaggerated width but we're going to draw it like this right I don't want to draw it like that I want to draw it like this so how do I do that well I need to subtract half of the width so I can figure out where the z0 position of my rectangle should be because really I'm Not drawing
the rectangle from the middle I'm drawing it from 0 0 so I need to draw it such that it will be in the middle of the screen when I draw it if if that makes sense so anyways the point of this is saying that if we have a width of 10 I need to subtract five from its X position so put it at 445 so that way it draws in the middle so let's do that uh rather than I guess since our width is hardcoded I'll just subtract five and now once we draw this on
the Screen you'll see that it is right smack in the middle so let's draw this uh let's go here and let's say win. blit no it's not going to be actually okay you guys are going to be confused by this but we're going to draw this another way so we're going to say p game do draw do wct so we're taking a w tangle and what I'm going to do is I'm going to say we're drawing this on the window so the arguments for this specific py game function is the window Or the surface that
you're drawing this onto in this case just our main window then we need to pass a color that this rectangle is going to be so I actually want this to be black so what I'm going to do is to find another color here I'm going to say black is equal to 0 0 0 because well that's the color code for Black it's just none of red green or blue so anyways we Define black so now we're saying we're drawing on the window it's color black what are we drawing Well we're drawing a rectangle so I
just pass in my rectangle which is border like that because border is equal to a p game rectangle so that's all we have to do so let's go ahead and try this and to press run and now we get a nice black border right perfectly in the center of the screen now of course I can still go over it notice that we're drawing actually below the Border um are we on top of it no we're on top of the Border okay that's fine it doesn't really Matter if we're on top of the Border or not
but now we need to make it so we can't actually cross this border so really all we have to do to make it so that we can't go off the screen is not let our Player move if they're going to move off of the screen so we just check if pressing this key would move them off the screen and if it will then we'll just not let them press it so inside of my yellow and red handle movement it's kind of annoying I should have done this Before so we could have just copied it in
we're just going to make sure that we're we can't move off the screen or into the border so for yellow on the left hand side of the screen um yes on the left hand side of the screen what we're going to say is and just in this if statement right here and we're going to check if by moving to the left we would have a position that is in the negatives so that is not equal to at least Z that would tell us that we're Off the screen because the 0 of our image would be
well not on the screen so I'm just going to say and yellow oops did I mean to press that yellow dox minus velocity is greater than zero so what this will tell us is if when subtracting the velocity from our current y position that will be greater than zero or not if it is we won't let ourselves move any further to the left so that the reason doing minus is because we're obviously going to Subtract two move to the left now we'll do the exact same well actually we're going to do a different thing for
the right um we're going to say and yellow and yellow dox plus velocity the reason it's plus is because now we're moving to the right now in this case we don't want to check if it's greater than something we want to check if it's less than something now what do I want to check if it's less than well I want to check if it's less than the Border in The middle of the screen because if we look at the screen right this is on the left hand side we don't want to be able to move
move past that border which is in the middle of the screen so we'll get the Border's X position and we'll put that here so we'll say border dox so this will not let us move past The Border's X position but the issue with this is you have to remember that we're drawing the image from the top left so technically the width of the image can Still move over the Border because the 0 position wouldn't be past that X now hopefully that makes sense but to show this to you again we go back to trusty paint
we have our border in the middle of the screen let's say this is our rocket ship like this technically this 0 0 is less than this borders X but its width is over top of it so what we need to do is check the width of the uh the image as well and make sure that the 0 0 plus the width of the image isn't going To be over top of that border so a lot of explaining here but all we have to do for that is simply say yellow uhx plus Vel plus yellow do
WID like that and again this another property of the rect we can call it width and that will make sure that we're not over the Border okay now we'll do the same thing for up and down so for up it's really easy we're going to say yellow doy minus the velocity is greater than zero and we'll do the exact same thing here except Instead of the width and the X's we're just going to check the heights so we're going to say yellow doy yeah plus velocity uh plus yellow not width but do height is less
then and actually in this case it's not going to be border doy this is simply going to be height because it gives us the height of the screen so this is making sure that the height and our image cannot move further down past the screen now let's just test this then I'll do the same Thing with red so run and now notice that I I can't move any further down the screen okay I can't move left off the screen I can't move right off the screen and in fact this is blocking quite a bit and
same thing here now there's a slight problem going down I'm not sure exactly what that is all right so I just paused for a second because for some reason my yellow guy can move further down the screen I'm not actually really sure why that is so a simple fix for this I don't Usually recommend this but since it's not that important based on the game we're making I'm just going to add um a few pixels to this right here so I'm pretty much going to say and yellow doy plus velocity plus yellow. height is less
than and then height minus 5 now what this should do ideally is just make it so that we can't move as far down so let's just rerun this and actually sorry this is already running so let's close that and run again okay now uh we can Move okay so five clearly wasn't enough we can't move as far down now but let's just make this 10 so let's go height minus 10 now let's run the game and same thing right okay so let's make this a bit more let's make this 15 pixels let's run let's see
it and there we go now we're like perfectly at the bottom of the screen okay so that's what I wanted now you might be wondering why on the other edges we're not like touching them immediately that's because the actual Size of this image is a bit bigger than what's showing up on the screen um that's sometimes a problem like if you take an image and it's like really small compared to the actual dimensions of the image then the rectangle around that image is going to be bigger than what the actual image is so that's pretty
much why we can't cross this border here because this image actually kind of extends further out you just can't see it because it's a transparent background Anyways hopefully that makes sense let's do the same thing for red now and then let's get into firing bullets and some more fun stuff okay so close that oh I launched this game like 12 times okay great okay close it all right so now we're just going to copy this uh and do the same thing for red so instead of yellow just change this red we can literally copy everything
and just change all the yellows to Red so and red oops not like that and red dox And red copy this one here this one will be red and same for this okay and red and red all right so now we have that let's just test this last time make sure all is good come on run what's happening invalid syntax where did I make a mistake let's see it is saying I can't even see because my window is not big enough at Red dox ah I forgot the an sign on all of these great let's
add the and sign back or the and word I guess okay run now and there we go there so now yellow's good Red's good ah but red see so red can move across the border now the reason red can move across the border is because I forgot that we need to limit how far it can move to the left not to the right so let's go to Red and actually we do need to change some of these things so for moving to the left Rather than checking if it's greater than zero we want to check
if it's greater than the Border dot uh X plus the Border do width okay so we're going to have that there then for moving right this isn't going to be reliant on the border this is going to be reliant on the edge of the screen which is simply going to be the width of the screen so hopefully that's clear why we're doing this but now we're making sure that we can't move further left than the border And going to the right this is different than yellow obviously we can move as far right as we want
so long as we don't go off the screen so let's run this now and let's try red and there we go we can't move to the back of the screen and the Border yeah we can't move past the Border or either down is good up is good awesome we are looking good all right so now what I want to do since we've just finished that is I actually want to start talking about bullets so how we Can uh actually have projectiles firing around the screen now this is a little bit more difficult than what we
just did but of course it's important to cover in this tutorial so to handle bullets what we need to do now is have a separate key that each character each person can press that will fire a bullet or a projectile from their character so to do this we need to maintain a list of all of the bullets so the first thing I'm going to say is bullets is equal to an Empty list like that we also need to decide how fast we want these bullets to go so I'm going to make a variable here I'm
going to call this bullet undor velocity and we can either decide to make this slower than the characters or faster than the characters but since I want this to be faster and make it a bit harder we're going to make it seven uh again feel free to play with these numbers so we're going to say bullet Val equals 7 so now what we need to do is Make a way for us to actually create a bullet and have it kind of fired around the screen so I'm going to show you now how we can handle
the presses of the left and right control so usually I would use something like the space key to fire a bullet but since we have multiple people playing on the same keyboard we can't use space because only one person can press that so I think it makes sense to use the left control and the right control to press to fire the Bullets this way you don't get sticky keys when you're pressing the shift key which is what I would have done previously and obviously we don't want to use enter and caps lock because well caps
lock is not an intuitive key uh to fire a bullet so we'll go with right and left control now we're going to do that but the thing is I want each player to have a limited number of bullets so I don't want them to Able just Spam bullets as many as they want or fire Them like rapid fire on the screen so that also means that I don't want uh players to be able to hold down the key to shoot bullets I want them to have to press the key each time so they have like
a very methodical shot right not like saying Call of Duty where you're just holding down the trigger the entire time I want them to have that actually press it each time so let's do that the way we're going to do that is by not handling the key presses this way we're Going to handle it this other method there's not really names for them so it's hard for me to describe them uh that I talked about at the beginning of the video so what we're going to do is say if event. type equals equals py game.
key down like that now this is telling us hey we pressed a key downwards then what we're going to do is fire a bullet so we need to check whether we press the left control or the right control so if Event and then oops like that do key is equal to pame Dot and then this is going to be kcore left I think it's lctl yeah lctl is left control and then otherwise we'll say if event. key is equal to py game. Korr Ctrl standing for right control then we will um kind of create a
bullet for our character so the idea here is I want to have a a list of bullets this list is going to store all of the red players bullets and all of the yellows Players bullets right in fact to make this easier let's actually just do two lists let's say redcore bullets equals that and let's say yellow underscore bullets equals that so what we'll do is we'll have the red bullets list store all of the red players bullets yellows will store all of the yellow players bullets and then we'll move these bullets around the screen
uh and kind of add them to the list so to create a bullet we'll just add one to the list And then we'll draw these bullets at their X and Y position position and will automatically move them so that they're going kind of in the direction that they were fired so the first thing is to create the bullet obviously so to do this uh for left control we want our bullet to be going to the right so let's do that so we're going to say uh I guess who is on the left I always forget
I think it's yellow yeah yellow's on the left we're going to say yellow uncore Bullets do append and just to make this easier to read I'm going to say bullet and the bullet is just going to be equal to a p game rectangle I don't have any an images for this one so we're just going to say py game. rect like that we're just going to create a rectangle that is at the position that we want to fire it from so if we think about this where should we place the bullet well the bullet really
should be placed at wherever the yellow character is right We want the bullet to come from their body so since the yellow character is facing to the right the bullet should kind of Spawn or appear at the edge of their body So at their Exposition plus their width that way immediately when you press the fire button you you see the bullet kind of coming out of the character so to do this uh we're going to say that the X position of our bullet and we're just going to make it a rectangle again is Going to
be at yellow dox plus yellow. width like that now if we think that this is too far away from the character because remember the width of the image is a little bit further than the actual um character itself we could subtract a few pixels and it would be like more inside doesn't really matter but anyways we'll just say bullet equals P game. wct yellow. X Plus yellow. width now for the height we can say this is going to be yellow uh Doy now this is going to be weird but we're going to say yellow do
height over two so we're taking uh the yellow doy position which is the top leftand corner of the image and then we're adding the height of it over two the reason for this is that so that it comes directly in the middle of the character because if we did it from yellowy it would come from the top left of the character which we don't want we want this to come from the middle of the image so we simply add Half of the height to put it in the image uh to put it in the middle
and really if we want to be even more precise we should then subtract or we should then add depending on actually it's going to be subtract in this situation half of the height of the bullet so the height of the bullet I think is going to be five pixels so I'm just going to subtract two uh because I don't want this to be decimal number but anyways you guys will see I apologize This is a lot to take in at once but I just want to make sure this is perfect so yellow dox plus yellow.
width to put that uh in the middle X position or sorry to put that on the edge of the image then yellow. y plus yellow. height over 2 minus 2 this is so the Bullet comes directly from the middle of the character then the width of the bullet is going to be 10 pixels and the height is going to be five so that is our bullet and then all we're going to do is Append this into the yellow bullets list perfect so let's copy this and let's do the exact same thing except for red uh
for our right control button press so now instead of having yellow dox this is just going to be red we'll literally copy the same thing except we need to remove this plus Red Dot width the reason for this is the red character is facing to I guess the left of the screen I know my hand positions are probably wrong but it's facing to the left so It's bullet are going to move towards 0 0 which means we want the bullet to come out of actually the left side of the character not the right side of
the character I would run this but there'll be a crash right now if I do that so let's actually um I'm just going to try to go through this the character is facing to the left so we want to start drawing the bullet at its actual left Edge which really is its just X position so instead of adding the width to it Like we did with yellow we're just going to put red dox now the height will be the same thing because we do want it to to be in the middle for the height so
red doy and then red. height and then literally everything else is the exact same it's just the edge in which this bullet is appearing we want to be different okay perfect now last thing and there's actually more before I can show you these bullets firing we want to make sure that each player has a finite Number of bullets so to do this we need to Define another variable and we're just going to call this numor bullets like that or actually to make it more clear we'll say maxcore bullets and we'll set this equal to whatever
we want I like three you guys can change that but I like three bullets so now before we actually go ahead and check if we can do the left control or we can do the right control we want to make sure that we don't Already have three bullets fired on the screen because if we do we need to wait until those bullets disappear go off the screen whatever uh before we can fire another one so I'm going to say and the Len of right what am I saying right red no this is yellow yellow uncore
bullets is less than maxcore bullets so if the amount of yellow bullets that we have which is defined by the length or the number of bullets in this list is less than our maximum bullets we can go ahead And fire another one otherwise no don't add another bullet to the list because we already have the maximum on the screen now same thing here and the Len of redcore bullets is less than Max bullets perfect now this will allow us to actually uh fire bullets on the screen now because it's going to take a second before
we actually see these I'm just going to print out redcore bullets uh and then yellow uncore bullets so this Way when I start pressing the right and left control key in my console down here uh where all this gibberish is appearing uh you will see it popping up the bullets list so let's do this you can see that it's empty now when I press control boom there you go we have a a button or a uh bullet inside of the list I press control again I press the other control and you can see that there
we go going ahead and adding to the list now I realized uh as I did that and good job We did that here instead of having yellow bullets this needs to be red bullets do aend uh because obviously that well that just wasn't working with yellow it was adding all of them to the yellow list which we didn't want so hopefully that's clear but that's how we have the bullets now they're in the list when I press left and right control boom they're getting added and well it will work the maximum it just wasn't working
before because we had a bug this was Yellow instead of red okay perfect now we have that now we need to move the bullets and we need to see if they hit any of the characters so what I'm going to do is I'm make another function that can handle this for us uh because it makes sense to kind of separate everything out so what I'm going to do is I'm going to make another function down here I'm just going to start typing it out then I'll Define it above and I'm going to say this one
is handle bullets Like that now we're going to pass the yellow bullets the red bullets and the yellow character oops or the yellow wrecked as well as the red uh yeah I guess as red as well the reason for this being that we want to check if any of these bullets collide with either of the characters because if we do well we'll need to do something about that right and same thing we need all the bullets so that we can handle moving them around the screen and drawing them and all that All right so now
let's code out this handle bullets function so let's go here it doesn't really matter where we put it and let's say Define handle _ bullets let's have this take the yellow bullets the red bullets the yellow character and the red character okay so what this function is going to do is move the bullets handle the Collision of the bullets and handle removing bullets when they get off of the screen or collide with a character So what we'll do is we'll Loop through all the yellow bullets check if they've collided with the end of the screen
or with the red character then we'll Loop through all the red bullets and do the same thing except for the other character so let's do this I'm going to say four bullets in yellow uncore bullets like that then I'm going to start by moving the bullet so since it's a yellow bullet it's coming from the left which means we need To move it to the right because it's coming from the character on the left so we're going to say bullet dox plus equals the bullet velocity to move it to the right so we move it
and then after we move it we're going to check for Collision so we're going to say if yellow now there's this fancy thing in python or in Python in P game called Collide wct and we can pretty much check if the rectangle representing our yellow character has collided with the Rectangle representing our bullet so this pretty easy all we do is just pass bullet right here and what this does is tell us that hey yellow did collide with the bullet or the Bullet did collide with our yellow rectangle or it didn't so this is true
or false uh but this is really easy way to to check for Collision use Collide wct keep in mind this only works if both objects are rectangles which they are and that's why I used the rectangles okay so now that We have that we're going to do something kind of fancy if we collide with the yellow character the first thing that we need to do is remove this bullet so we can just say yellow bullets. remove and we can remove the bullet that's fine we're going to delete the bullet because it's gone it collided but
we need to tell our main game Loop down here somehow that uh collided with the red character right we need something to pop up we need to remove Health whatever it is we need to do something but I can't directly modify anything in my main game loop from this function right other than the stuff that was passed to it so what I'm going to do is I'm going to post an event now in P game there's are these things called events right just like event. quit just like event. keydown right whatever uh we're checking the
types equal to P game. keydown py game. quit so I'm going to post an event create a new event and Then we can check for that event inside of here and do something if that event occurs now this event is going to be red collided or you know bullet hit red or red hit or whatever we want to call it we'll do the same thing for yellow but we're going to post an event that we will then check for in this wallo so to do this we need to First create this event so I'm actually
going to go up to the top of my program here uh we'll do like kind of a new section and we going To say in all capitals yellow uncore hit and then we'll say redor hit like that and this is going to be equal to something that's kind of weird but py game. user event + one and for this one py game. user event plus two this just represents the code or the number for a custom user event since we're going to have multiple user events we can add one to this one and add two
to this one so now we have two separate user events That we can check for and handle I know this is strange but this is how you create a new event you say pame do user event plus uh some number obviously going up in sequence so plus 1 plus 2 plus 3 plus 4 if these were both plus one they would be the same event because they would have the same underlying number representing them this right here uh to my understanding is really just a number like it's you know 450 it's some number we don't
know what it is we just Add one to it to make sure we have a unique event ID that's pretty much what we're doing so yellow hit and red hit those are my two events so we're going to go to down here uh we're going to go into here sorry and up here we're going to say py game uh like this. event. poost and we're going to post a py game. event uh I think it's do event. event like that and inside of Here we're going to pass the event that we want now actually sorry
this should have been red not yellow uh so red. cidere because we're checking if the yellow bullets hitting the red character so you guys probably saw that but that should be red and the event we're going to pass is or post is redcore hit so this is telling us or we're making a new event that's saying that the red player was hit now we'll literally copy all of this and do the exact same thing for not Our yellow bullets but for our red bullets so we'll say red like that we'll change red to yellow and
then instead of yellow bullets this is going to be red bullets instead of red hit this is going to be yellow hit now this is the exact same thing except now we're checking the red bullets but we need to move the red bullets in the other direction because we're we're firing from the right of the screen moving to the left closer to 0 0 so we subtract the bullet velocity so This handles our yellow bullets this handles our red bullets and that should be it for moving the bullets so let's actually try this out uh
and let's see how many mistakes that I've made assuming we made any so refresh we have our two uh ships now I'm going to press control and ah we got an issue uh deprecate and integer is required but got type float I'll be right back just going to have a look at what the issue is here all right so I found the eror Pretty silly one I should have came up with this uh pretty much we cannot have floating points when we create a a new P game rectangle so for both of our bullets we
need to actually put two slashes here for integer division it's fine this is going to round anyways it'll be okay uh but we just need to do integer division so red. height integer divided two yellow. height integer divided two uh so that way we don't get any floating Point issues now same thing Here with this border so we're going to go to our border and we have width over two we're just going to change this to over over two uh so that way again we don't have that floating Point issue that we were running into
before but this was indeed working uh with despite of those two issues so just fix those division signs to be two division signs so SL slash but I realized that we're not drawing any of these bullets so let's draw these bullets onto the screen Because it's going to be hard for me to show you that it's working without drawing them so inside of our draw window now I want to take uh actually let's just take a list of bullets so what we'll do is we'll combine the you know what I can't do that because it's
going to be drawing the wrong color let's take redcore bullets and let's take yellow underscore bullets doesn't matter what order we take them in and let's draw these bullets onto the screen So after I draw everything else we'll draw our bullets so we're going to say four bullets in redcore bullets then what we'll do is we'll say pame do draw. rectangle we'll draw these onto the window these are going to be red so this is an opportunity to create another color called red uh so let's go here we're going to say red is equal to
255 0 0 because red well is all red and nothing else we also need yellow so let's go ahead and do that now can I Remember my primary colors uh I'm just going to look so I don't mess this up I mean I believe this is red and green uh creates yellow I think that's correct so let's go here with yellow so 255 255 Z okay and now we have red and yellow so we can draw p g. draw. window color red and what are we drawing well we're going to draw the bullet which is
really just a rectangle copy this do the same thing and the only thing we need to change is the color so this is going to be yellow And this is going to be yellow there we go so we have our two colors defined we're now going to draw all the red bullets and all the yellow bullets on the screen so we just Loop through them and just draw all of them out okay so let's refresh or let's run this uh and draw a window missing two required additional arguments Red Bullet and yellow bullets that would
make sense because I forgot to pass them so let's go down to our main uh function here see Where we have draw window we're going to pass the red bullets so lowercase red bullets and lowercase yellow bullets awesome quickly just so you guys can see everything I'm going to zoom out uh give you an idea this is what the main function looks like in case you guys are on a larger display and you want to see all of it this is what the other functions look like just going to kind of scroll through so you
guys can have a look here and pause the video if you Need a specific part or if I'm going too fast for you okay so let's Zoom back in let's run and let's see if this is working now so I'm here on my left guy I press control boom We fire a yellow bullet kind of hard to see on the white background but also notice let's let's go with the right one cuz you will to see the red that this bullet when it hits my player it's disappearing that's awesome this is working and boom we're
good to go so now what we need to do and Also notice if you try to hit uh control a bunch of times it only lets you shoot at most three bullets at a time right which is exactly what we wanted if I go up here now I can't shoot any bullets until these go off the screen uh and in fact I forgot to handle the fact that the bullets go off the screen we need to remove them so let's do that next awesome so much stuff I always forget how much stuff we actually need
to do so now after we check this Collide Rectangle we're going to check if any of these bullets are off the screen so to do this with the uh yellow bullets all we have to say is if bullet dox and this one is going to the right is greater than uh and we're not going to bother with the width of the bullet or anything it's fine we'll just make it disappear when it gets to the edge we'll say bullet dox is greater than the width of the screen than yellow bullets. remove bullet but we'll just
do An else here to make sure that we don't uh so this will be L if so that we don't potentially remove the bullet twice anyway so we'll do that now we'll add an L if here we'll say l if bullet dox is less than zero because that would be when it's off the screen if we're subtracting the velocity then same thing here red bullets do remove bullet so that should be good just checking if it's going off the Screen in either direction okay so let's try this now um when I press control a bunch
of times boom I should be able to press it again awesome they're getting removed all is good all right so before we do anything else uh let's actually just change the background because my eyes are hurting with that yellow on white so we'll change it to that nice space background that I showed you at the beginning so to do this we need to load in our space background if we go to Our assets folder we can see we have space.png so we're just going to say space is equal to pame do image. load and then
we are going to load in um os. path. jooy so os. path. jooy with the assets folder like that and then we want to load in space.png now that is that's fine we can do that but I'm also going to rescale this image because it's really big to be A lot smaller just so it looks nicer so to do that we'll say py game. transform do scale and then we'll wrap this image around and inside of this we'll put the dimensions now we have perfect dimensions for this we can just make it the width and
the height height uh of our window now this might make it a little bit kind of stretched we'll have a look at how it how it looks but I'm just going to make this with height So we're resizing it to that so now rather than filling the screen with white every single iteration and actually let me show you what happens when I don't do that because that's interesting so before I draw the background let show you what happens when we don't fill the screen with white look you can see this I'm just moving around all
over the place the reason this is happening is because P game does not remove the last drawing that we made Right it just keeps drawing stuff onto the canvas so if I don't draw a white background every single frame or I don't draw something that covers the entire screen then you get all this kind of movement stuff because it's not erasing anything that it previously Drew so anyways I just thought that was interesting so let's now put that image onto the screen we're going to say win in all capitals do blit we're going to blit
space and then we're going to put It at 0000 because this is the background so we can just start at the top left and fill the entire screen cuz we already know it's width and height is that so let's go ahead and run and there we go we get a nice space background actually doesn't look bad at all in fact this looks pretty nice so I'm going to leave it like that awesome then we can go there you go yellow looks a lot nicer on that background awesome so now let's Handle those events so when
we actually get hit we need to do something we need to have some health or something like that then we're going to add sound effects we got a bunch of stuff uh actually not that much but a few more things to do so now inside of my main event Loop remember just a quick refresher we're posting these events right yellow hit and red hit so when we post these events they just get added to this uh py game. event. get CU that's Kind of appearing with all of the events so all we have to do
is just inside this for Loop check for these events so if event. type equals equals redcore hit then we'll do something and if event. type equals equals yellow uncore hit like that then we'll do something else so this is a perfect time to implement a notion of Health so we want to have both characters have some number of health and every time they get hit that's obviously going to subtract so to do That pretty straightforward but we're just going to make two variables here we're going to say redcore health is equal to 10 and yellow
underscore health is also equal to 10 whenever a player has zero Health again feel free to change these numbers then we'll say that the opposite player has one so that'll be kind of the objective or or how you win or lose or game so if red is hit what's the obvious thing to do subtract red health so red Health minus equal 1 If yellow is hit then we'll say yellow underscore Health minus equal 1 then what we want to do is now check actually we don't need to do it inside of this for Loop but
we can do it outside of this wall Loop if either player has uh Health that is equal to zero and if they do the opposite player will win the way I'm going to do this is interesting but I'm going to say if uh let's say if redcore health is less than or equal to zero and then I'll say if yellow uncore Health is less than or equal to zero I'm actually going to Define this variable I'm going to say winner uncore text equals and I'm going to say yellow wins like that now on the other
side I'm going to say winner text is equal to Red wins this is the text that I want to appear on the screen when either of these situations happen we'll get into this in a second but I just want to start defining it now above here I'm going to say winner text equals a Blank string and I'm going to check in one more if statement if wintercore text does not equal blank then inside here someone one so the basic logic behind this we have this variable called winner text it's equal to nothing if either the
red player or the yellow player has lost so they have zero Health then we will set the winner text to be something other than empty string in the situation where winner text after we check both of this is not equal to an Empty string someone one we should display that winner so we will get to that in a second but now what we want to do is show both of these scores on the screen and then once we've done that we just have to add sound effects handle someone winning and we're pretty much done we're
getting very close so let's do this uh let's start showing the score to show the score that means I need to pass the score to my draw window and I need to somehow draw that score in the Window so I'm just going to pass the uh I guess it makes sense to pass red first so we'll pass red health and yellow Health like that to my draw window now let's go to draw window let's now take inside of draw window the redcore health and the yellow underscore Health like that and now inside of here what
we'll do is we'll actually draw these their score or their health on the screen now to do this this involves using fonts we have to actually Render some text on the screen so this is where we get into our next step so what we're going to do at the very top of our program is we're going to say py game. font. anit now I just took a quick pause there because as you guys can see I spilt water on myself so that's great but we'll continue that's fine I Will Survive anyways you're going to put
P game. font. anit at the top of your program and this is going to initialize the pame font library or whatever it may Be then what we need to do is Define a font that we are going to use so it's getting kind of messy up here I'm just going to do another kind of little section and I'm going to say that the healthcore font is going to be equal to py game. font. sys font with these specific capitals we're going to define the name of the font which I'm just going to use comic Sands
and then the size in this case I'm going to pick 40 so what I'm doing here is I'm just Defining the font that I want to use comic Sands size 40 we're all good we can continue all right so now that we have the font defined we need to use it so we're going to go inside of draw window I'm going to show you how we can actually put uh font onto the screen uh now draw this wherever you want just obviously after the background's drawn I'm just going to draw it after the spaceships meaning
that uh it will overlap our spaceships actually you know What maybe that's not the best idea maybe we want our spaceships to go over top of this font uh if that situation occurs which it could so let's start by doing this let's say red healthcore text and this is going to be equal to P game uh or not pame we're going to say score not score healthcore font finally got it right third try do render now we just Define this font right we're going to use this font to render some text now the text that
I Want to render is the following I want to render Health colon and then space plus the string of red health so we'll take whatever that number is convert it to a string and concatenate it with health then we need to say one for anti-aliasing I'm not really going to talk about that is but you just always put one as the middle argument for our purposes and the color of this text which is going to be white so red Health Text is Health font. render it's equal to Health Plus whatever the health is and then
one white same thing now for the uh not red text but for the yellow text so we say yellow Health text now what we've done is we've created kind of two text objects and we want to draw these on the screen so to draw them on the screen we're going to say win blit we're going to pick uh I guess we already know the window we're going to pick what we're blitting which in this Case is red Health text and we need to pick where red is on the right side of the screen so that
means I want to blit it at an X position that is like right at the edge of the screen I'm going to do this dynamically uh you can hardcode a number if you want but the correct way to do this or the way that will look the best is with um minus and then redcore Health text do getor width this will get the width of that text and subtract that From the width of the screen so the top left position where we're blitting this will be like right at the edge and then I'm also just
going to subtract 10 pixels just so this has like a 10 pixel pad from the very edge of the screen where do I want to blit it on the Y I'll blit it at 10 uh because it's going to be right at the top of the screen we'll just make it 10 pixels down by having this -10 and this 10 we're padding it so it's 10 from the right wall and 10 from The top wall now we'll do the same thing or a very similar thing for uh for our yellow text so wind. blit we're
going to say yellow Health text and then where do we want it we're actually just going to put it at 1010 reason we can do this is because we don't really care about the width of it because it's going to be the left border that we want padded from the left wall and then 10 pixels down as well from the top so that's what blitting it at 1010 will do anyways um This will give us the red Health text the yellow Health text it'll be showing up on the screen so let's try this actually uh
we handled the events we're passing in the health yeah we're like very close to done so let's run this and now you can see the health is showing up so we have it in the corner boom move that like that and then notice that the health gets updated but for some reason the health is changing for both of them so I think I just have a small bug so Let's have a quick look here uh we have that red health so yellow Health minus one red Health minus one red hit yellow hit okay uh we're
passing red Health we're passing yellow Health okay for some reason they're both getting updated so I guess that means that this event must be triggering uh for both of them so let's try to see why that's happening so I'm just scrolling around wondering why this isn't working and I'm realizing that well red health is in both Positions here so this needs to change to Yellow Health uh because I had red health so obviously it was drawing the same thing so anyways let's try this now run and now if I hit someone only the health updates
on one side which is what we're looking for so we're very close to done we just need to handle the situation where someone wins and add sound effects so let's do someone winning first uh this is actually really straightforward I'm just Going to make a function what this function is going to do is just draw a text on the screen that says blank person one and you'll see how this works I'm going to say Define draw winner we're going to take in some text that we want to draw and then we're going to make a
new font so let's go to the top let's go with our other font let's say winner font is equal to pame like that do font. Sy font this should be comic Sands Well you can make whatever you want and then I'm going to make this size 100 we'll make it nice and large so now we'll use the winner font to actually render uh the text so we'll say winner font. render we'll render the text anti eling one color white and then we'll draw this onto the screen so we'll say win. blit we'll blit the winner
font and we're going to do this nice and fancy and have it perfectly Center in the middle of the screen so I'm going to go Inside of here I'm going to say width over two now we'll actually uh double divide it by two uh I did I do that somewhere else I'm not sure just to make sure we don't get any errors although width over two is an even number so I think that's fine if we do that we'll say width over two minus because width over two again is the direct middle of the screen
minus the I need to I've made a mistake here okay let's let's go Text draw uncore text equals that we need a variable draw uncore text equals that I don't know why I thought bleding winner font was going to work but draw text is equal to winner font. render that's better so now we'll say width over two minus draw text doget uncore width this will get the width of the text so how wide it actually will appear on on the screen over two this will put it directly in the middle of the screen because it
will take whatever half the Width of this is and subtract it from the X position so that way when we draw this it will be perfectly in the middle of the screen I kind of went over this before we'll do the exact same thing for height so we'll say height over two uh and then minus draw text. getor height over two again get height is just going to give you the height um might be smart to do integer division here but I think this will be fine then we're going to say py Game. time. delay
and we're going to delay this for 5,000 milliseconds which is 5 Seconds you'll see why but what this will do and sorry we also want to update the display so before we start delaying we're going to say py game. display. update so what this is doing is we're going to call this function when someone wins so for 5 seconds we are going to show the uh the winning text and then we're going to restart the game so the reason I'm doing this and I'm not Doing it inside of draw window is because I want to
just pause the game whenever someone wins show this text and then just restart it immediately after that's why I have this pause if you want to change the pause to be longer or shorter uh just a thousand multiplied by whatever seconds you want to pause it for and that's how you pick the delay okay so now inside of winner text here we're going to say draw underscore no not window draw uncore winner and we're Just going to pass it the winner text because what this will do is then give it the winner text it will
draw it on the screen we'll pause for 5 seconds it will appear and then we will break now when we break this will bring us to py game. quit which would usually quit the game now we can do that for now so let's actually just do that and then I'll change it so it just restarts the game so here let's just Spam control a bunch of Times and uh make it so that we actually win so there you go boom we hit it it says yellow wins appears on the screen wait it's going to close
the game in a second and boom go ahead or the game goes goes ahead and closes now if we don't want the game to quit what we need to do is make it so that we don't quit the game here but we just restart it how do we restart it how we started it originally just by calling this main function since we Define any game Specific variables in here when I just recall the main function it will redefine these variables and the game will just restart so instead of having py game. quit I'll just say
main like that but that means that what I need to do now when we actually do quit the game is say run equals false as well as py game. quit right inside of here so hopefully that's clear but this means now whenever we press the X it will actually close because if I removed py Game. quit from here and I didn't quit then we would just stop the while loop but we would restart the game whenever you press the x button which obviously isn't what we want so we have that now we can do one
last test then we're adding sound effects and we're done so let's do this uh let's just test this out and let's keep going boom yellow wins give it a few seconds and it should just restart the game okay there we go restarts the game We get put back in our original positions we have 10 Health we can fire our bullets and we're all good awesome so let's now add the sound effects which are super simple and then we will be done so the first thing that I need to do is load my sound effects uh
actually sorry second thing I need to do is load my sound effects first thing I need to do is initialize kind of the sound effect library in Python so I'm going to go to the top here and going say pame do Mixer. AIT and this just starts kind of like the sound aspect of of P game so that it will work anyways now that we have that we're going to load in a mixer sound which will allow us to start and stop a sound whenever we want so the first thing I'm going to do is
I'm going to make a variable I'm going to call this bullet uncore hitor sound and this will be when we actually hit something that'll be the sound and then we'll say Bullet underscore fire like that underscore sound and now let's load these in so we're going to say pame dot and then in this case we're going to say mixer. load and we're going to load from os. path. jooy the start of the PA path is assets and the end is simply the name of what we want so the gun silencer funny enough these are the
sounds I've used right the gun silencer is the one for when someone collides and the or sorry the gun silencer is for when Someone shoots and the grenade is for when it collides so I'm just going to say grenade + 1 do MP3 and then we'll just copy this line do the same thing but change grenade plus one to be gun plus silencer uh did I spell silencer right yeah uh MP3 so now we have both these sounds and if we want to use them it is really easy to do this all we have to
do is go down and I'm just going to make it so that whenever we fire a bullet so whenever This happens uh we actually make put that sound right so now I'm just going to say bullet fire sound. playay all right is it do start or is it doplay I think it might be dot start uh let me look at my other code here uh so actually no it's I've been lied to it is playay okay so we're going to play the sound like that so bullet fire sound. playay and the same thing here so
whenever we fire the bullets we'll play the sound and then Whenever we get hit so whenever we lose Health we'll play the Collision sound so we'll say bullet uncore hit sound. playay copy that and paste that there so that's it that that adds a sound effects this should be our game so let's run and pig game. mixer has no attribute load okay so let me see what this is actually called um I thought it was called load but I guess it's called something else ah so I've made a mistake this is actually not supposed to
be load Where is load uh this is supposed to be sound with a capital S so just change that there this happens all the time I just forget the syntax py game. mixer. sound uh and then this should work so let's run this now with the proper syntax let's run and bullet sound uh unable to open file assets uh grenade + one. MP3 now it looks like I do have grenade Plus 1.mp3 for some reason that's not working uh I'm just going to go ahead and I Don't usually recommend doing this but since I don't
know the mistake I'm going to try assets SL grenade one and then we'll just do the same thing here so we'll remove the os. path. joyan I don't think we actually need it for this specific sound or for the way that we're loading these and then we'll just do that so we'll just kind of you know make the path ourself assets SL grenade plus1 and so on so let's try this now see if all is good unable to open file okay so Give me one second I will be right back okay so it turns out
that there's actually a Corruption of these MP3 files of course that's going to happen to me at the very end of the tutorial uh but I promise you that the code I just wrote and I'll zoom out so you guys can can kind of see all of it and I'll just slowly scroll through as I conclude here uh the code that I just wrote so the way I loaded that that's totally fine like even the os. path. jooy that should work And then to play the sound all you do is do playay so just trust
me that this does work for you guys uh for some reason when you download the MP3 file you like they're corrupted as well then just find your own sound effects and just load them in so throw them in the assets folder name them something and then load them I think it's just an issue with downloading the files from GitHub you can't download MP3 files uh but do that load them in pick your own Sound effects they should work with playay it's a really minor part of the tutorial so I'm not too worried about it uh
but then you should hear the sound effects when you press those buttons and well it does obviously add a lot to the game now I will quickly mention before I leave off here because this is all we're doing for this tutorial that there's a lot more stuff in P game that you can do the point of this was really just to get you up to speed nice and fast show you How to create a simple game and show you how to do most of the things that you usually want to do you know projectiles moving
characters around handling Collision all that kind of stuff loading images loading sound effects although that didn't really work uh and all that kind of stuff and keep in mind like you know usually you can separate things out into different files this isn't perfect what I did but again just to give you an idea and really get you kind of started In Python and pame hello everybody and welcome back to another P game tutorial now it's been a long time since I've done one of these but you guys know that the foundation of tech with him
my YouTube channel was really built around making all kinds of fun little p games like I've made Tetris snake some platformer games stuff like that which you guys can check out as well if you wanted to see those and I wanted to bring another one back here to all the Old subscribers and just show you guys you know this is another cool Pi game we can make especially with quarantine happening Pi game is just such a great module for making some fun 2D games that don't take you that long to kind of get up and
spinning and of course you know we can use Python for this which is a great and pretty fast language to write code in so the game that we're going to be creating today is a space shooter game now this is inspired or kind of Based off of that old original Atari game where you have those spaceships coming down the screen and you're this big shooter and you're trying to shoot them all of the sky I know that that version is a lot different than what I'm going to show you here but this is the inspiration
now stick with me here for another minute or two I need to give you this introduction so you really have all the tools you need to work through this project uh the first thing I'm going to Say is these videos take me a really long time to make and I really want to make sure that you guys are able to actually create the game so please do me a favor go like the video and make sure you're subscribed to the channel if you're not just show your support and if you guys really want to give
me an extra big thank you and show your appreciation I'd really appreciate if you go subscribe to my new YouTube channel which is called timeout with Tim that's Where I'm going to be posting a weekly podcast where I talk about tech programming uh Finance just myself Life Style stuff like that and I would really appreciate it even if you guys don't want to watch that you just go over and subscribe uh and support me over there so anyways let's demo the game and as I demo the game I'll talk about some other important things for
this tutorial Series so first of all all the assets you see here there will pixel8 assets Are available from the description down below I've made a really easy link on my website so all you have to do is just click it and it will automatically just download a zip folder that has all the game assets and the code as well I get comments all the time with common problems which I'm going to go over at the beginning of this video to hopefully make sure you guys don't run into those but if you're running into problems
just click that link the code will download You can open up that code and you can steal whatever code you need and and reference it and make sure that you know it really was my mistake maybe uh and not yours and that you can see if anything's going wrong but this code that I'm showing here is what we're going to be recreating I already have it written full disclaimer on the left hand side of my screen so if you see me looking over there during this long tutorial that's what I'm doing just Making sure I
haven't messed anything up so the idea behind this game is that you're this ship you know you can shoot bullets um and you want to just make sure that these little ships here don't get to the end of the screen and if they do you lose a life the idea behind what I've created here is this is kind of a basic guideline it's setting up the main functionality and then what you guys can do is add your own features to it and I'll talk About some extensions you can put on so that you guys can
make this game as custom as you want so the idea is to give you the core functionality show you how to do everything and then you guys can add and make it your own game afterwards so with that being said I think that has pretty much been it for this introduction what we're going to do now is actually get into coding and just do a little setup for the project and then obviously start writing some code All right so the first thing we need to do for this project is actually install the module called pame
now pame is this third party module it's what we're going to use to make this space shooter game and you do need to install it now a lot of people have difficulties with this this is probably the most difficult part of the tutorial for someone who doesn't work in Python very often doesn't understand how all this works so what you need to do if you're having troubles With the steps I'm about to show you here is click the card in the top right hand corner or click the link in the description that says how to
install Pi game that's an older video but it goes through exactly how to install Pi game all of the common issues in problems and you should after watching that be able to come back here and follow along with no problem so what we're going to do and just first of all obviously we need python downloaded and installed I'm Using python version 3.7 and the text editor that I'm going to be using is Sublime Text now you can use whatever you want you can use the standard python idle you can see I have that installed on
my computer as well doesn't matter what you write in but just cuz I get asked all the time I'm using subline Text Now obviously download python if you don't have that 3.8 should work um if you're having issues with 3.8 download 3.7 and then what we need to to Do is use pip to install py game now pip stands for package install or python I believe or python yeah I think that's what it is um anyways that comes by default with your python installation so usually what you can do is open up a command prompt
window if you're on Terminal or open up a uh terminal window if you're on Mac or Linux and type pip install P game like that now if you hit enter and you see something like this like Requirement already satisfied or finding module installing module you're good you installed py game you're ready to go that's all you need to do if you see an error that says pip is not a recognized command go watch that video it'll show you how to install pip properly uh now if you're on Linux and if you're on Mac what you
might need to do is type pip 3 pip 3 stands for pip Python version 3 because on those distributions or on those I guess operating systems they Have python 2 built in automatically so when you type pip that actually accesses the python 2 interpreter not the Python 3 interpreter so Tri pip 3 Tri pip uh if this doesn't work again watch that video I have one for mac and for Windows which I'll link in the description and once you get that what we're going to do is just type python in here or open up your
idle wherever you usually do your python stuff just try to import the module pame like that and if it works and you get This welcome message then you're ready to go and we're going to get into the video right now so once we've done that what we're going to do is actually and I'm going to close this now set up a project directory or a folder on our computer where we're going to store all of the stuff for this project so what I've done is I've made a folder I've called it space shooter tutorial and
you can see I've already dragged in the image assets here so what you need to do If you don't have these assets which you won't is go to the description hit the link that says download image assets it will download a zip folder so you'll see I'll put this into a compressed one so that everyone can follow along here uh if we go what does it send to compressed zip folder it'll be in a zip folder like this what you need to do is unzip it take this folder out so extract it and put it
into the directory that we're going to work in it's very important That when we do this the python file we create is in the same directory as the folder that has the assets the assets are the images you can see I have things like this yellow ship which I'll bring up onto my other screen here we have the green ship the red ship uh and all of that okay so just make sure that you do that otherwise that's not going to work okay so once we do that what we're going to do is open up
a python uh window where we can write code so in this case I have subline text but if you want you can open up idle like that uh and idle is perfectly fine to to write code in as well but this is subline text which is just a nicer editor so what I'm going to do in here is make a new file and I'm going to call this main.py now this very very very important do not name this file py game if you name this python file py game or any file in this directory is
named py game you your script will not work I Learned this the hard way when I forgot to tell people that in the previous tutorial and I got 100 comments do not name it pame I know it's a tempting name just do not do that now again what we're going to do to make sure everything's working here is just import pame now fortunately for me uh in subline text I can click Control Plus the b key to run my script so that's what I'm doing here but for you guys if you need to run your
script and you're an idle obviously hit F5 or you can use the terminal window on Mac Linux whatever and do Python 3 or python the name of your file when you're in the correct directory okay so once we import pame what we're going to do is import a few other things so we're going to import OS we're going to import time and we're going to import random so now we're actually ready to start writing some code so let's get into it all right so the first thing we need to do is actually load all of
our image assets Into our script so that we can use them and display them on the screen screen cuz the first thing I'm going to do after we load these images in is actually start setting up the pame window and talking a bit about some basic pame syntax and how all those things work because obviously this is a module which means now we have some different syntax and some different tools we can use that aren't native to the Python language so notice again that This main.py file is in the same folder where this assets folder
is I don't have all these images inside directly with the main.py the main.py is in the same level as assets that's really important and that's a big mistake if you don't have that so make sure you're listening pay attention and do that the first thing we're going to do is load all these images so I'm going to make a comment you don't have to do the comments if you don't want but this is Just to make it a little bit cleaner we're going to load the images what I'm going to do is use all capitals
for my variable names here I'm going to say red spaceship equals in this case pame and not in all capitals py game. image. load and I'll go through this after so don't worry if you're confused os. path. jooy and we're going to do app Assets in here and then in here what we're going to do is what was this file called I need to look at my other Screen pixelcore Shore redor small.png okay so what this is doing this line of code and we're going to do a bunch of these lines of code which I'll
speed through in a second is we're saying from the pame module use the image. load method and then in here we're going to load the image which is located at os. paath joyan this is the name of the folder that our images are in notice that's assets right here on The left hand side of my screen and the name of the file is pixel ship red small.png so if you look inside of here we can see we have pixel ship red small.png this is what it looks like a very basic you know five pixel thing
uh and you can see that that's how we load this if we want to add a folder name to a file name because we're loading from a folder we can use os. path. joyant although note I could completely om this line and some of you might be like well Why aren't you doing this this is just the proper way to do it is to do assets slash and then the name of the file like that that works but we're going to use os. path. jooy to make sure everything's clean so I'm going to copy this
a few times because we're going to need to load all these files in right and they're going to have to have all their file name so we have red spaceship we need green we need blue and we need yellow right so the Yellow is going to be our main player so I'll tab it down and say player ship like that just so we know and all we need to do for these ones up here is change red to the appropriate color so in this case that's going to be green that's going to be blue and
I believe this one is just pixel ship yellow uh it doesn't have that small afterwards so pixel ship yellow we can check that just by looking here yep there we go we got it and just Make sure that you have that PNG extension otherwise obviously that's not going to work so what we're going to do now is we are going to install or not install sorry load in the bullets and the other assets so we need to load in the the background and we need to load in uh the bullets so let's say lasers is
what I'm going to call them and we'll say redor laser equals this case we'll copy this line up here paste it in and Assets in this case I believe it's Something like laser uncore red or something so let's look at this pixel laser red yes okay so pixelcore laser red.png let's copy this a few times and of course just change the colors to they need to be so red green blue and yellow need to make sure that's all capitals let's change the file names now so pixel laser green pixel laser blue and pixel laser yellow
okay so let's spell that Correctly and now let's load in the background image so let's say BG or background I'm just going to call this one BG notice I spelled that comment wrong and BG is going to be equal to in this case py game. image. load os. path. jooin assets and then what is this called background- black.png so let's punch that in background- black.png okay so now assuming we spelled all this correctly we've loaded in all these images to make sure this works we can Run the code if we don't get any errors this
was successful now I'm if any of you have like corrupted images or something like that just try redownloading cuz sometimes that happens where it says it can't open open the file even though it does exist but make sure again that they're in the correct folder they're named the right thing and you're loading them in like this if you want to use your own image assets put them inside the assets folder and then Um you know name them what you need to name them and load them in like this okay so now that we have all
of these loaded in what we're actually going to do is set up our P game window so the first thing we do when we're working in pame is we create a width and height for our screen we set a name for the display and we just run it and make sure that it's working fine so the standard and the reason I've named these all capital by the way is cuz these are going to be Constants they're not changing and the convention in Python is to name constants with a capital what we're going to do to
make our Windows we're going to say win equals P game. display. setor mode and inside here we're going to put a topple with a width and a height now we're going to define the width height up here like this so width height equals in this case we're going to do 750 by 750 feel free to change this if you want um and that's how we're Going to get started so width height equals 750 750 this just means width is 750 height is 750 we're going to say wi which stands for the window is equal to
py game. display. setor mode width height and width height just tells it this is how big our window is going to be once we do that we're going to set the caption or the name of our window so we can do that by saying py game. display. setor caption and inside here we're just going to call this space Shooter and in my version I'm just going to call it tutorial you you guys can call it whatever you want so there we go space shooter tutorial now if we run the script we will see that a
pame window pops up and then just disappears cuz we're not doing anything else so if we've got that successfully things are looking good again feel free to change these numbers I'm on a 4K display so it's going to look a lot smaller on my display than it is on yours if you're on 1080p right 750 x 750 will take up most of your screen if you're on a 1080p display but I'm on 4K so it's going to be you know 1/4 the size uh is that how it works I think so maybe something like that
all right quick water break there and now let's get into the next stuff that we need to do uh which is actually drawing and getting our main Loop kind of set up so whenever we're working in pi game what we need to do is create a Main Loop which is going to be kind of what handles all our events so it's going to be what uh handles Collision it's going to be what calls things to be drawn on the screen it's going to be what allows us to quit the game to move a character stuff
like that so what I usually do is I Define a function I'm going to call this main which stands for main Loop and inside here I'm going to set up a few variables that we're going to need for the game so the first one We're going to need is run run equals true is just going to dictate whether this while loop is going to run or not and then what I'm going to do is create an FPS which stands for frames per second and set that equal to 60 now of course you can change this
to whatever you want the higher this number the faster your game's going to run the slower this number uh or the lower this number the slower your game's going to run now just keep in mind you don't want To make this number too low because if you do then that means that you're only going to be checking for collision and checking for events once every whatever this number is so in this case if we say 50 frames per second what that means is we're going to show 50 frames or sorry 60 frames every second and
that means that we're going to check Collision we're going to check if we're moving the character once uh or 60 times every second so the way that we can set that Up in pame is by making a clock object so we're going to say clock equals pame dot time. clock with a Capital C like that and then inside of here we're going to say clock. tick and make sure this is at the top of your W Loop FPS so we're essentially saying we're going to tick this clock based on this frames per second rate so
60 FPS and what this allows us to do is make sure our game stays consistent on any device that we give it to so if we run this on a really Fast computer or a really slow computer doesn't matter it's going to run at the same speed because we've set that clock speed of 60 FPS now what we typically do inside of here is start drawing stuff on the screen and start checking for events so what we need to do first is check for events and the first thing we actually want to do is check
if the user has quit our window so to do that we're going to say for event in py game. event. get and what this is essentially saying is every Time we run this Loop so once every uh or 60 times every second we're going to Loop through all the events that pame knows and we're going to check if an event has occurred occurred if that event occurs do something right so an example of an event is like pressing a key is pressing the quip button is uh pressing the mouse button something like that you can
look up the events from the pame website if you're trying to do something different but most of what I Show you is pretty much all you'll need so now what I'm going to say is if event. type equals equals Pi game like this if I could Spell correctly do quit with all capitals then what we're going to say is run equals false so what this means this pame do quit is if we press that top right the X in the top right hand corner of our screen uh quit the screen like quit P Game Stop
running so that's why you'll notice I set run equal to false so the next time We get to the top of this Loop we won't Loop anymore because we quit right and that's the idea behind that so we could check for other events in here in fact I'll show you another common type of of event so if event. type equals equals pame do key down what that means is we pressed some key downwards if we did that we'll trigger an event that's what this means now we're not going to use that inside the event Loop
cuz I'm going to show us a different way to move Things around but this is the basic Loop that we need right now so let's actually go ahead and call this function and run it and just make sure that the quit button's working and show you what I mean so you can see that it pops up now our window we have space shooter tutorial and we can click the x button and if we do that it exits the window if you don't have this event here it will not exit the window when you press the
quit button so that's just something to Keep in mind that you need to make sure that you make run equals false and exit out of our infinite Loop that's going to happen here that's running the entire game it's handling Collision movement all of that uh when that starts happening okay so now that we have that we should probably start drawing some things onto the screen and the first thing that comes to mind for me is the background so I'm going to do something that might seem a little bit confusing To you guys try to look
past um you know really the inner workings of how this works uh and just understand that this is possible I'm going to make a function inside of this main function that I'm going to call redraw window now the idea behind this is that when we do things like in games and just in programming in general we typically want to separate things out into their own functions and create small pieces of logic that do things uh quite well they do one or two Thing like just one thing quite well so rather than drawing all the different
things because we're going to have to draw a lot of different things within this while loop we're going to put it in a function that's inside of a function and just call that when we need to use it so just treat this like a regular function but just understand that since it's indented and it's defined inside of this main function we can only call it when we're in this function and that's Totally fine that's all we need to do but this is going to allow us to access all of these variables defined inside of the
function rather than making it its own function and having to pass them all through as parameters which can get quite annoying when we have a lot of things that we want to pass so again yeah the idea is that this is going to draw everything for us on the screen it's going to handle all our drawing anything that needs to be rendered stuff Like that uh so we can just be in its own separate piece so if something goes wrong with drawing we know right away where that is it's in redraw window so the first
thing we need to do is do py game. display. update and in fact what this does is refresh the display so the way P game works is we have a bunch of things called surfaces now these surfaces can be drawn on we can blit things onto them which means like put an image onto them or something like that And the way that it works ideally is we have this one surface and every time that we Loop so we run one of these while Loops so 60 times a second we're going to redraw everything onto the
screen and then refresh it uh so that it has the updated version so the first thing we need to do since we're going to be redrawing everything is draw a background image as our first thing so what that will do is it will cover any stuff that would behind or drawn before And then we draw everything on top of that background image that's going to be shown for the next frame and you'll understand what I mean in a second uh but just bear with me here so what we're actually going to do is do win.
Blitz BG comma 0000 now what this is saying is wi is a Surface right it's this pame surface that we've set up as our main py game window at the top of our screen so a method that's available on this is called blit now what blit does is take One of these images so one of these py game images it can be some other things as well which really have been turned into what's called a surface in pame and draws it to the window at the location that we defined here now an interesting thing with
P game is the way that we actually use a coordinate system so I'm going to bring up my drawing tablet here to show you what I mean I've got some networking stuff on there uh and and show you what I mean by the coordinate System so let's say this is our pame window and just excuse me cuz I am drawing with my mouse uh we know we have an X and A Y right so this is our x axis this is our y axis and typically we think that 0 0 is the bottom left well
that's actually wrong or different in pi game in fact 0 0 is the top left so what that means is that our x coordinates are the same as we would assume if we want to increase X we're going to the right or if we want to go to the right we Increase X so X goes like that but y actually goes down which means that if you set something at position y0 it's at the very top of the screen and if you want it to go downwards you need to increment the Y so let's say
I want to move a character down I need to increase its yvalue that's what I'm getting at here now this is the same for objects so let's say we have a little square and we want to draw it on the screen well the top left hand corner is uh where we're Going to draw this object from so if I say I'm drawing a square at 2525 what that means is that I'm am going to draw this Square starting at the top left position I of 2525 so if the width of our square is say 30
if I can't draw three this pen size is too thick uh let's see if we go let's do 20 that's my rough version of a 20 that's a two uh if the width is 20 and we draw it at 25 that means that this corner here right so this right corner is actually Going to be at quick math 45 right so that's what we need to understand top left hand corner is the coordinate system for p game so just keep that in mind when I'm drawing things so when I say wind up blit background at
0 0 that means take that background image and draw it at 0 0 in the top left hand corner of our screen and since we're going to draw the image starting at the top leftand corner it will fill the entire screen now the only thing is Though we're going to see when we run this uh well actually if if we uh wind up blit if we call this function one second sorry so let's call this function now from inside of uh here so redraw window so just inside this main loop we're going to go clock.
tick immediately call the rraw window in here it just blits the background and updates the display so let's run this notice that the background is not the correct size so what we're going to do is Actually scale this background up you can see it's about 1/4 the size it really needs to be uh so we're going to make it two times bigger just about so that it fills the entire screen so to do that we're going to go up to where we loaded in on background and we're going to use another method so we're going
to say py game. transform. scale and what we're going to do now is put this entire image so this whole line we had before as the first Argument and then as the second argument we're going to put what we want to scale this image to so the dimensions so in this case it's going to be width height where width height is those variables we defined earlier for the width and height of the screen so if we run this now notice that it fills the entire screen because we scaled that image and then we're drawing the
scaled image onto the screen now you can see we get some little pixelated stars and some fun Stuff like that okay so I guess the next thing to do is to actually um deal with drawing a few things else on the screen we'll get into characters and stuff in a second uh but like the score the level we're on things like that so let's do that first uh we're going to say score well actually I guess it's not score we're just going to have level and lives so we'll say level starts on level one uh
and we'll say lives starts on five feel Free to increment that if you want doesn't really matter to me and I'll show you how we can draw those to the window so how can we actually draw text so you saw I had lives and I had uh level the top right and left hand corner of the screen how do we do that well what the first thing we need to do is actually create a font in P game so a font allows us to kind of render that font so for example comic Sands is what
I'm going to use uh we need to create The font object and then use that font object to actually render the text to the screen so the annoying thing in pame is that you need to initialize fonts for them to work so that's pretty easy but at the top of our program right after we import pygame here we're going to say py game. font. net this just tells pame okay get set up get the font ready to go so that there's no issues when we want to start using it so that's what we'll do py
game. font. anit and now inside of Our main here I'm going to Define mainor font so that's a variable name is equal to in this game py game. font. font and here we're going to name the font so there's all kinds I'm not going to go through them but the one that I usually use is Comic Sands and then the size of this font so the size that I'm going to use is 50 uh make it smaller or bigger depending on what you want and now I'm going to show you how We can use this
to actually draw the lives and the level on the screen so here I'm going to make a comment I'm going to say draw uh you know text like that and the first thing we need to do is make a label and then blit that label to the screen so you saw how I blit this surface which is the background to the screen what I need to do is turn some text into a surface and then put it on the screen so I'm going to say okay uh I guess this would be livesore Lael is Equal
to mainor font which we've defined up here which is Comic sand size 50. render and here I'm going to type what I want to render so in this case I want to render an FST string uh if you're not familiar with f strings what this allows you to do is embed variables inside of brackets like this so left brace right right brace like the curly brackets so I can do something like level colon level and what this will do is take take the value of the variable level here and Just show that and so that's
with an F preceding this string now that only works in Python 3.6 and above so just keep that in mind when you're running through this okay so then our next arguments are one and color so one stands for anti-alias you can see that's popping up here uh I'm not going to explain really what that is you're just pretty much always going to use one if you're blitting something or rendering text sorry and then color is An RGB color so RGB stands for red green blue it's a value between 0 and 255 inclusively that means you
can use zero and you can use the value 255 all and if you wanted to make say red well it's red green blue so you say I'm going to use the maximum amount of red the minimum amount of green and the minimum amount of blue that would give you red if you wanted RGB if you wanted blue then you would do 0 0 255 if you want white funny enough it's 255 255 255 because white is Actually a combination of all colors so that's why or combination all of red green Blues that's what you do
like that uh if you want it black it would be 00 Z and you know you can look up RGB color codes and find them quite easily on the internet so Live's label would be that we'll say level oh I just realized I called this level it should be lives my bad so lives lives let's do level label so level label equals mainor Font. render do an F string again not a d string an F string and we will do level colon and this time we'll do level and then we'll do one 255 255 255
so to summarize this has created text which is white an yellow sing of one that has these contents and now we need to put on the screen so put on the screen we're going to say win dublit first one what do we want the lives label okay livesore label and the position we want to put it on we need to Pick an XY I want it in the top left hand corner of my screen but not like directly in the top left hand corner just a little bit offset so I'm going to say 10 10
so 10 pixels down 10 pixels right is where the top leftand corner of the label will sit so it will sit just barely offset from the top of the screen and then we're going to win. Blitz the level label of course and here for our XY it's going to be a little bit different I want this on the right hand Corner of the screen so I'm going to take a guess that um actually you know what let's do the mathematical way because we're going through some in-depth explanations here anyways if I want this to be
10 pixels from the right hand corner of the screen what I need to do is determine the top leftand corner of the label so where should I put that right let's say like I want the label to sit so that the edge of the label is only 10 pixels from the far right hand Right hand side of the screen so to do that I need to figure out the top left hand corner position well what I I can do is find the width of this label I can find the width of the window and then
I can take my padding whatever I want the padding to be and use some mathematical equation to figure out where that should be so thinking off the top of my head here this is going to be width which is the width of the uh window itself so width minus in this case it's going to Be levelor label. getor width so getor width is a method you can use on surfaces that tells you the width of that surface so since I don't know the width of this level label because I don't know how big or how
long this text is going to be I need to call that method and then I'm going to subtract another 10 pixels because if I left it at this that would mean that it would be right on the edge so like the l or like Whatever this level number is would be squished right on the edge so we'll subtract 10 pixels to move it off and then we'll pick a y value which is going to be the same as what we used before as 10 and blit that to the screen so let's look at this now
and notice we get lives five level one perfectly in the right position I mean say that you know we had we changed the width so actually let's do that let's change the width to be uh 800 so let's Go like this if we change the width everything works fine and in fact I can change any numbers I want because we've done this in a dynamic fashion everything will stay consistent it will stay totally fine so we'll put them back to 750 750 but that's why I've been doing things maybe in a more tedious way rather
than just hardcoding because I want this to work for any width height that I choose so let's zoom out a tiny bit there let's move that over and now Let's get into some more stuff so we've displayed the lives displayed the level now we need to make a character and in fact we want to be able to move a character around the screen so the first thing I'm going to do is set up a ship class so I'm going to say class ship this is going to be what we call an abstract class which means
we're not actually going to use this class we're going to inherit from it later because keep in mind we have enemy ships and we Have players ships right those are the two parts of our game really right and they're interacting with each other so the enemy ship probably has some similar properties to the player ship so we can share that in one kind of upper level class uh and you'll understand how this works more but just follow along with me for now so we're going to make an anit method and we're going to say okay
so what are some properties of a ship that we want to store in this game well we Need the X position and the Y position of the ship so where is the ship starting is it starting at the top is it on the left is it in the middle so let's go XY like that uh what color is this ship that's something that's important right so what color and what about the health does this ship have a specific amount of Health in fact I'll make this an optional parameter of 100 which just says that our
default ship has a health of 100 right so the reason we need to Put col here is because when we have an enemy ship we don't know what color it's really going to be right so that's what we'll Define with this color parameter when we create a new ship is it red is it green or is it blue it can't be yellow because yellow is going to be the main ship the one that we're using using to uh to shoot at the other ship right all right so actually what I'm going to do is remove
this color parameter for now just because since this is a general Ship class for our players ship we already know what color that's going to be it's only the enemy ship that will you know change its color on initialization so we'll Define that later but let's uh let's just just ignore if that confused you at all uh the color aspect that I was talking about so we have self.x uh equals X and self. yal Y these are setting up attributes for the class so that each ship we create can store you know its x Value
and its yv value right and I'm going to try to go through basics of oop here like give you a little bit of an explanation in case some of you aren't familiar with the syntax but just follow along and understand that what I've done is made a ship what this class allows me to do is make objects of it so I can have multiple ships that all have these attributes so they all have an X they all have a y and they all have a health that's what the class is letting me do Is later
we'll create an instance of it which means that we can have multiple instances of a ship that all store their own health value their own X and their own Y and they all move on their own kind of terms right and that's the idea here we're going to have multiple things so let's put it into objects and classes Okay so we've done that we're going to say SL Shore image equals none talk about this in a second SL laser image equals none and self-thought lasers Equals blank and self. cool down counter equals z now the
the idea behind this is that when we start shooting lasers we want to make sure that we can't just Spam the lasers so I'm going to define a coold down counter here which essentially means we're going to count or we're going to wait like half a second before we let the user shoot another laser we'll get into that more later but you know we're just starting to class these things out uh just so That we have that okay so we have that now uh let's define ship and what we can actually do in here is
Define a few methods so the first one that I want to do is draw so actually let me go back here for a second just because uh I feel like some people might be confused on this so self. ship image and self. Laser image are what is actually going to allow us to draw the ship and draw the laser so we need to pick what image from the ones up here that we've loaded in Are we going to use for this specific ship since this is a general class and it's not going to be instantiate
I'll show you what I mean in a second uh we just Define those as none for now but when we actually set up our own ship later and start creating ships we'll Define those images so that be able to use them okay so we have draw so draw is going to be important for now and what I actually want to do cuz I just want to show you guys how we can move around the Ship before we get into anything too complicated is just draw a rectangle for now so I'm going to say we're going
to take a window in the parameter so this is going to tell us where do we draw this like where are we putting this and we're going to say window uh that's no not BL we're going to say py game. rect sorry py game. draw. what this says is pame use the draw module do draw rectangle we're Going to pick where so we're going to draw that on the window we're going to pick a color let's make this red for now so 255 0 for red we need to put a wrect in here now this
is a x y width height which tells us how big is this rectangle and where is it on the screen so where is it going to be well it's going to be at self.x self.y because that's the position of this ship and how wide is it going to be well for now since we're just testing things let's make it 50x 50 Now if we want the rectangle to not be filled in we could Define a width so let's say we Define a width of two that's going to give us a hollow rectangle with two pixel
size for the pen size around but if we want to be filled in we can leave it as nothing or put zero explicitly which tells us that that means this is a filled-in rectangle okay so now that we have that I'm going to show you how we can use this ship and then we'll start getting into some more Advanced things but I do I want to show you moving it around first so let's make a ship let's say ship equals ship and here we need to pick an X and A Y value to start the
ship at so I want to start it near the bottom of the screen so what I'm going to do is pick like 300 by 650 and then what we'll do we don't need to define a health because that's an optional parameter right we've already have that defined is inside of my redraw window I want to draw this ship so what I'm going to do is so ship dot draw window now the idea behind this is that this draw method draw draws the rectangle for us all it needs is a window so what we can do
is just call that draw method if there's any more advanced stuff that needs to happen we don't need to deal with it here the ship can deal with that itself in its own draw method so let's just call it with the window now we'll see the ship so let's run this and we notice that I've Made a mistake let's see what this make window is not defined my bad we need to put capital win in there window is the parameter name I'm messing it up so let's do win if we run this we get this
red red rectangle popping up at the bottom of the screen so if I want to start moving this rectangle around now I need to modify its X and Y position um based on what keys I press so let's do that now so to do that we're going to set up a way to track what keys are Being pressed by the person now I could show you how to do it inside this event Loop but the issue with that is it only registers one key press at a time so let's say I press like the side
key and the top key at the same time it won't move both ways it will only move one of them whatever one you hit first I want it so I can move diagonally as well so I can move at the same time by just holding down keys so we'll be allowed to do that by uh pressing both keys at the Same time with this method so what I'm going to do is I'm going to say keys equals pame dokey. getor pressed what this does is return a dictionary of all of the keys and tells you
whether they are pressed or not at the current time so since this runs once or 60 times every second I'm going to mess that up every time I say it so just get used to it uh we'll check 60 times every second if we're pressing a key if we are we'll move in a certain direction if we're not We won't move so let's say if keys and in here py game. Kore so kcore is just the prefix for what keys you can use so you do py game and then or keys since it's a dictionary
we're going to access the value and see if it's true py game. Kore and then whatever key it is that you want so if you want a you type lowercase a if you want to check if the left Arrow key is being pressed you do left if you want enter it's actually Going to be return if you want space it's all capital space uh you can see I have this nice auto complete that's telling me but ideally you can kind of Guess with just lowercase letters and anything that's like a full word like enter or
something or return is going to be all capitals so if we want to move left we're going to say if Keys py game. Korea then we'll go hash left I'm just going to do a comment so that tells me we're moving left and to move left I Need to subtract from the x value of my player so I'm going to say ship dox minus equals 1 now minus equals 1 means we're going to move one pixel to the left now ideally what I should do actually is Define a velocity variable which tells me how fast
I'm allowed to move in every direction so let's do that at the top here I'm going to say player Vel equals and let's pick some number I'm going to pick five what this means is every time I press this key I can Move five pixels so you can you'll figure out how fast that is when we start testing the game but that will also be dependent on your clock speed right so if you had a lower clock speed you probably want a higher velocity because this Loop is only running so often so if I held
down my key with a higher clock speed I'm going to move more because this is going to trigger and happen more times and move me more to the left right so let's do minus Equals ship uncore Val or player B like that and now let's do the other keys so I'll go a little bit faster here if Keys as I say I'm going faster makes a bunch of mistakes py game. Kore D so this is to the right like that make sure I don't forget that Co in there then we'll say ship. X plus equals
player Bell then we'll say if keys py game. kcore and this is going to be W for up we're going to go up like that and then ship oops ship. y minus Equals player. because remember we're moving up so we need to subtract the velocity because the starting position is 0 0 in the top left and then we're going to say if Keys P game. Kore s which is going to be down notice I'm using WD you could use the arrow keys if you want by changing this to be all capital left all capital right
all capital up all capital down but let's do this we'll do down then ship doy plus equals player Bell okay so now that we Have that what this will do is move our player so let's run this and let's have a look so if I use my WD you can see that this Cube now moves around the screen so let's now start restricting how this Cube can move because notice I'm going to go completely off the screen I can go any direction I want right and maybe you might think this is a bit too fast
as well so let's make sure that we can't move off the screen so to do that what I'm going to do is Say if Keys py game. Kor s and uh ship. y plus player. Vel is less than height so what this is saying is if I add uh sorry not Val what am I saying player uncore Val if I add this player velocity value to the current value of my y will I be off the screw if I'm not off the screen let me move cuz I'm less than height which means I'm not off
the screen cuz I'm trying to move down right otherwise Don't that's what that's saying so that's that's that line so now let's see the other ones and ship doy minus player Val is greater than zero because we're moving up so we want to make sure that we're not going to be less than zero uh when we're doing that and for right we'll say and ship dox uh plus player Vel is less than width right and we'll say and ship dot in this case x minus player V is greater than zero so now if we run
this you'll notice that I can't go down well I can but it stops me I can't go left right if I try to go up I can't go up if I try to go right though I can go all the way off but just not um like only here now the reason why I can go this far off is because the top left hand corner is what I'm checking so right now technically the constraint that I've plugged in here that's in my code is valid because the top left is Still in a valid position what
I need to check though is if the edge of this cube is hidden so the way I do that is by getting the width right so what I can do is a quick fix here is say if I'm moving to the right let's add 50 cuz that's the width of the cube and make sure that the top left hand corner is further enough to the left such that you know even if I'm adding this width it won't go off so that's the idea here with uh going right and now same thing with the bottom so
if I add 50 to the bottom so when I'm going down I want to make sure that the bottom Edge doesn't go off the screen so that's how you do that is you just add the width to that equation so now notice I can't go any further than that and if I go to the right I can't go any further than that now obviously we're going to change this because we're going to use like proper Graphics in a second but I want to show you how to move first in a more fundamental aspect so you
Understand the mechanics behind what I'm doing okay so now that we've done that let's actually make a proper ship so let's make a proper players ship rather than that has the proper Graphics rather than what I've just done right here so in draw what I'm actually going to do here is go window. blit and I'm going to say ship uh or self. Shore image this is just how I reference the attributes that are specific to this ship so the one that's being drawn and I'm going to draw This at self.x self.y like that so draw
window. blit self. ship um self.x self.y we'll get into the laser stuff later but that's like further on once we have the graphics working okay so we'll do that and now what I'm going to do is to find a new class I'm going to call this player now the player is going to inherit from ship which means that it's going to take this initialization it's going to take this draw method and use It we're going to add more stuff to the ship class later that will make this make more sense this inheritance but for now
just understand that any methods in here because I've defined this inheritance means I can now use them inside of player so what I'm going to do is to find a knit inside of player so Define uncore nit self XY Health like that health will be a default parameter of 100 once again and what I'll just do immediately is call this this Initialization method from inside of here so to do that I'm going to say super doore nitor self XY Health like that uh I don't know if this takes self I don't actually think it does
I think it's just XY Health what this says is super is this parent class ship let's use ship's initialization method uh on this so we Define our own initialization method because we're going to need to change a few things in Here which I'll show you in a second but let's use the super method so it creates all of these different variables that we need and it initializes things right it just runs that code and now let's add our extension so we're going to say self. Shore image equals yellow ship and self. Laser image equals yellow
laser so we've defined now these two nonp parameters so now we have those we're good to go and what we need to do next is create what's called a mask so what a Mask is going to let us do is do Pixel Perfect Collision so you may notice in other games where there's like weird hit boxes and uh if you hit like the edge of something but there's actually not a pixel there it still counts cuz it just does a square hitbox well pame has this thing called masks which let us do pixel perfect Collision
which we'll get into later but we need to define a mask so we're going to say self. mask equals py game. mask. from surface from surface Self. ship image now what that means is okay take this surface which is the ship image and make a mask of it this mask just tells us where pixels are and where they aren't in this image so that when we do Collision we know if we actually hit a pixel or not then what we're going to do is say self. maxor health CU we're going to add a health bar
later is equal to 100 or not 100 sorry is equal to health so whatever Health we start with is the maximum health we can have as a Player now the reason we need that is because we're going to decr the player's Health right because we Define health up here but we need to still store what it started with so that we can figure out what its maximum health was when we want to draw the health bar and figure out the percentage to decrement it by so there we go we have the player and now I
think uh that should actually be okay for drawing so let's just just change everything from ship now to player now An easy way to do this in subline text is do command H and find anywhere that says ship make sure it's uh case sensitive and replace that with player like that so we're going to say ship player which means now all these things that are highlighted right and you can see them it's not highlighting the capitals will change to player so player will be equal to well that'll have to change but anyways you get the
idea so let's hit replace all and now all of Those are changed to player so player dox player doy all that and let's now change instead of ship this is going to say player so we're going to initialize a new player which is equal to a player object starting at 3650 and then we've changed all that so now we'll draw the player so let's run this and notice now I have the ship and it's moving around now no fancy animations here but that's fine we're not going to do any animations in this specific video let's
Fix this now so that we can't go off the screen with the ship so to do that what I'm going to Define in ship is actually a way to get the uh the height and the width of the ship so I'm going to Define inside a player actually let's do it inside a ship because this will be fine let's define getor width like that so this is a method and what we're going to do is return in here self. Shore image. getet uncore width so remember whenever we Have a surface we can call get width
and get height on it and it'll give us that so here I'll also Define getor height self return self. ship image. getet uncore height like that okay so these are two methods they're just Getters they're literally just returning a value to us because we're going to want those in the main Loop I've defined this in ship not player because player inherited from ship and we're going to want to use these inside of the enemy ships which we Create later so let's just go ahead and add them to this you know Base Class that we have
above okay so now that we've done that rather than plus 50 all we need to do is go player. getet uncore in this case this is height and player dog getor width so before we had 50 there because 50 was the height and width of our rectangle but now since we have the actual um image we need to get the height and width of that image and Use that as the offsetting value in this equation right so that's why we're adding those into there so let's run this and now notice that I can no longer
go off the screen to the right I can't go down can't go left cannot go up you may be like oh why is it only like on this side it's a little bit different than this side all that you can modify those numbers like add a few pixels if you want it's just based on where you start so like say I start at some Location right well moving to the left I don't really it's hard to explain this but if you start at pixel value 11 and then you can move back five right so you're
at six but if you go so you can move back even more from six and you go to one pixel but you can't go any further than that but if you're going to the right say the boundar is at like 20 then you can go to 16 but you can't go further than that because if you're at 16 and you add five which is the Velocity you'll be greater than the width which is 20 pixels in that example so you can't move that far over so I get that question sometimes like why is it different
on the left and right side I don't think it's a big deal but some people do it's just based on where you start the object and you're subtracting a certain pixel value of like five four so you're only going to be able to move in a certain direction so far I hope that makes sense that explanation okay So now that we have that the ship's moving around like we're we're making pretty good progress here let's do the enemy ship so let's let's get that one running so we have player so let's define enemy so class
enemy ship like that it'll inherit from ship and in fact we don't really need to call it enemy ship we can just call it enemy like that and inside of here we'll say Define uncore netore self XY Y we're actually going to put a color parameter here remember I was talking about that before and then Health equals 100 so inside of here we're going to do the same thing we've done before I'll go through this slowly after but I just like to type it so that you don't hear my keyboard the entire time that I'm
talking and then we'll pass X Y Health okay so what I've done is I've finded a new initialization I've said this time we need to pass a c because Our enemy ship will be different colors right it'll be red green blue uh it will not be yellow and we'll pass the health as well and we'll call the super Constructor so this one right here to set everything up and then we will add our own images and stuff uh after so what I'm actually going to do in here is make a class variable and I'm going
to call this ship I'm actually going to call it colore map now the idea behind this is that what I Want to do is make a dictionary where a specific string because what I'm going to do is pass a color as a string so like we'll pass string like red green or blue based on what color it is we want so if they hit red I need it so it gives me the red images so this enemy will have the red images right if they give me green I need them to have the green images
so I'm going to make a map which is just a dictionary that says Okay if we type red right so if we do red then what that maps to is the red spaceship image and the red laser so if we have the red ship it's going to use the red spaceship image and the red laser right if we have green then what this is going to give us is the green spaceship and the green laser right and same thing for blue so if we go Blue this will be blue spaceship and blue laser now that's
like pretty Straightforward I need to make sure I add commas here because this is a dictionary let's hit enter one more time so that's proper and now what I can do is just use this map so I can say something like self. Shore image self. laser image is equal to self. color map color so all I need to do is just pass that color the parameter that we passed in to this map and then that will return to me the images that we're going to use so that's what we have so We'll do self. ship
image self. laser image is equal to self. color map um there's not really much more I can do to explain that that that's the basic concept behind that okay so once we have that we need to make a mask so to make the mask we're going to say self. mask um is equal to in this case pame do mask. from surface like we did before except this time well actually I gu be the same thing self. ship image like that so we have the mask we have uh the Colors set up we have the images
and all we need to do now actually I don't even think there's much we have to do here we're going to implement a method that allows us to move the ship but I think that's all we really need for the enemy so let's have move and let's have V and what this is going to do cuz the enemy ship will only be moving downwards right it's going to start at the top of the screen and move down this is just going to say okay Self.y plus equals V so if we pass a velocity to this
move method we'll move the ship downwards okay so looking at my other screen I think that's all we need for the enemy ship so let's now figure out how we can start spawning enemy ships and have them moving down the screen and then we'll do lasers we'll do Collision uh a main menu and I guess an end screen like if you lose and we'll pretty much be done with this application although that is in a little Bit cuz the lasers are are the more complicated part of this so let's start moving the enemies so what
we're going to do is make a list here I'm going to call this enemies say enemies equals blank list what this is going to do is Store where all of our enemies are and in fact I'm going to make another variable I'm going to say oops not static method I'm going to say wave length is equal to five so we're going to start with the wavelength of five and Then we're going to increment that every time and in fact I'm going to set level equal to zero cuz I'm going to do something cool in a
second you'll see why I'm doing that uh but what I want to do is every time that we get to the next level generate a whole new batch of enemies and have them start moving down the screen so every level we generate a new wave that wave will be in random positions and then they'll start moving down slowly based on a certain velocity Which is going to be called the enemy fell and set that equal to one pixel so they move quite slowly downwards on this screen uh and we we'll see how this works so
that's the idea here what I'm actually going to do is I'm going to get ahead of ourselves a bit inside of the rraw window function I'm going to say for enemy in enemies enemy. draw win the reason this works right Because you're like well I don't have a draw method inside an enemy the reason I can do that is because this inherits from ship ship has a draw method where it draws the ship image and we've defined a ship image here so we can draw that for the enemy right based on whatever color it is
that that enemy is so for each enemy let's draw it onto the screen that's what this says in fact I'm going to make sure that I draw them uh behind the player just so that Say an enemy and a player are in the same position the player's over top of the enemy because ideally you want to see your own character uh not the enemy if you're overlapping so that's the idea behind that okay so now that we have that we need to move enemy and spawn them so the first thing I'm going to do is
actually move this redraw window to the bottom we might be moving it around quite a bit throughout this but let's put it at the bottom now to keep it kind Of out of the way and at the top I'm going to say if the Len of enemies equals equals z level plus equals 1 so essentially as soon as no more enemies are on the screen because once they hit the bottom once they're off the screen this this list is going to be empty that represents our enemies cuz we're going to delete them I'll show you
how that works in a second let's increment the level cuz we've beat the current wave of Enemies let's increment the amount of enemies we're going to have so let's say ccore wave or wavelength yeah uh plus equals 5 so if we start with a wavelength of five every time let's add five more enemies that's what I'm going to go with but you guys can add as many or as few as you want and then let's now create this many enemies so let's say four I in range wavelength like that let's spawn some new enemies and
append them to the enemy List and start moving them down so what I want to do when I spawn these enemies is pick positions for them so they don't all come down at the same time ideally I want them to come down so I want to spawn all of them here I want to create all of them here but I want them to move down and look like they're coming at different times so to do that I'm going to pick random positions for them that's way above the screen so the idea is I'll go to
my drawing tablet here to show you Quickly if this is our screen right and I want my enemies to all be moving at a consistent rate I want to spawn them all at once but I want them to look like they're moving at a different duration I can put them above the screen in a negative position and move them down slowly so what happens is these will all move at the same time right they'll move at the exact same velocity downwards but since they started at different heights it will look like some of them started
Coming down before the other ones when in reality they just started higher up so so that's the concept that I'm going to use here is I'm going to randomly spawn them at different heights and different um X values they might overlap with each other that's just the principle of random there is ways to fix that but we're not going to do that here uh so that they look like they're coming down at different speeds or different areas right so that's the idea so let's Do that so what I'm going to do is I'm going to
say enemy equals enemy here we need an X and A Y so random. Rand range remember I imported random at the top the range that I want for the X position is going to be 100 and width minus 100 so this is pretty much saying I want to spawn my enemies at a maximum left side of 100 uh actually let's make this 50 and a maximum right side so their top X position or top left X position uh at Width minus 100 that's just to make sure they don't go off the screen right and then
we need a y value so let's do random. Rand range in here we need a one so I want these to start negative so they start off the screen so my first value is going to be the smallest value that I want them to start at which is going to be 1500 and the next value will be the closest so I want them to start between -500 and 100 now you could in theory have the possibility that they All start at the same level because this is random but the idea is that they probably won't
do that because it's such a large range so some will be up higher some will be down lower and they should be in kind of relatively different positions so that they come down at different times now you can change the way you spawn these if you want but this is my idea um this is what I want to use but again you guys do whatever you want this is your game so Random because now That we've done the X and Y position we need a color so let's do random. choice and inside here we're going
to make a list of colors so in this it's going to be red blue green now what random not Choice does is randomly chooses one element from a list pretty straightforward so this is the list of colors that we want that are valid uh red blue green so randomly pick one from that for the ship that's just cuz I want some variety I want some different ship Colors if you want to have like red ships have more health or something go ahead feel free to do that but um I'm not going to do that for
this I'm just going to make them all the same but just different colors right so it spawns them uh and now what I need to do is just add them to the enemy list so enemies. append enemy like that and now that I've done that they're in the enemy list and I can start accessing the enemy list to Move my enemies so we've done that we've spawned them in uh if the enemies the L of enemies is zero we'll increment the level increment The Wave by five spawn all the enemies that we need and then
you know move forward now you could say all right well if we get to a really high up level this might be slightly flawed because you're going to have so many enemies within this smaller range so you could do something like -500 times uh level over five or something Like you can change this value if you want uh level level over five will be a bit of an issue but you can do like a more Dynamic approach to this range if you want to multiply by some constant value or something like that but that's just
I'm just throwing that idea out there in case you guys want that so if we want to move these enemies essentially what we're going to do is every time that they're on the screen so there's any enemies in our list we'll Move them down by their velocity pretty easy we're going to say for enemy in enemies enemy. move and in this case it's just going to be enemy velocity like that now you see how neat and nice our code is reading right now because we've implemented these methods keep that in mind that you know that's
the nice thing about making classes and methods is that when we use a Mainline like this it's really easy to read because we have these nice methods that Literally are reading out and telling us what it is we're doing so I think that should work let's run this code uh what's the issue here what have I done wrong uh random. Choice key error green ah so it would help if I spelled everything correctly so the green needs two Es the issue there was I spelled that wrong so when it tried to create an enemy that
was Gren not green it couldn't do that but let's run this now and see that if we wait a second cuz it Is they spawn quite high right now all these enemies start coming in now you know we got unlucky here they kind of came in a batch but we can again do whatever we want if we want to spawn them like every 100 pixels upwards you guys can figure out how to do that uh but the issue we see we're seeing immediately is we're not losing any lives when these enemies go off the screen
and they're not actually being removed from the list which means that We're never going to make new enemies once all the enemies are off the screen so what we need to do now is every time we move the enemy make sure that they are not off the screen and if they are decrement the lives and remove them from the list to show hey this enemy is gone so to do that we're just going to check the position of the enemy so if enemy umy plus enemy. getet height notice we've used this method now that we
needed uh plus actually I guess not Plus cuz we already moved them so we'll just check uh is greater than height then what we'll say is lives minus equals 1 CU we lost a live they hit the checkpoint the end of the level let's delete them then so if we want to delete them since We're looping through this list I need to make this a copy of the enemy list and just do enemy. remove or not enemy sorry enemies. remove enemy what this does is remove the Object which is this enemy from the enemy's list
I've made a copy here so that it doesn't modify the list We're looping through cuz sometimes that leads to issues uh and that will mean that then once all the enemies have gone off the screen there'll be none left in the list so we're able to hit this Len equal 0 you know condition increment the level and increment the wave so let's do that and let's run this and let's see if they Actually go off the screen um I guess I'll fast forward and we'll go through this okay so we can see that the lives
now obviously we're going negative because you know we've lost at this point uh but just notice that that once we get to5 cuz we started with 10 the level increments and now more enemies start coming onto the screen in different positions and these seem to be working fairly well now obviously what we need to do is make sure that we don't Have a negative Liv score so we'll Implement something that will fix that for us uh which is just going to tell us if we lost and then we'll get into shooting the lasers and after
we do the lasers and the collision with the lasers I think that's pretty much all we'll need for this game so let's uh let's do the thing if we lose now so essentially if lives is less than zero or I guess less than or equal to zero and in this case I'm actually going to say or Player. health is less than or equal to zero because we are going to implement a health bar that's what I forgot we'll need to do that next with the uh with the player then we'll say that we lost so
we'll just say lost equals true we'll Define a lost variable up here we'll say lost equals false like that and now if we get spell lost correctly what we'll do is If lost is equal to True uh we're going to increment some kind of counter system that essentially says we're going To show a lost message on the screen for a certain amount of time and then once that lost message is done we'll go back to like the main menu which we're going to create later so lost equals true let's actually just do something inside of
redraw uh window here so we'll say at the bottom if lost so if lost is equal to true we can access that CU it's up here here what we'll do is we'll say lost font which we're going to make need to make a new font for so instead of Main font we'll say lost font like that make this a font size of 60 so just a bit bigger a bit more emphasis and we'll say lore Lael equals lost font. render in this case the text is going to say you lost Exclamation point Exclamation point one
color that'll be white 255 25 25 then say win. Blitz lost label and if we want to put this perfectly Center in the screen I'll show you some math magic to do that that's going to be width over two minus I'll explain this in a second don't worry lore label. getor width over two so the idea behind this and let's put it at a y position of 350 is that if we want this to be in the center the center of the screen is the width over two but since it's has a width like the
text itself and we draw from the top left we need to make sure that we're drawing so that the width right when we include that width will still be centered so if we do width over two and then we Subtract from that to go left so that we account for the extra width half of the width of the text that'll be perfectly Center because that's like I don't know a really great way to explain it but essentially if we have Center here if we draw it's going to come all the way over to one side
or all the way over to one side so if we can move this position over slightly so that it's half of where the width is then it will be perfectly Center in the middle of the screen um That's my somewhat visualization using my hands hopefully that made sense uh but that's the math there to put that in the middle and there you go so now we'll check what happens if we do lose I'll show you that the game is going to still run when it says you lost which we'll fix in a second uh but
the idea here is that it's just like you know it's it's going to say that we lost so let's speed this up we'll get through it and I'll show you okay so we're coming down to One life we see you lost now pops up in the middle of the screen obviously the game keeps running but I'm going to show you how we fix that now so to fix this we need to increment some kind of like timer that tells us how long to show the Lost message for before we just reset the game and also
pause the game right so it doesn't keep moving and decrementing the lives once we lose we want to just pause the game once we lose so we're going to say after lost we're Going to say lore count equals z and what we're going to do now now is if we've lost right lost equals true we'll say lost uh lost underscore count plus equals 1 so increment one every time and then down here we say if lost like that so if lost uncore count is greater than in this case we're going to do 60 because that's
our FPS so actually we'll do FPS multiplied by five So if we wanted to say show the message for 5 seconds we would do FPS mul by five because FPS is how many frames we show per second um you know and then how many seconds we want so in this case let's do three so if it's greater than that then what we'll do is we'll break this wall Loop so we'll say run equals false and we'll quit the game otherwise so else will continue now what this is saying essentially and we're going to have to
move this redraw window to Actually be at the uh very beginning of the loop so I should have left it there but that's okay uh what this is saying is if we've lost so if lives is less than equal to zero or player health is less than zero loss equals true loss count plus equals one and then we say if lost so if we have lost if the loss count is greater than FPS * 3 then run equals false which means we've now got past our 3se second timer let's quit the game if it's not
so If it's still looping we're still waiting to hit 3 seconds continue which means don't do any of this don't let us move don't move anything go back to beginning of this wall Loop and keep running and then we're redrawing the window every time so it'll look like that lost just sits there for 3 seconds and nothing else happens let's run this I'll show you what I mean so again I'll speed up we'll get to when we lost and I will show you okay so we're getting down To it here we can see two one
you lost boom level freezes wait two three Boom game ends okay so that is how that works uh we've got the loss counter going here we can add a main menu pretty easily later on but now time for for collision and lasers now the lasers and the bullets are a little bit more complex in terms of how they move cuz we need to shoot them from the enemy ship or from the player uh but we'll get into that I guess right now all right so the first Thing we need to do if we're going to
be shooting lasers is we need to create some kind of laser object so in this case what I'm actually going to do is make a new class called laser so let's type this out class laser we're going to do in a knit and what this is going to represent is just one laser object now the idea is that we're going to have multiple lasers being shot from each player right so if I shoot a laser going upwards I need to make sure that it Keeps going in that same upwards angle right it's not following what
the player is moving because a common issue people do is they'll make like the laser follow the exposition of the player which means that if I press the left Arrow key once I've shot the laser the laser moves to the left which is not what we want to do right we want to make sure each of these items are independent of the person or the player or the enemy or whatever it is so that they can kind of act on their Own and they can collide with things on their own and they're their own entity
so that's the idea so what we're going to do here is have uh a laser it's going to have an XY it needs an image we're going to pass that image from the ship class so the idea is that when we make a new laser object so when we shoot this laser the player will create the laser object add it to it its laser list you can see we have lasers here and then it will control how those lasers are moved So that that's kind of the concept uh but we'll get into that in SEC
so let's say self.x = X self.y = Y self. IMG equals IMG and of course we need to make a mask for this as well because this is what's going to be colliding with different things so self. mask equals py game. mask. froms surface self. IMG uh not you could put IMG there as well doesn't really matter but we're going to do that so now what we're going to do is make a draw method so the draw method Will take self window like before and we'll say window. bit self. IMG and then self.x self.y now
what we'll do is we'll do Define move so Define move self Vel which will move this with the velocity so the velocity will be going upwards or downwards based on what we pass in here so in this case we'll just say self.y plus equals V if we want to go down we'll give a positive Val if we want to Go up we'll give a negative Val as the parameter and if we add a negative value obviously that means we go up so we have move let's define a few more methods we're going to Define off
undor screen which is going to tell us if this laser is off the screen based off the height of the screen so we're just going to return from this uh return self.y is less than height and yep and self.y is greater than zero Uh we'll do greater than equal to uh less than equal to as well I guess and that should be good for this right now now we're going to Def find one more method which is going to say Collision which is going to tell us if this collides with an object so laser Collide
object and what this is going to do is call a function that we've yet to Define but we'll Define in a second uh called Collide so all this will do is return the Collide of object self now let's Actually go ahead and create Collide method because or yeah Collide function I guess because what we're going to need to do is check if things are colliding when we're moving the lasers so it Mak sense to do that before we start actually moving the lasers but essentially what we're going to do with the Collide is uh use
these masks to determine if two objects are overlapping if the pixels between them are overlapping and if they are then we'll Say yes these two objects are colliding so I'm going to define a function here called Collide it's going to take object one actually we'll just do obj1 and obj2 what we need to do here is use something in P gamer use this mask property called uh actually I got to look over here to see exactly what it's called because I'm blanking on it right now I believe it's like overlap yeah that's what it's called
it's called overlap so what we need to do when we Call an overlap and actually let me go to my drawing tablet give you my beautiful drawing skills with my mouse again to show you what I mean so what a mask is is essentially if we have like this right so this is my object object an object has a width and a height now we know that when we're drawing these objects only some of the object is actually taken up with pixels right so in the example of our ship we have something this is going
to be my very Crud ship right this is like my rocket ship say it looks something like that maybe it has like a little tail but the idea here is that these are where the pixels are and all of this Blank Space here is not where any pixels are but based on the way that we've loaded this object in if something hits like right here we'll say that it's hit the object because it's inside of this width height hitbox like this wh hit box I'm not sure if uh if I explained this before but Essentially
let's say we bring in a circle like we it's really hard to draw with this mouse let's say we bring in a circle right well what actually happens is it makes a square around this circle and that is what the surface of the circle is it's rectangular because it's very difficult to have um circular objects in computer Graphics uh like when we're rendering and drawing things and creating surfaces so the idea is that we have this circle but really it's Represented by a square where all these other things right here are transparent but the actual
Circle itself is the pixels right so we want to make sure that when something hits our object we're not saying it hit unless it actually hits some of the pixels of our object not the transparent background that may exist that's a part of that object and you will see this quite often when you load in Sprites is it'll load in with width height right like say we Load in a little character it'll load in like this like this will be our character and if you hit this side like anywhere on this box it will say
we hit the character even though it's not touching the pixels so it's misleading to the player so the way that this uh mask thing works is if we have two um let's say objects like this and they're overlapping like this what we do is we ask py game we say okay so if there's like pixels here here here here here Here and there's pixels here here here and there's pixels in the same area so if there's pixels inside of this inside of this overlap in both objects will say that this collided if there's not we'll
say it didn't collided or we it did not Collide because these two objects are not overlapping where their pixels exist I think that makes sense but like the idea is if we have you know Stickman right and he has his thing like this and then we have you know I don't know say a Laser like that maybe the Laser's hit box is something like that even though these two boxes are colliding we're not going to say they Collide unless the pixels hit the other pixels so the way that we need to do this though is
we have these two masks which represent where pixels are that's why we created that mask object but in order to determine if they're overlapping we need to come up with something what's that's called an offset the offset essentially Tells us the distance between the top leftand corner of both of these objects we need to know that because given that information we'll be able to determine if they're actually colliding with each other and where their point of intersection actually is because what what the overlap method will do in mask which we'll use in a second is
tell us where these two objects Collide so a point of intersection between them now we don't really need that but we're just Going to see if we get a point of intersection and if we do we'll say yes these objects collided if we don't they did not but the idea is we need this offset which tells us how far away object two is from object one based on their top leftand Corner coordinates so to calculate that what we're going to say is obg1 uh actually I will say offsetx equals obj2 dox minus not minus equals
sorry minus obj 1.x this will tell us the distance from uh object one to object two it's fine if this value is negative which it may be sometimes depending on the coordinates uh but that's how we do that for offset X now offset Y is going to be equal to obj 2 doy minus obj 1 obj J1 doy so again that just tells us the difference between them since this is XY I mean you can consider that a vector with two components we need to do these separately and subtract like that so now That we
have that what we can just do is return obg1 dot mask dot I believe this is overlap yeah I've said that so many times do overlap and then here we're going to say obj2 so is object one overlapping object two with the op offset of offset X offset y so that's what this Collide function will tell us is given two masks right so given object one and object two if they both have a mask so mask here in S this needs to be object two. mask if these masks are overlapping based on the offset that
we've given between the difference of their top left coordinates uh then we'll return true otherwise we'll return false and actually what this needs to be is return does not equal none because if they're not overlapping this whole thing that I'm highlighting here will return none if they are it will return to us actually a topple or a tuple uh that looks like This XY that tells us the point of intersection so hopefully that wasn't too confusing and I didn't go too crazy fast it is kind of hard to explain masks without my drawing tablet out
which I don't really want to get out right now uh but I think that's good enough explanation for the Collision so if we go back to where we actually called that which is here we can see that all this is doing is returning the value of this C Function now the reason I've called self here is because I want to see if the object is colliding with myself right and I could call it in the other method or the other order which is self obj but all self does is give access to this specific instance
so in this case it'll be a specific laser uh so we'll just pass those two things in so the self which is this object and then the object that's giving us here that we want to check if there's a collision with and Then it will return to us if it's collided or not okay so now what we're going to need to do is Implement a few things inside of the enemy and player class in terms of creating a laser uh as well as creating a cool down for the laser so we can't shoot it too
fast so the first thing I'm going to do is Implement a shoot method uh inside of this base class uh ship because both of our methods or both of our classes will be able to use this so Define shoot self Uh we're going to say V like that is it no I think we literally just need self I think we'll literally just have shoot self and then what we're going to do is say if self. cooldown counter equals equals zero which means we're not in the process of counting up to a specific cool down or
keeping track of how long until the next shot then what we will do is create a new laser and add it to the laser list so we'll say laser equals in this case laser we'll give it our XY Value so XY and then what else does the laser need it needs an image so the image we'll pass is self. laser image because laser image is what we're storing here as the image for the laser then we'll say in this case self dot oops do lasers do append laser like that and the next thing we'll do
is re set the cool down counter so that it starts counting so I'm going to say or not reset we'll Start the cooldown counter so it starts counting up so self. cool down counter equals 1 so the idea behind this is that we will make sure that we are at zero for the cooldown counter so it's not as certain value like waiting to go down or waiting to go up or whatever it's going to be and if it is we'll create a new laser at this current location which will'll move later on we'll add it
to the lasers list and then we'll set the cool down counter to start counting up Now what I'm going to do here is say Define um cool down and what this is going to do is just handle counting the cooldown so we're going to say if cooldown counter so if self. cooldown counter is greater than or equal to in this self. cooldown all capitals and I'm going to Define that as a class variable up here so coold down equals 30 so that's half a second uh because the FPS is 60 right so if that's greater
than self. cool down self. cooldown counter Equals z say else self. cooldown counter plus equals 1 uh and we will only increment this cooldown counter if sorry not else say if self. cooldown counter so L if self. cool down counter greater than zero so essentially if this cooldown counter is zero we're not doing anything right because it's not greater than or equal to self. cool down uh and it's not greater than equal to zero but if it is greater than zero and it's Not past the time limit increment it by one okay so now we
need a way to draw and to move our lasers so the idea is that we're going to call this shoot method that creates the laser from down here so essentially if we hit the space bar we'll call shoot which will create a new laser object so actually let's Implement that now let's say if keys in this P game. Kore space so we're going to use the space bar then what we'll say is Player. shoot so that will call that method and we'll create a new laser now remember this only going to create a new laser
if the cool down counter is equal to zero otherwise it just won't do anything that's fine we can hit space as much we want but if we're on cool down it's not going to work so what we're now need to do is have a method that can move these lasers because right now if we do that it's just going to make them and they're going to stand still and in Fact right now we won't even see them because we're not drawing them so first actually I'll just draw the lasers so inside this draw method I'm
going to say for laser in self. lasers like that uh and then we'll literally just do laser. draw window so that will draw all of our lasers we have a draw method on our lasers that just draws them here so that's totally fine to call that no issue there now we're going to define a new method this will Be called move lasers so Define move lasers self Vel and then objs now the reason I have objs here so V makes sense cuz that's like how fast are we going to move the lasers the velocity but
obj stands for objects and the idea here is that when I move these lasers I want to check for collision with all of these objects so to do that I need the objects that I want to check collision with which are here so we're going to move all of the Lasers by this velocity so we're going to say for laser in self. lasers and before we do that we're actually going to increment the cooldown counter by calling self. cooldown so every time we move the lasers we're going to call this once a frame which means
that we'll increment the cooldown counter when we move the lasers right so we can check if we can send another laser or not and then we'll Loop through all of the lasers and what we'll do in Here I got to check here is go laser. moove the velocity so we'll move it by the velocity and we'll say if laser. offscreen which we've made that method here we'll delete the laser so with laser off screen height we'll say if that's off the screen then we'll go self. lasers do remove laser like that and there shouldn't be
a problem with that now otherwise if Laser. collision with an object and we'll actually need to implement another for Loop in here in a second I'll tell you that okay let's take a step back here so I think I'm going to confuse myself a little bit so I just want to step back and make sure everyone understands so first of all I've change this parameter from objs with an S to obj the idea being that actually what I'm going to do in this specific move lasers method is check if each laser has Hit the player
so the idea behind this is that this is going to be used for the player and for the enemy but inside the player what I'll actually do because this is the base class right we're inside a ship is I will uh Implement a new method called move lasers but rather than checking if we hit the player we'll check if we hit any enemies so that's kind of the idea we need two separate move laser methods one for checking if all of the lasers shot by the enemies Have hit the player and one for checking if
all the lasers hit by the player have hit the enemy so that's the idea since there's only one player we only need one object here which means for each laser we can do if laser. Collision object then we can reduce the health of that object which will be our player so we can say obj do Health minus equals let's say they lose 10 health so we can change this value to be whatever we want but I'm just going to keep it at 10 for now And I think that that is pretty much good except that
we're going need to delete this laser so self. lasers do remove laser like that so yes so that's what this is doing call the cool down which goes through and says okay you know we're going to increment this cool down based on what what we've defined here so if we can shoot or not then we're going to for each laser that we've shot that exists currently in our list We'll move it down the screen by the velocity we'll check if it's off the screen if it's off the screen we'll remove it if it's not off
the screen but it's collided with one of our objects in this case this object will be the player that we pass to it we'll do object. Health minus equal 10 which is the player right minus equal 10 and then we'll say self. lasers. remove lasers so remove that because when it hit them we don't want it to keep going down Afterwards and potentially hit them a bunch of times if it keeps colliding with the player so that's the move lasers here I'm going to copy this and we're just going to change it a bit inside
of player so let's put this inside of player this is going to override that parent class one and we'll do the same thing so it'll call self. cool down again and we'll say for laser and self. lasers laser. move but now what I'll do is I'll say l if uh Actually yeah lasered off screen height we'll change this to OB JS then we'll put an else and inside of here we're going to put another for Loop so we're going to say four in this case obj in objs then do this uh and say if laser.
collision obj and then we could do obj Health minus equals 10 but since what I'm going to pass in here is a list of all of the enemies because we want to check if the player lasers have hit any Enemies we're just going to remove that enemy from the obj's list so we're going to say we'll remove the laser obviously we'll say objs do remove obj okay so I think that makes sense so we have the player what this is doing is I'm going to pass to here and this is going to make a lot
more sense when I start actually passing from the main loop it's just I know it's confusing now because it's kind of an abstract concept but for each laser that The player has move the laser if the Laser's off the screen remove it if it's not off the screen for each object in the object list if the laser has collided with that object remove it so delete that object otherwise remove the or not otherwise but remove the laser after that happens as well so that's all we need for player and ship for moving the laser so
now what we need to do is for each player well our player and for each ship or each enemy ship we need to Move their lasers each Loop so for enemy and enemies we also need to call enemy. move laser right with a velocity which is going to be the I guess what was the velocity the laser velocity do we have laser velocity as a as a variable we do not so I'm going to Define that I'm going to say laser undor Val equals 4 then here we'll do move it by laser uncore and check
if it's hit the player so we pass the player object there That's the idea behind that then down here we're going to say player. move lasers pass in this case the laser Las and the entire list of enemies so self. enemies so this will now check if the laser has collided with any of the enemies so that's the idea behind this is that what is the move lasers method is doing there's easier ways to do this probably but this is the way that I came up with it that seems to make the most amount of
sense so let's run this now And say self is not defin so oops so this shouldn't be self- de enemies my bad this should be enemies H long session of recording starting to get TI here so let's run this and check now so if I press space okay so name X is not defined uh where is that so I've made a mistake somewhere here let's have a look so laser XY self. laser image okay so that should be 83 and shoot so I know what the issue is immediately but I'll break it down for you
so I made a Mistake here in the shoot method by calling XY when really this should be self.x self.y won't be surprised if we get a few more errors like that so let's run this and press space uh when I press space nothing's happening aha so I've determined the issue so you saw that none of the lasers were showing up now there's a few problems I'm going to go through I want to summarize what we've done so far and then fix this issue uh so what we just did was create these Move lasers now I'm
I apologize in advance if this was really confusing because I was kind of confusing myself while I was going through this but the idea is again these are moving the lasers so we call this every loop on all our enemies and on all our uh players or our player so that that they can handle the movement of their own lasers notice that in the draw we're drawing all the lasers they should show up on the screen what we do is inside of coold down we're Making sure that we're not shooting too fast uh and that
we have at least a half a second delay before we can shoot that's what this does here we make sure that the coold down counter is equal to zero then we make a laser and add it to the list if we uh press space right if we call this method if we shoot so then we set the cool down counter to one the cool down counter goes through does its Loop and then it lets us shoot again once it resets to zero so here this is The move laser for the player this is a little
bit different what this is doing is checking if the laser collides with every single enemy which we pass in as objs right if it does we remove that object we remove that enemy and we remove the laser now the issue I was having is this right here if laser. offscreen uh height then remove the laser what I did in off screen was a little bit of mistake so this actually needs to say not this so what this is Telling me here is if this is on the screen that's what this value is so I need
to negate that to not to make sure that I actually get what I'm looking for is if this is off the screen I get true and if it's not off the screen I get false whereas before if it was off the screen I was getting false and if it was on the screen I was getting true so it was just immediately being deleted so let's go ahead and run this now and notice and I'll show you this mistake as Well when I press uh this bullet it's going backwards now the issue with that and let's
just actually just test if this even works so it does if I if the laser hits them it it deletes them the reason that's happening is because I haven't made the velocity negative to make it go upwards so what I need to do is here in laser valve for players I need to make that negative the reason for that is I want to make sure that I'm going up not down because if I pass a Positive velocity and I add a positive velocity to my bullet or my laser it's going to go downwards not upwards
so let's negate that or change that to negative and now notice my bullets are going up now if you don't like the speed of these bullets you want to increase them I I agree with you I think they might need to be a little bit faster let's make them five like that and we will notice uh a slightly substantial difference in terms of the speed of These bullets but notice that that Collision was working and now all we need to do is make it so that the enemies start shooting at us once the enemies start
shooting at us we'll implement the health bar and then we'll pretty much be done with uh with this we obviously need to do the we have you lost screen actually uh but we need to add like a little bit of a menu and stuff but we're pretty much almost done once we do that so let's do that now uh Let's make the enemy start shooting at okay so what we need to do now to actually have the enemy shoot a bullet is pick some probability that they're going to shoot each frame so ideally what we're
going to do is something like if random. Rand range between zero and some number is equal to one then have the enemy shoot so what number do we pick though is the question so let's say you want every second your enemy to have a probability of 50% of shooting so every second you want a 50% chance that your enem is going to shoot So in theory every two seconds your enemy should shoot a bullet and that's going to apply to every single enemy well you need to take that probability which is one over two right
which would mean you just put two here and multiply it by 60 because you have 60 frames per second so if you want the probability to be that they have a 50% chance of shooting every every second Then you make this number 120 because 60 * 2 is equal to that and in fact if you want to keep this easier for yourself you can do something like 4 multiplied by 60 even though we know that's 240 uh just so you can change this to have it equate to the the amount of seconds before you want
the enemy to shoot now you can hardcode like every two seconds have the enemy shoot but I just like to have some degree of Randomness to make the game a bit more difficult uh I don't Know if this probability is going to be too low or too high let's leave it on two for now and just mess with this number and see if it's good or not for you right so now that we have that though let's run this and hopefully our enemy should start shooting once they get onto the screen so let's have a
look at this and they do you can see that they're starting to shoot um some of them are shooting more frequently than others of course obviously this is Random right now notice that I can run through my enemies so we're going to fix that so that we can actually if we hit the enemies we lose Health uh but also I can be hit by the bullets they're disappearing these things can hit me and you might notice that the bullets are shooting slightly offset from the center of the enemies uh it's quite easy to fix that
you can just subtract oh actually I'll fix it for you guys right now uh you can just subtract the x value Of where you're going to start shooting the bullet from so in this case if we go to enemy where are we here and shoot where is shoot shoot shoot shoot we need to find the shoot method uh if we override the shoot method in enemy so we'll just take that and move it that here what we'll do is we'll just offset where this is being created so I'm overriding this in the enemy I'm going
to say self.x minus like 10 pixels so Now if you look at this they shouldn't be or they should be shooting more from the middle because we just offset it where the bullets start uh by 10 pixels so that one clearly didn't do that much for us um let's move it over even more let's move it over like 20 pixels and see if that makes a bigger difference let's have a look here waiting for some enemies to come on the screen let's wait for this guy to shoot his green bullet so that's slightly to The
left that's okay with me I'm fine if they're like that far to the left I want to see these blue guys shooting now though give me the bullet okay so that's fairly in the center so for me that's fine I mean if you wanted to be perfectly Center you'd have to use a little bit more math there uh but this is the probability of them shooting I think it might be a little bit too high right now uh but again we can mess with that number and change it around but now Let's do the collision
between the spaceship and the other ships and then a health bar a main menu we're pretty much done so to do the collision between a the player and all the other ships all we have to do inside of here is say if enemy actually sorry if Collide enemy and in this case this is going to be player then we'll just say player. health minus equals 10 and then remove the enemy so enemies do remove enemy like that uh enemy if we Spell that correctly okay so let's put that at the top though because we want
to make sure we don't remove the enemy before we check that so we'll do that right after the enemy shoots like that and then we'll put this as an L if actually just to make sure that we're not going to check if you know the enem is off the screen if it's already collided with the player so that's the idea there uh we have this random shot we have this collision with the player That'll remove the enemy and we'll reduce 10 Health from our player now we need to add a health bar which is pretty
easy to do actually and then the main menu and we're pretty much done so let's do the health bar to do the health bar what I'm going to do is just Implement a function inside a player so I'm going to say Define health bar like that here I'm going to take self and all I'm going to do in here is draw rectangles that are Red and green based on the health of my player so the first rectangle I'm going to draw is going to be red it's going to be the length of my player and
then I'm going to draw a green rectangle that goes on top of that red rectangle but will be only the length length of the health right so if it's like say we have 50% Health we have 50 out of 100 Health it'll be 50% of the length of the red rectangle but on top of it so that it shows like half green half red it's kind Of a cool trick I'll show you exactly how that works let me just get this because there is a little bit of an equation that goes into doing this uh
that I had to come up with so here what we're going to do is we're going to say pame do drawrect we're going to draw that uh so we need to draw the health bar I guess it's going to be a window we want's take that on the window rectangle we need a color we're going to draw red first so 255 then we need the rectangle so self.x [Music] self.y uh if I could spell this self.y Plus self. image so self. ship image. getor height why is my typing so horrible today self. height + 10
let's finish off those brackets there so the idea behind this is that we want to make sure the health bar is below our player so we want to get the y-v value of the player Add the height of the ship add 10 pixels and then start drawing that there and the self. X can draw where we usually draw the X and that's fine now for the width what we'll do is self. ship image right. getor width so it's the same width as the ship and for the um height I'll just make it 10 pixels and
you can make that as much as you want but we'll just do 10 now let's copy this and we'll do the exact same thing now in green uh except just a little bit different for The rectangle width so it's going to be the exact same stuff except the only that's going to change is the width and the color so zero so red green blue so 0255 Z and what we need to do now is essentially determine what percentage of the width we should draw so if we want the width to be this so self. ship
_ image. get width we're going to multiply this by some fraction that will essentially tell us uh how much width we want to put so to Do that we're going to multiply that by one minus in this case maxcore Health minus self. health and I actually think that should be self. health and then that's going to be divided by here self. Max Health now I think I might have made this math equation way more difficult than it needs to be but let's just think about this for one second so I want to multiply the width
by one minus uh these Don't need as many set oh yeah I think these brackets are correct 1 minus the maximum health minus the self do Health which will essentially tell us okay um so how much difference is there between the maximum health and the health we have right now and then divide that by the max Health to get the percentage Health that we're down and we're going to subtract one from that although I think an easier way to do this would just be to multiply by self. health yeah This is going to be easier
by self. health over uh self. Max health so I'm glad that I took the initiative to fix that there yeah so this is the image width multiplied by the health over the maximum health which is just telling us what percentage of Health we're currently at so since we know this is going to go in increments of -10 uh this is fine to do like we won't get a decimal value here but you know sometimes we might so just keep that in Mind but yeah I think that's the equation I think that makes sense hopefully that
makes sense to you guys I'm just trying to figure out what percentage of width that we should draw the green rectangle at so that if we lose 10 Health that goes down a little bit right and we can do that variably using that kind of equation that I just drew so we have health bar so let's Implement that now into the draw method of the player ship so let's define the Draw again so Define draw do self window we're going to call the super draw method so super dot underscore uncore sorry what am I saying
done it super. draw pass that the window and then we'll call self. health bar so self. healthbar with the window so I've just overridden the method from the parent class which is this one here which has the draw I called the parents draw method with the super and then I'm calling the health bar for the window or with the window Which now should draw that health bar for me so let's have a look uh what's the issue here let's see has no attribute get ah so I've added extra dot accidentally here this should be a
get underscore height get underscore height I'm sure most of you probably noticed that so get underscore height let's run this now what's the issue here I made another mistake uh W argument is invalid I think I forgot to add the 10 yes I did so multiply There let's see if this is the correct bracket yeah so I think I'm just messing up a bracket here I think that goes there and I think now we should be good no we're not let's see what's going on with the brackets here give me one sec guys okay so
I did fix it the issue was I just had all these brackets messed up in here I just need to add two at the end there the code will be in the description if you guys are getting confused with what I'm doing cuz so here You can see when we load in the health bar is off the screen we can fix that if we want quite easily uh in fact let's actually do that now just before we forget go down to where we're allowed to spawn first of all where we spawn the person in and
make it so he spawns at 630 and let's just add 10 pixels to where this guy can move so if we go player get height plus 10 this is just to make sure that the health bar will be able to be Shown if we add 10 pixels there we'll ensure the health bar will be showing up so let's do that now we can see the health bar shows up in fact it cuts off a little bit so let's make this 15 pixels um and now let's run this and we can see that the health bar
will stay perfectly on the screen so there we go the health bar is on the screen let's watch what happens if we hit one of these guys you can see the health bar does decrement it goes down and that is A strategy I guess in this game if you want to waste your health and hit one of the things to like sacrifice yourself for that you can do that so yeah that's uh that's how the health bar works so I guess now all that's really left to do is the uh the main menu so let's
go ahead and do that okay so main menu what we want to do essentially is just have it so it says like press any key to begin and when you press that key you can begin and that way if you die it'll Bring you back to the main menu and you can choose when you want to start playing again other than that though the main functionality of this game is pretty much done so let's Implement a main menu so let's define mainor menu this is going to be quite simple I'll go fairly fast we're going
to say run equals true while run we're going to say for event impy game. event doget if event. type equals equals Pame do quit like that then we will say is run equals false okay and then in here we're going to say just draw this on the screen and actually sorry I need to say if vent. type equals equals py game Mouse button down colon main so what this is saying uh is if we press any of the mouse buttons enter this main Loop and start playing the game uh if we press the x button
set Run equal false we're going to quit here so we'll say pame do quit like that in fact we can actually just use the quit method too it's up to you whatever method you'd like to use uh but this is saying if we press any Mouse button call the main function if we press quit quit but what I want to do is just draw like some text that says press any key to begin or press uh you know the mouse button to Start something like that so the first thing we'll do is we'll just say
win. Blitz BG notice I'm just doing it in line here because it's just going to be short for the main menu so we'll blit the background we'll say pame do display. update and then we'll create a font up here so we'll say titlecore fontals pame do font. sys font comic sends let's do size 70 and then we'll render something onto the screen So we'll say title uh label equals title font. render press the mouse to begin dot dot dot let's render that one let's render that white so 25 25 2v5 and then let's say win.
blit title label let's blit this in the middle of the screen we remember that shortcut I showed us so that's width over two minus title label doore width over two that'll put that in the middle and then here for The Y let's put that at 350 and then that should be good so now that we have that uh what this Loop will do so rather than calling main we need to call maincore menu and let's have a look at how this works so we're getting an error funny enough uh plus 15s so I've accidentally pressed
s that's what happens when I try to save too frequently apparently uh what's the issue now pame do quit main menu let's have a look here py game. Quit um inconsistent use of tabs and spaces love when I get that issue so for me to fix that I usually just do this converting dation to spaces so that should work now and let's run this uh win is not defined so win needs to be capital that let's run this and there we go okay so I'll go through this in a second I'll summarize I just want
to show you now it says press the mouse key to begin uh if we exit out so press the Mouse button to begin if I hit X it brings me back here I'll show you how to fix that if you don't want that to be the case but when I press the mouse the game begins we can start playing uh and you know when we exit it'll reset like it should normally do so that's how that works if we want to fix it so that when we press the X it doesn't bring us back to
the main menu menu what we can do is just instead of saying run equals false in here we can do quit what that's going To do is quit the entire Python program uh which will just end this whole thing for us if we press the X so that's the idea now main menu will summarize quickly what I did here literally just set up the exact same thing that we have before except for a main menu so I made a main loop with a run equals true variable I defined a font I said in here we'll
draw what's going to be on the screen for the main menu which is just these uh two things right so the label And the background then I'll do an event Loop I'll say okay so for each event notice I didn't put a clock in here cuz I don't care about the clock speed for the main menu that that's irrelevant we're not moving anything around that's fine so I don't need to clock so we just have an event Loop if you press quit it and it ends the game and if you press the mouse button down
it starts the game and it will always bring you back to this main menu function because since we Call Main here without setting run equal to false when main exits right when main is done we exit out of this wall Loop here we go back into main menu and wait until we H hit the x button to stop playing the game so that's the idea behind this and that is pretty much this game okay so we ran into an issue here list. remove X X is not in the list uh so let's just fix that
here so 111 in move lasers so we ran into a quick bug uh let's try to find that 111 111 in Remove laser if laser. Collision object objects are remove obj uh self. laser lasers. remove laser so I guess what we should do is make sure this laser is in the list before we remove it because I guess it could have been removed uh in a different situation so in that case we'll just say if self. laser I guess we'll say if laser in self. lasers then we'll remove it otherwise we won't so this is
the fix here just to Make sure that if this laser is in the list you can remove it otherwise we will not so let's run this and see now cuz I hit something and I ran into that bug so I want to make sure that we don't get that again okay so that seems to be working um you know one thing to note is if you hit a if you hit something and it has a laser shooting that laser will disappear just cuz we delete the object itself uh there's not really an easy way to
fix that the way that we've Implemented it I don't think it's a huge deal I think that's part of the strategy of the game is like if you want to remove someone's laser go in and shoot them uh like I think that is a decent strategy or that's something that be incorporated and yeah that is pretty much it for this tutorial hello everybody and welcome to a brand new tutorial series on this channel where I will be showing you how to make a car racing game in Python using py game now Pame is one of
my favorite modules in Python it's been a while since I've done a tutorial series using it so I kind of came up with this game right here which actually fun fact is one of the first games I ever created using a software called Game Maker so I kind of recreated in Python and it turns out to actually be pretty complicated to implement and makes a really good tutorial anyways let me explain who this tutorial is for and then I will demo the game to you so this Tutorial is kind of designed for intermediate programmers if
you are a beginner you can definitely follow along I'll try my best to explain everything as always but this is going to use quite a bit of kind of more advanced python syntax or more intermediate python syntax and so if you haven't seen object-oriented programming before it might be a little bit difficult to follow along but again I will try my best to explain with that said this will Probably be five videos maybe 2 and 1/2 hours of content everything you need will be linked in the description in each video all of the assets you
see here most of them I actually made myself and of course they're free to download from the description all of the code that I write in each video will be uploaded to GitHub so you can look at the code per video not just the finished code and yeah with that said that's pretty much everything you need to know So let me Demo the game for you and then we will start actually writing the code so the idea behind this game is we have two cars one car is kind of the player car so the red
car the other one is the computer right so the green car now the objective is to Simply beat the green car to the Finish Line at every single level now you can see right now that the green car is going quite slow but as the levels increase it increases in speed and will it gets progressively more Difficult now I always like to leave my games pretty basic and then allow you guys to kind of add on to them so something you could do to make this more challenging is add on obstacles you could add like
I don't know oil or something on the track so that you would slip if you hit it you can do all kinds of crazy stuff what I'll be showing you in this tutorial will allow you to kind of add that stuff as you continue now you can see here we moved on to level Two notice the car will get progressively faster and then this game goes up to 10 levels the last level has the green car almost as fast as the red car and so if you beat that last level there then you win the
game anyways I won't keep playing through this but this is a pretty Comm complicated thing to actually make I know it looks trivial but to allow the car to move in this way to have this car follow a path to have a collision with the track that's kind of Not square right not rectangular Collision to have the Finish Line to increment levels to change speeds there's a lot going on here and this is a really good kind of learning experience from this tutorial anyways enough of this long introduction I apologize let's go ahead and get
into the code go ahead and get started now we have some set of steps that we need to walk through and then once we do that in this first video I'm going to show you How we can move a car around the screen I know that seems trivial but we're going to implement acceleration velocity braking and slowing down uh and a bunch of other stuff like actually changing the angle of the car and determining the horizontal and vertical displacement of the car based on its angle so it's actually pretty complicated and that's why this video
will be you know the length it is it's probably pretty long although I haven't filmed it yet Obviously and anyways before we can do all that we need to set up our environment so I here in Visual Studio code feel free to use whatever editor you want and the first thing we're going to want to do here is download all of the assets for the game so I'll just walk through them kind of one by one cuz I actually made almost all these assets myself so hopefully you guys are impressed by that we have a
Finish Line we have this grass which is kind of the Background I didn't make this I found this on Google Images we have a green car I made this I was impressed that I made this with pixel art hopefully you guys like that too we have a gray car we have a bunch of other cars uh as well I just made a bunch of different colors so you guys could swap the colors if you want but I'm using green and red and then obviously we have the red car and then we have our track border
I'll discuss why we need this in a second and Then we have our track so notice this track kind of has some white outlines the reason for that is I took this from Google images and then remove the background from it in Photoshop I'm not very good at doing that so that's why it looks the way it does feel free to use any track that you want but what you will need if you use a different track is you will need the Border or kind of like the yeah I guess you call it border I
guess you could call it the walls or The outline of the track as well you'll see why we need this but this is how we're going to handle collision by using kind of just the edges to determine if our car has actually gone off of the main track and that's how we're going to bounce our car backwards so again you need the main track like this and then you would need the track border you could do it with just the Border as well and then you could have some background uh kind of beneath the Border
you'll see What I mean in a minute but I'm kind of just explaining why we have these two images here then of course we have the white car again this is just so you guys can have some options when we're using the cars great so download all those again Link in the description it should download a zip folder and then you can extract extract the zip folder Story by right clicking on it and get all of the images now that we have that what we need to do is install py game so what You're going
to do is go in your terminal or command prompt and type pip install py game like that now for some reason this doesn't work I have two videos on this channel I'll link them in the description as well they walk through all of the possible ways that installing pame could go wrong and how to fix them so I'll refer you to those two videos there for some reason you cannot install pame so watch those and then come back great obviously I already Have pame installed so we are good to go now that we've done that
I'm going to make a python file in fact I already have one called main.py outside of the images directory but inside of the folder where my project is going to be all right so now that we've got all of that set up I'm inside of the main.py file and we're going to start writing some code now the first thing I'm going to do is just import pame because we're going to need that a few Other Imports we'll need as well it's going to be import time and then I'm just looking at my cheat sheet here
in fact if you notice me looking to the right it's CU I have all of the code already written just so that I don't get lost as I'm going through this tutorial uh we're also going to import math we'll be using a lot of stuff from the math module now that we've done that the first thing I actually want to do is just load in all of my images the reason I'm doing that now is because we actually need some of the images to set up some other things you're going to see so the first
thing I'm going to do is load put in my grass so in all capitals I'm going to say grass the reason all capitals is because this is a constant this is not going to change so that's the convention I'm going to say py game. image. load and then I'm going to put the path to my image which is going to be Images slash and then Grass.png like that so now I have my grass next I'm going to load my track so I'm going to say track is equal to py game. image. load it's going to
be images SL track.png G like that after we do that we will load in our track border so I'm going to say trackcore border like that is equal to py game. image. load and this will be track hyen border let's make sure that's the correct name uh looks like it is okay great and now that we have the track border we can Load in the finish line so I'll just say finish is equal to that and then this will be finish. PNG and then we can load in our cars so we will say red car
is equal to and then this will be red hyphen car and then we will have our green car let's make sure that's all capitals and then green car like that now of course feel free to swap these cars if you want I don't think I need to explain how to do that but you just change the name inside of here and then The corresponding variable name great so now that we've done that what I want to do is start displaying some of these images on the screen but first I need to actually set up a
screen or set up up what's known as kind of the display surface so what I'm going to do here is say that my window or my win in all capitals is going to be equal to py game. display. setor mode and then the mode that I need to set inside of here is a Tupple containing the width and the height of my display now the width and the height of this display I actually want to be equal to the size of my track so whatever the track size is that's how big I want my pame
display to be so what I'm going to do here is say whip comma height is equal to and then track. getet uncore width and then track. getor height like this so a little trick in Python whenever you have a surface Which is what this does it loads in an image and renders it as a surface or stores it as a pame surface you can get the width and the height of that Surface by using get width and get height so we're going to get the width and the height of our track and then I'm going
to say that I want a display that is of size width height and that is obviously corresponding to the size of the track now that I have set up the window I'm just going to give my window a name so I'm going to say win Dot and then this will be setor caption like that and I'm just going to say racing game exclamation point like that okay so now that we have our Windows set up we should see if we run the code here uh let's see uh no such file or directory images grass.png okay
that's interesting let's see why that's happening uh oh it's grass. jpic well that makes sense so let's fix that let's run this now and then we should See a pame window pops up and then it just immediately goes away uh because apparently it has no attribute set caption interesting I believe that's because this is actually the correct one py game. display. setor caption my apologies again that's going to happen a lot I'm going to make mistakes in this video Let's run this code now though and see what we get and there we go perfect so
everything is working as we would expect the reason the window is not Staying on the screen is because we haven't made it stay on the screen yet okay so now we have loaded in some of our images the next thing that I want to do is actually show some of them on the screen so I'm going to set up my event Loop I'm going to say while run and I'm going to make a variable here that says run equals true now the event Loop in Python is kind of a constant Loop or in pi games
sorry that is going to be handling all of your Collision all of Your movement all of your events like the user pressing a key and so the first thing you usually do is you set up this Main Event Loop and that's what keeps the window alive right keeps it running on the screen and then as soon as you quit the window or the game ends then you would destroy the event Loop and destroy the game and then the window would disappear hopefully that makes a bit of sense but we're going to say run equals true
while run now inside of here I'm going to say the following for event in pame event doget this is going to give us a list of all of the events and then we can Loop through them and the first event that we want to check is if the user has closed the window so if they press the X in the top right hand corner so the way we do that is we say if vent. type is equal to py game. quit then we're going to say run is equal to false we're going to break out
of this for Loop right here and then underneath this while loop I'm going to say py game. quit now this will just close the window cleanly for us so the idea is if we press the quip button we make run equal false we exit the wall Loop and then well we would quit the game awesome so now that we have that if I run my code we should see that it says racing game window shows up everything's fine and then if I click X it closes there we go and that is some good progress okay
so Now that we have that what I want to do is set up a clock now what a clock does is make sure that our window is not going to run faster than a certain frame per second or than a certain speed is probably what I should say so right now this while loop is going to run as quickly as our processor can handle it so if you have a really quick processor it's going to run faster than if you have a really slow processor but the thing is when I have this game I want
it To run at the same speed on every single person's computer right or I want it to at least have a maximum speed so one person can't be going like super fast down the track meanwhile on a slower computer they're going really slow just because their processor can't handle it so I'm going to set up a clock and this clock will fix that for us so I'm going to say clock is equal to py game. time and then clock with a Capital C then up here I'm going to say FPS standing for Frames per second
is equal to 60 right at the top of my w Loop I'm going to say clock like this do tick and I'm going to tick by FPS now what this does is make sure that this wall Loop cannot run faster than 60 frames per second okay so if you change this number then that will change how quickly this while loop can run hopefully that makes sense but if we run the code now we should see that it's just working the exact same we're not really going to see a difference because We're not drawing anything on
the screen okay so now that we've done that I want to draw some of these images on the screen and just see the size of them and then we're going to kind of position them and redraw them just to make sure they look good so let's go inside of here and let's start by doing this pame do display not clear but do update now this is a method that you need to run every single time you want what you've drawn on the screen to actually be drawn So what you can kind of do in pame
is you can draw a bunch of stuff and then as soon as you've drawn it onto the screen you update the display and then it will show all of the stuff that you've drawn so in this case I want to start by drawing This Grass background and then the track over top of it so let's do that we're going to say py game uh actually not pame we're going to say win which is the name name of our window do blit this is what you do when you Want to draw an image onto the screen
we're going to put the image we want to draw so I want to draw grass and where do I want to draw this at position 0 0 now the coordinate system for pi game is 0 0 is at the top left hand corner I guess top left would be there for you guys and then as you go down the Y increases so the bottom of the screen would be the largest y value and as you go to the right the X increases so the furthest right would be the largest x Value sorry uh so yeah
the X increas as you go right perfect so let's run this now let's see if grass is showing up and notice grass is showing up now it's not quite large enough we'll make it larger in a minute but for now we can see it on the screen so now that we've done that we want to draw the track so I'm going to say wind up blit and then track like that and we'll draw the track at 0 0 now notice the order I've drawn this I've done the grass first and then the track Second that's
so the track will show up over top of the grass if you did in the other order well you would get it in the other way let's run it now and notice now we have our track and that the size of the window is exactly kind of the size of the track here right so now what we need to do is draw the finish line and we also need to increase the size of the grass and I actually want to make the track a little bit smaller because it's taking up a bit too much room
on The screen for my lying so let's just draw the finish line now we'll say win dot blit like that and then we'll say finish and we'll just draw this at 0 as well just so we can see what it looks like and then that's the finished line that might actually be a good size but we might need to make that a bit smaller as well when we change the size of this stuff okay so now that we've done that we need to change the size of some of these images so to do that I
want to Write a function the reason I want to write a function is to just going to make it a lot easier for us to scale our image rather than having to manually write the same thing a bunch of times so I need to go look at my cheat sheet here and we're going to write the following function define scale image this is going to take an image and a scale factor now the factor is like if I give two it's going to scale it by 2x if I give 0.5 it's going to shrink it
by a Factor of two or Shrink it or I guess multiply by a factor of 0.5 right whatever way you want to think of it but that's kind of how it works so now I'm going to say the size this will be the new size is going to be equal to round and then this is going to be image. getet width multiplied by the factor the reason we need to round this is because we need to have integers when we scale the image we cannot have decimal values so we'll do that now let's copy this
We're going to go comma and instead of get width now we're going to do get height and again we're going to multiply by the factor so this will give us a topple that contains the new width and the new height of our image then what we're going to do is return uh like this py game. trend form do scale and then we're going to pass the image and we're going to pass the new size that we want this image to be let me make sure that's right looks like It is so that will allow us
to scale our image now the thing is I don't really want this function kind of cluttering up my main file so what I'm going to do just to clean things up a little bit here is I'm going to make a new file called utils.py and inside of utils.py I'm going to put utility functions that are going to be used from inside of this main file so inside of here I'm just going to import this function and at the top of the program I'm going to Import P game like that just because we need to access
the P game in here to use this P game function great so now rather than having this function here I'm just going to say from utils import and we will import scale uncore image like that great so now we can use scale image so the first thing I want to do is I want to scale my grph so I want to say scale image I'm going to pass this image to scale and then what do I want to scale it by let me check here and see for now We'll try with 2.5 we might want
to change that but that's what we'll go with right now and then for my track I don't really want to shrink this too much but I want it to be a bit smaller so I'm just going to scale it by 0.9 okay so now we've scaled the track and the grass while we're ated I'm just going to scale the track border to be the same size as my track the reason for that is I need the border to be the same Size otherwise we're going to have come some weird Collision errors in the future so
let's make this 0.9 9 and then the Finish Line will leave like that for now okay so let's run this and notice that that looks a little bit better the grass is taking up the full screen track is a bit smaller everything looks good now let's just draw a few cars and then let's scale those so let's go down here and rather than blitting the Finish Line let's blit a car so let's just go with Redor car all the cars are the same size so if you scale one you can scale all of them uh
notice the car is a little bit big I'd like that to be a bit smaller because we want to be able to fit two cars on the track kind of parallel or beside each other so let's make the car a bit smaller let's go to Red Car let's go scale image and that should not be in all capitals let's go scale image like that we're going to scale this to 55% so 0.55 and then we'll do the same thing Here scale image and 0.55 okay now let's run it and let's look at our car and
that is a much better size sweet so now we have drawn pretty much what we need to onto the screen however what I would like to do is kind of clean this up a bit and you're going to notice we're going to continually be cleaning and refactoring stuff as we go through this I want to take all of the stuff related to drawing And I want to put this in a separate function just to make sure that I know where all of my drawing is being done and I'm not drawing you know like a hundred
things inside of this wallet because that's going to get really messy really quickly so I'm going to make a function up here called Draw now the reason I'm not going to put this inside of the U Tails function is because this is very heavy or very correlated to the game whereas the stuff inside of Utils.py I could use this in any game whereas this draw function is going to be used only in this game right so it kind of makes more sense to be in this file anyways I'm going to take a window that I
want to draw stuff on and then I'm going to take images that I want to draw then inside of here I'm going to say four and we're going to go with IMG in images I'm going to say win do blit and then I'm going to blit the IMG and and we're actually going to say IMG Comma pause and you'll see why in a second and I'm going to blit it at this position now what I'm going to do is I'm going to say my images are equal to and I'm going to make a list containing
images and their positions that I want to draw them on the screen so I'm going to say grass and I want to draw this at 0 0 and then I'm going to say track and I again want to draw this at 0 0 and for now we won't draw the car we're going to draw that a bit differently so now Inside of here I need to call this draw function I need to pass in my window which is a capital win and then my images like that so now if we run the code we should
get the same thing we got before and we do all is working okay so that is all good now we want to draw the car and we want to move the car around the screen and the thing with the car is we need it to be able to change its position we need to be able to rotate the car right so we can go left it can Go right because that's how we're going to be able to turn we have to be able to turn around the track and what we need to turn the heading
of the car so we will continue in 1 second but I need to quickly thank the sponsor of this video and this series which is algo expert algo expert is the best platform to use when preparing for your software engineering coding interviews they have over 160 coding interview questions on the platform and I am one of the Instructors on that platform so you can be sure there are great explanations for each of those questions check them out from the link in the description and use the code Tech with Tim for a discount on the platform
so what I'm going to do here set up a class and this class is going to handle all of that stuff for our car so I'm just going to say class and I'm actually going to make an what's known as an abstract class I'm going to say abstract car like This now let's see why we need this in a minute but the idea is we're going to have both a player car and a computer car so there's going to be a lot of stuff that's common to both of these cars so we're going to put
all of the common stuff in an abstract class this is a class that's not meant to be instantiated but that's meant to act as the base class for the other two classes if you're not familiar with inheritance don't worry about it too much just Understand that all of the stuff I put inside of here is going to be used by both my player car and my computer car and that's the point of this so inside of abstract car I need to go and look at my code here to remember what I put I am going
to Define in a knit now I'm going to say Define a knit like this and inside of here we're going to take self we're going to take a x and a y um actually no we don't want an X Y we're going to go with Max velocity as our First parameter and as our second parameter we're going to go with the rotation undor velocity so the reason I want both of these is because I want to know the maximum speed my car can go so the maximum velocity and I also want to know how quickly
my car can rotate so it's rotation velocity and then inside of here I'm going to say self. maxcore Vel is equal to maxcore Vel I'm going to say self. Vel equals z the reason why the starting velocity is zero is because Your car is not moving when it starts it has a velocity of zero and then I'm say self. rotation velocity is equal to rotation V I'm then going to say self. angle is equal to zero and the point of this is that r car will start at an angle of zero and then when we
change the angle that will change the way that the car is rotating okay so now that we have that the first thing I want to handle is just rotating the car so I'm going to go inside of here and I'm going To say Define rotate like that I'm going to take a self a left is equal to false and a right is equal to false now you're going to pass left equal stri if you want to rotate to the left and right equal stri if you want to rotate to the right now inside of here
all I need to do is say if left I'm going to say self. angle and then this is going to be plus equal and then self. rotation velocity like that and then if we are moving to The right it's going to be the opposite so we're going to say LF right then self. angle minus equals self. rotation B and now that I'm thinking about it when when I'm going to the right my angle is increasing when I'm going to the left my angle is decreasing so I actually think it might need to be the other
way around um or maybe I'm crazy here you know what we'll leave it like this for now and if for some reason we're rotating in the inverse Direction Then we'll change this I think this is right I'm just confusing myself okay so now we have rotate I'm just looking at anything else we might need here for now that actually looks good so what we can do is call the rotate method and then depending on if we're going left or right we'll rotate to left or right the way we rotate is by changing the angle however
we need to actually rotate the car right we can change the angle in this class but that's not going to Change the position of the car image so what we need to do is find a way to actually draw the car image rotated so we need to know how to rotate the image in py game now this say a little bit complicated but I'm going to go inside of utils.py and I'm going to write a function that can take an image and return to you a rotated image based on an angle so let's do that
we're going to say Define L bitcore rotate Center and what this is Going to take is a Surface this is where we want to draw the uh actually let's call this wind this where we want to draw the rotated image then we're going to say the image we're going to say the topor left and we're going to say the angle okay so I'm just going to write this function then I'll explain a little bit about what's going on after but I will note that rotating an image in pi game is not trivial if you're going
to be rotating an image you can just Normally rotate it but if you do that you're going to get all kinds of distortions and the reason for that is the rectangle that contains the image so I should say every single image in pi game is really a rectangle and then the actual image is inside of that rectangle so even if it doesn't look like a rectangle there is a rectangle that's containing the image so when you rotate the image you're also rotating the rectangle and based on the position that You're rotating the rectangle around you
can get really kind of weird like you know morphing and distortions occurring with the image so that's why we need whatever we're doing here so I'm going to say a rotated image is equal to Pi game and I believe this is transform it is transform. rotate and we're going to pass the image and the angle that we want to rotate now what this will do is rotate the image around the top left hand corner now that's no good we don't Want to rotate the image around the top left hand corner because that's going to lead
to us kind of having like a circle around that um stationary Point instead we want to rotate around the center of the image so the way we're going to do that is we're going to say new rectangle is equal to rotated image like this and this is going to beore rect and we're going to say that the center of this rect is equal to image Dot and then get uncore Rect like this and we're going to say that the top left so top left like that is equal to the top uncore left and then inside
of here we're going to say do Center okay so what's happening here is pretty complicated but I will try my best to briefly explain it I have to admit I did take this code from stack Overflow I didn't come up with this on my own anyways point being we rotate the original image when we rotate this image I'll show you in a second we get all kinds of weird distortions and the actual X and Y of the image is going to change based on how it's rotating around the top left hand corner so then we
have our new rectangle so we say the new rectangle is equal to the rotated image. getet rectangle the point of this is we want to remove move the offset so we want to make it so that we rotate the image without changing the X and Y position of the image on the screen That's what this whole line is trying to do for us so we're saying let's get a rectangle from the new rect but let's make its Center equal to the image the original image it's rectangle at the top leftand Corner position then whatever the
center of that is so we're getting the original image we're saying the top leftand corner of that original image is equal to whatever its X and Y position is because the image doesn't know its X and Y position so we need to set the top Leftand Corner explicitly to be equal to that then we're saying let's get the center of that and wherever that Center is the new image needs to still be on that Center so that way we're only rotating from the center of the image not from the top left but we had to
originally rotate from the top left because that's the only way to rotate an image in pame hopefully that makes a little bit sense and then what we're going to do is say this we are going to Say win blit and we're going to split the rotated image and we're going to do this at the new rect do toop left so the whole idea of this new rectangle is to find the correct X and Y position of the new rectangle such that it's going to be in the same position as it was before but now it's
rotated all right a lot of uh complicated code there but there you go that will blit it and rotate it in the center for us so let's go to main. Pi now and let's define a method inside Of abstract car that can draw the car for us we're going to say Define draw and then we're going to take in self and we're going to take in a window all we're going to do is the following we are going to say first we need to import this I believe this was blit uncore rotate Center yes it
was so we're just going to say inside of here blit uncore rotate Center and then we're going to pass self. IMG actually we're going to pass wind sorry and self. IMG which We've yet to Define which we'll do now so we're going to go to abstract car we're going to say self. IMG actually not up here what am I doing sorry we're going to do it inside of here we're going to say self. IMG is equal to and then here I'm going to say IMG is equal to and we are just going to reference one
of the images that we want for this car so in this case I want the redor car I'm going to say self. IMG is equal to self. IMG understand this is a little Bit weird what we're doing here is saying the following we're going to store inside of the class the image that should be used for this class class so in this case I want it to be a red car then I say the self. image so the image specific to this instance is equal to self. IMG so whatever the image is here and then
inside of here we then reference that image so that we can rotate it and well blit it in the center okay that's all great however I need to First make a way to actually rotate my car before we can see if this is working so let's let's actually just draw the car first let's make a car I'm going to say car is equal to and first we should create a concrete instance of this class so I'm going to say class we're going to go with player car like that now inside of here all I'm going
to do is just copy this going to remove it from abstract car because now we have this class and that's actually all I need inside of Player car but I need to make sure I inherit from abstract car so let me just explain this quickly in case this is a bit confusing we have the abstract car class this defines a bunch of functionality when we put it inside of the bracket it's like this we're saying we're going to use everything from inside of here so imagine all of this is just copy and paste it right
inside of player car the only thing we're doing differently here is we're defining image Inside of here and then it will be used inside of the initialization when we instantiate this car class okay that was a lot of big words but let's continue so I'm going to go here and say car actually go with player car is equal to player car like that now we need to pass to this a maximum velocity and a rotation velocity so for now I'm going to go with 44 uh feel free to change that to make it slower or
faster obviously the higher number the faster It will go and now let's just draw the car so inside of draw I'm now going to pass my player car so that means we need to now take player car and now we're going to say player undor car. draw and then inside of here now I'm going to take my py game. display. update I'm just going to put this right inside of the draw function so that everything related to drawing is contained in one one place okay so that should draw our car let's see if this is
working and Required one uh required missing one required position argument win uh okay player card. draw that would be right here so we just need to make sure we pass our window to the draw method so let's run this now and we got an eror uh blit rotate center missing two required positional arguments top left and angle of course I forgot those let's fix that so we need to pass the top left hand position now the top leftand position is actually going to be equal to the X and The Y of the car which we
haven't defined yet so we're going to do that now we're going to say self.x self.y is equal to self. startor position pause like that sorry and then inside of here we're going to say startor pause is equal to and then we're going to Define what the starting position should be so I'm just going to say actually let me just go look at my other code and see where I started it before I was starting it at 180 Uh was that right let's see 180 and 200 okay so go 180 and 200 okay so now our
self and x self.x and self.y is equal to the starting position which we've defined here and inside of here we now need to pass that so we're going to say self.x self.y and then we want to pass the angle and the angle is just going to be self. angle like that okay let's run this now and let's see what we get okay So there we go our car is now drawn here now let's just see if changing the angle actually does anything so let's go and make the angle 90 let's see where we go now
notice we are facing left perfect that's what we would expect okay now let's make the angle 180 we should be upside down now and there we go so we are getting the car in the correct position sweet so let's make that back to zero and now let's make it so we can change the angle based on Pressing a key so we're going to go and I'm going to write the following inside of my main event Loop remember anything in the event Loop is kind of handling events handling Collision handling all of those types of things
so this is where we would put you know key presses and moving the car so I'm going to say keys is equal to py game. key. getor pressed like that and then what I want to do is check if we pressed a specific key so I'm going to say if keys and then I'm going to go pame dok notice that's a capital underscore and then a so I want to use WD to move my car so this would be left if I'm pressing on the a key so if I'm doing that then I want to
say player car. rotate left is equal to True okay let's copy this and then let's go here and say if Keys pame Kore D so this would be right then I want to say right is equal to True okay so that should now allow us to actually rotate our car left and right by clicking on A and D if You're wondering how you find other Keys you can look them up uh there's a bunch of I guess these are called constants in P game but you also can just do kcore and then whatever the lowercase
letter is of the key that you want if you want like a space bar or something then you would go all capitals and you would go space same thing with like shift or enter or any of those keys if it's not just a standard character then it's usually in all capitals okay let's run This though and let's see if it works and now notice if I go left and right I can rotate my car and the speed at which I'm rotating my car is defined by that rotation velocity so you guys can mess around with
that but if you change the rotation velocity you'll notice you're rotating uh faster or slower okay that's great so we can now rotate the car off to a good start that's actually a pretty difficult thing to do so congratulate yourselves if you Made it through that now let's see how we can move the car forward so we have our self do velocity we have the maximum velocity we have the rotation velocity we have the angle the next thing we need is the acceleration because cars don't just instantly reach their top speed they take a few
seconds to get up to speed when you slam on the gas you are accelerating you're adding more Force to the tires you're going faster and then eventually you re reach kind of like a Terminal velocity which is what we're going to get to here so I'm going to say self. acceleration did I spell that correctly looks like I did is equal to 0.1 so this means every time that we are pressing down on I guess it's going to be the W key to go forward we're going to increase the velocity of our car by 0.1
let's call it pixels per second that's maybe the unit that we're going at if you want to accelerate slower then make This 0.05 right or if you want to go faster make it something like 0.2 anyways we have that now I want to define a method and I want to call this move uncore forward okay so Define move forward and inside of here I'm going to take self now all this is going to do is it's going to increase the velocity of my car based on the Exel ceration and if I'm already at the maximum
velocity it just won't do anything but it will move me forward so inside of here I'm going To say self. Vel is equal to I guess this is going to be the minimum uh yeah the minimum of self. Vel plus self. acceleration and self. maxcore velocity so what this is doing is saying okay well if self. Val is already at the maximum and we add self. acceleration we don't want to go faster than the maximum so we put self. Max Val here so if this is greater than this we just default to the maximum velocity
if it's not though then we will increase the speed of the Car by the acceleration remember the uh velocity starts at zero okay so that will increase our velocity now that's great but we actually want to move the car forward so to do that I'm going to make a new method called move I'm going to say Define move like this and inside of here after I increase the velocity I'm going to say self. move now the thing is inside of move I need to actually calculate what direction I'm going to move my car because if
I'm Angled to the right or I'm angled to the left then I need to move in that appropriate Direction I can't just go up or go right or go left so I'm going to start by just showing you how we move in One Direction so I guess one plane or one dimension and then I will show you how we can move in multiple Dimensions so move X and Y based on the direction of our car that's going to involve a little bit of trigonometry anyways inside of here I am going to say self.x Plus equals
self. velocity so we're just going to move to the right based on whatever our velocity is that's all we're going to do to start right now then we'll get more complex okay so now that we've done that we want to uh Implement another key press to move the car forward so I'm going to go here and say if Keys py game. keyw then player card dot move forward like that so now as we press down the W key we should increase Speed as soon as we get to the top speed we'll stay at that speed
and we'll move forward now remember we're not decreasing the velocity here so as soon as we hit the maximum speed we'll stay at that maximum speed even if we let go of the W key we'll keep going at the same speed I'll show you how we fix that in a second uh but just wanted to note that as we got in here okay so I've loaded now notice when I press W I move over to the right like that now I'm Going to stop as soon as I let go of the key but when I
press the key again I'll be moving at the maximum speed so that's it that's how you move One Direction right we just incremented the x of the car and that moved our car over okay that's great but we ideally would like to be able to move in two Dimensions so this is where I need to pull out uh the paint program and start showing you some trigonometry okay so I'm here in paint and I'm going to start describing the Trigonometry that we're going to use to actually move in the direction that we're facing this is
not trivial this is why I'm in paint now please go easy on me I am using my mouse so this is going to be really rough but it will give you kind of you know what you need it would give you the the basic visualization of this so the idea is we have some car let's say this is our car now if he's just moving this way all we have to do is move the y direction right if he's Facing completely up then we can just move that direction if he's facing completely to the right
or completely to the left any of these kind of polar coordinates here then we can just go in those directions right it's very easy we can just decrement the X increment the X decrement the Y increment the Y however what happens if we're moving on an angle like this well it is not so simple now to actually figure out how much we need to move this guy by because we can't Just move by the X and we can't just move by the Y we need to move by both of them we need to go some
amount up right and some amount to the right now first of all what are those amounts well if you said the amount is equal to whatever the velocity of the car is that's incorrect the reason for that is if my car has a heading like this like it's pointing this direction then the velocity that we have is in that direction right so let's say my velocity Is four well if that's the case then this is four that does not mean that my X is four and my Y is four in fact I need to use
this total velocity to determine how much X and how much y I need to go by so that my total velocity accumulates four because when I'm moving in two directions I'm moving well two ways and so I need to sum the velocities but it's not so it's not as easy as just adding them together to determine what the total velocity is going to be now in This way we're going to go in the opposite direction we're going to say the following we're going to say okay well this is like a right triangle right we want
to go some Direction X some direction y so let's say X and Y like that and then this is our total velocity right here now it turns out that we know this angle and if we know this angle we can actually figure out what Y and what x are by using trigonometry so there's a few very Popular equations way I remember them is the following we have so which is s and then we have uh c c ah like this so C and then we have TOA as well t o a now o stands for
opposite now this is relative to the angle that you're talking about so if I'm talking about this angle right here the opposite side is y so o h a uh those are all sides okay it's side lengths is what I'm talking about and S stand sign C stands for cosine and T stands for tangent anyways I have my Angle so the opposite side is this because that's kind of what the angle is like facing it's what it's looking at and the adjacent side is this it's X because that's what's beside the angle that's the way
you can think of it so if I want to solve for y here keep in mind I know my angle and I know my velocity then what I need to do is the following I need to set up my equation so I'm going to say that the S of theta is equal to my opposite over My hypotenuse now we know the angle and we know the hypotenuse so H is really V which is my velocity now let's just plug in four because we know the velocity is going to be four we'll say the maximum velocity
is four right so now we're solving for o and O is really equal to Y right because that's the opposite side and so what we do is we say that the S of theta which we can calculate we just take the sign of the angle multiplied by four because we need to to take the Division and multiply it on this side is equal to Y so the S of theta multiplied by our velocity gives us our displacement in y and then if we go to cosine here it's just going to be the other way around
we're just going to take the cosine and we're going to multiply that by our velocity and that is going to give us how much we have for displacement in X so just basic trigonometry but I wanted to walk you through that all right so hopefully that Is a decent enough explanation what we actually do in the code might differ a tiny bit just because of a few factors but this is the general idea of how we can solve kind of two components based on one velocity and an angle we're calculating the X and the Y
component that's what they're known as because this is we can kind of call this a vector right like this line right here if you know anything about physics you would call this a vector because we have A angle so we have a direction and we have a velocity or a magnitude and then we want to split it into its two components X and Y okay so let's get rid of that and let's implement this so let's go to our move method and now rather than moving just by the velocity we're going to do that kind
of an equation that we just did so the first thing I need to do is I need to convert my angle into radians this is because we use radians in most computer math Radians is just kind of a special way of calculating angles uh in case you're unfamiliar 360 is equal to 2 pi in radians and 180 is equal 2 pi okay you don't really need to know that but just figured I'd let you know so we're just going to say math. radians and then self. angle like that notice our angle is in degrees because
that's how we want to rotate it but then when we actually are looking for the components we need it in radians now let's calculate the Vertical displacement or the vertical velocity so we're going to say vertical is equal to and then this is going to be math Dot and I actually think this is going to be cosine for this math do cosine of radians multiplied by self. velocity and then we are going to say that the horizontal is equal to math. sign of radians multiplied by self. then I'm going to say self.y minus equals vertical
and self.x minus equals Horizontal now you can switch this to the plus sign and watch what happens but the reason we we need minus is because these are actually going to return to us in a lot of instances negative values and based on the way that we are angling our car and just kind of some other things we've done that I don't really want to get into too much we need to subtract rather than adding now if we're subtracting that means if this value is positive we're going to the left Right and if we are
uh and sorry and we're going up so we're going to the left and up which is the way that our angle is directing so that makes sense and then if this value is negative that means that we're going to be going to the right and we're going to be going down I mean respective to X and Y uh anyways let's just run our code here and see if this works and so let's do this and now notice I can move in whatever Direction my car is facing there you go So we are now moving our
car which I'm I'm going to call a success now the only thing we need to do here is we need to make it so our car slows down because as you saw let me actually run this again my car just instantly stops right if I let go of the key it just instantly stops that's not realistic our car is going to have momentum it's going to be moving and it's going to take some friction to slow the car down so we need some way to actually slow the car down When we're not pressing on the
key which is what we're going to do now so we're going to implement a method here on our car we're going to call this reduce undor speed we're just going to take in self now what we're going to do is reduce our speed by half of our acceleration that is because we can accelerate faster than we can slow down at least that's the logic that I'm going to use I'm not sure if that actually applies in the real world but that's Kind of what we're going to do here also just so that we don't slow
down super super quick because we can accelerate really quick anyways you'll see how this works as I get into this method now I just need to look at where I have this in my other code so that I don't mess this up too bad okay so we have reduced speed what we're going to do inside of here is say self. Vel is equal to the maximum of self dovel minus self. acceleration over two and then this is Going to be zero now the reason we have this is because if this value for some reason is
negative we don't want to be moving backwards we just want to stop and so that's why we have the zero right here so we change the velocity and then since we have this move method already set up we can just say self. move so now when we reduce the speed all that's happening is we're reducing the velocity by half of the acceleration and then we're just going to move and since This is set up it'll just work it's just going to move us slower in whatever direction we're facing and while we're slowing down if we're
not on the gas we can still turn which is a very important thing to keep in mind okay so now we have reduced speed so what we're going to do is go inside of here and we're just going to do something I'm going to say moved is equal to false and inside of here I'm going to say moved is equal to True now the point of this is that if we are pressing the W key we don't want to reduce the speed but if we let go of the W speed or W Speed The W
key we do want to reduce the speed so now I'm going to say if not moved so if I didn't press forward on the gas reduce my speed so I'm just going to say not self we'll go with player car and this will be do reduce underscore speed so now you should see that when I'm not pressing on the gas I'm not pressing on the W key we Should reduce the speed so let's run this code and let's see what we get so now notice that we slow down right and it takes a second to
slow down I'm pressing the key I let go of the key and we continue going and then we slow down until eventually we stop all right so with that said this long video is now over if you guys had the patience to sit through all of this give yourself a pat on the back and not expect it to be this long but there is a lot of stuff that Goes into moving a car in this fashion in the next video we're going to set up the actual collision with the the track we're going to make
it so you bounce off of the track we'll then add a Finish Line and we'll make it so that you can hit the finish line and collide with the visil lent so we'll just be doing Collision pretty much in the next tutorial then after that we will implement the computer car so moving around a path which is also not that Easy to do and then I guess we'll do four videos for this series and in the last video we'll Implement all of the nice stuff like the text showing the kind of the stats the level
system all of that fun stuff so I am back with video two in this series in this video we're going to be talking about collision and handling Pixel Perfect Collision actually anyways first thing I want to do is actually make it so our car can move backwards because well we Didn't do that in the last video and I meant to show that so let's do that now so to move backwards is very easy in fact it's the exact same as moving forwards except we just need to modify uh the velocity and everything a little bit
so we're going to go and make another method here and this is going to be called move backward and inside of here we're going to say self Dov is equal to the maximum of and this is going to be self do velocity Minus self. acceleration when we move backwards we need to subtract the acceleration because we're trying to go in the opposite direction so we want a negative velocity to be moving backwards because it's like the reverse gear in your car you don't turn around to go backwards you can just rotate the wheels in the
other direction which is what we're going to do here and then this needs to be self. maxvel over two I don't know why I deleted that the idea Of this is that we want sorry this needs to be negative is that we want the the uh maximum possible negative velocity to be half of the Velocity going forward the reverse gear in your car you cannot go up to 100 miles hour right you can only go a certain speed there's a top speed in that so same thing here we're going to make it so when you
go in reverse you are going slower than when you are going forward uh I don't know why that's super important but that's What we're doing so self do velocity minus self do acceleration and then negative self dot Max velocity over two just splitting that in half I think that's pretty self-explanatory let's now make it so we have a uh key that does that so we're just going to copy this and I'm just going to change this now to key this is going to be s s will go backwards and then we will change this to
be backward like that notice I have moved equals true we need that to make Sure we don't reduce our speed as we are going backwards perfect now that we have that let's run the code and let's check if the reverse gear works so now I can move backwards and notice I cannot go backwards at the same speed that I can go forwards right I go at half the speed great there you go backwards is working if you try to turn when you're going backwards you'll notice that the Turning Works and you actually should be turning
in the inverse Direction which is Correct and that's why we set up all this stuff so that it just works when we add other things in the future great so what I want to do is just clean up the code a little bit here I want to take all of this stuff so Keys moved all of the stuff related to moving my uh player and I want to make a function here and I'm going to call this move undor player now inside of here uh we will just take the player car so we'll say player
car like that and then we can perform all of This stuff simply using player car okay so again just trying to clean this up so now inside of here I'm going to say move undor player and I'm going to pass my player car and this will handle all of the movement let me just get rid of that let's run this and let's make sure it's still working and it is we are all good okay one more small refactor I want to do is I just want to go and grab this reduce speed method here and
put this inside of my car class reason being that My computer which is going to inherit from this abstract car class as well does not need to be able to reduce its speed it's going to be the same speed the whole time and so it makes sense to have this in the class where it's actually going to be used because it's not going to be used by anything else that implements the abstract car class uh you could leave it in there there's Arguments for both but I am just going to move it here great so
everything will Continue to work we don't need to test that moving forward though the next thing I want to do is Collision so this is where we need to talk about masks and we need to talk about how you actually handle Collision of different objects in Python so what I'm going to do is open up paint here and we're going to start talking about masks all right so I'm inside of paint here and I'm going to explain to you masks and how we do Pixel Perfect Collision so let's start with Traditional collision and then we
can explain Pixel Perfect Collision so let's say we have some object and and let's just make it a circle for Simplicity now remember I told you that every single surface in P game is really a rectangle so even if this is all that we're showing we actually have a rectangle around this circle here so we might not see the rectangle and the reason we wouldn't see it is because all of these pixels here would be transparent pixels They wouldn't show up on the screen but they're still there it's still a rectangle so let's say we
have another image and let's just do it like this and maybe inside of here I don't know we have some green whatever okay this is what this image look looks like point being is that these two rectangles the rectangles containing these two images are overlapping this is the overlapping area right here however if we're looking at these two images remove the Rectangles they're not colliding with each other right the pixels that are present in both of the these images are not touching each other but if we were to use traditional Collision which is just rectangular
Collision you just check if two rectangles are lying inside of each other then it would say that these two objects are colliding and this is the overlapping area but again the pixels in the images are not actually colliding so how do we fix this because I don't want it to show me that two objects are colliding unless the pixels on the screen actually look like they are colliding this is where we use something known as a mask now what a mask is is an array of values representing whether or not a pixel in an image
is transparent or present whether it just exists it's not a transparent pixel now the point of a mask is that rather than performing rectangular Collision like this we can Simply check if pixels that are not transparent are overlapping into rectangular regions so let's clear all of this and now let's look at an example of a mask let's say we have a very simple image okay I'm going to just go with a rectangle because it's easier here and we have maybe something like this okay we have pixels all in here pixels all in here and then
inside of the other two regions is transparent okay and now we have another image and Let's just do something like this and maybe we only have pixels inside of this bottom left hand corner well the mask for these two images would look like this it's just going to be an array so we'd have a large array it's going to be a two-dimensional array and we would have 1 comma 0 okay and again excuse me I'm using the mouse here and then 0 comma 1 like that now for this image it would be similar but we're
going to have nothing in the first row because we have No non-transparent pixels and then we would go here and we would have 0 comma 1 like that okay now let's imagine these masks are directly on top of each other the two objects are completely on top of each other then what we would do is we would just compare values in these arrays and see if two ones are at the same position right so we check here say okay there's no one here so we're not colliding in this region okay then we go here so
okay there's no ones there so We're not colliding there we go here okay no ones we're not colliding and boom we find two ones which means we're colliding in this region right here and so we would say okay yes we are colliding because two pixels that are not transparent are touching each other there you go perfect that's all you need to know however it gets a little bit more complicated because we need to know the location of both of these masks before we can do this comparison in the Example I just showed you we just
imagine they were on top of each other so if I select this and I grab it it's going to be a bit rough but we imagine this mask was right on top of the other one and in that case it was really easy to check if they were colliding what if the mask is sitting somewhere like this or sitting here or sitting up here well we need to know that and that's known as the offset so we have something and actually let's make a new file here we Have something known as our calling mask and
then I guess the mask that it's being called on so let's say that this here is our calling mask and then this is the mask that this mask is being called on well we need to determine the difference between the top left hand coordinates so that we can overlap these masks in the appropriate region to determine if pixels are Collide so I want to calculate the displacement in X and the displacement in y so then I know The total displacement and then I can align these masks properly before I do the Collision so if this
is my calling mask and this is the mask that I want to find the offset on well I just need to find that I'll show you how we do that in code and then that's one of the values that we need to pass to kind of our Mass Collision function so that we can can overlap these masks in the correct area all right that's my explanation of masks hopefully that was Good enough for you now we are going to actually do this first thing we need to do though is create masks so so to do
this we're going to say trackcore bore mask now this is the whole point of having this track border is that we're going to use this border let's go to it quickly here as our mask this will be one mask and then we will compare this to the car our player car and we will see if these two masks are col iding with each other and this is actually Really easy to use because its corner is 0 0 right its top position is 0 0 which actually just makes it way simpler for us to do the
offset calculation so I'm not going to do scale image I'm going to do pame Dot and this is going to be mask. from surface and we're just going to pass in here the surface we want the mask of which is our track board easy enough that's how you get a mask okay so we have that mask now what I want to do is make a method in inside of my Abstract car class it will go inside of abstract car because this is going to be for both the computer and my player and I will call
this Collide now we're going to take in self mask x = 0 and yal 0 with the point being we are going to pass some other mask here we'll generate a mask for our own image we will then have the X and the Y of the other mask we obviously already have the X and the Y of the car we will determine if two masks are colliding in here so I'm going To start by saying carore mask is equal to py game. mask. from surface and this will be self. IMG so whatever image we're using
for this car then we are going to calculate the offset now the offset needs to be integer values so keep that in mind so I'm just going to say INT in like this and the reason we need that is because we could get some floating value when we do the subtraction but we need to calculate the offset X and the offset y now the offset Is relative to the calling mask in this case we're going to set say I guess Collision or actually go with POI which stands for point of intersection is equal to and
then this will be mask Dot and I believe this is called overlap of the car mask with the offset so we're going to use the other mask as the calling mask which is going to dictate how we calculate the overlap if we did it the other way we need to flip the over or the not the overlap the offset Sorry okay inside of int I'm going to say we're going to go with x minus self.x and Y minus self.y oras the other way around let's see of course I've done it incorrectly it's going to be
the other way around it's self.x minus X and self.y minus y okay so the reason why we're using this as our offset again is because the calling mask is the other mask that we're passing so we're going to take whatever our current X position is and whatever our current y position Is and we're going to subtract ract that from the X and the Y of the other mask now that will give us the displacement between the two masks if we did this the other way around that'd be fine but we would then have to swap
this and say the car mask is calling the uh the other mask okay so that's how that would work hopefully that makes a bit of sense the reason we're converting this to int again is because we need integer values for the offset we cannot have floating Points and our self.x and self.y can be floating Point values okay so now that we have that this is going to return to us the point of intersection between these two masks if there is one now we don't actually care what that point is at least not right now we're
just going to return the POI now what we can do to determine if two objects have have collided is we can see if the POI is equal to n or not if there is no POI the two objects didn't Collide if there was A POI then they did Collide so now we have Collide so I'm going to go inside of here and I'm going to check for this Collision so I'm going to say if and we're going to go carore player. Collide and we're going to do this with what mask was it this was going
to be the track border mask and notice that I don't actually need to passer an X and A Y here because the track border is positioned at 0 0 now we actually haven't even drawn the track Border but that's fine because we don't need to we don't need to draw the track border right now because we just know that it's going to going to be at the exact same position as where our current track is on the screen because the track border and the track are the exact same size they're pretty much the same image
except one is just the border the other is not so we don't need to draw it but we can still use the mask and we know its location is going to be 0 0 okay so We have that if player _ car. Collide track border we can say does not equal none there then what we can do right now is we can just print Collide and that way it's really easy for us to see if we actually have collided we can just look in our console and see if well we had a Collide so let's
run this and uh py game. surface object has no attribute overlap okay let me go here uh okay car mask P game. mask surface mask. overlap ah I realized what I did here I passed the track border when I meant to pass the track border mask okay so make sure you've actually passed the mask that was the point of creating it let's run this now and okay we're all good so now Watch What Happens when I go into the wall notice I get a bunch of collisions and then when I get off the wall it
stops for a second and if I go back to the wall it continues printing Collide now you can't really see it because it's my whole console is Filled with Collide but let's quit this and clear and run again and I'll show you let's turn and let's go here and then we get a bunch of collides as soon as we hit the wall okay so that is the idea behind the Collision that's really all you need to know for calculating Collision now that we have done that we need to do something when we hit the wall
we can't let our car drive through the wall so what I'm going to implement now is a Bounce so if you hit the wall you're going to bounce off the wall with the same velocity that you hit the wall with right I guess uh we could go into the laws of uh physics laws of physics Laws of Motion maybe is what it's called if you hit something with a certain velocity then you're going to go back in that same direction right just like when you throw a ball off of a wall it comes back and
you're going to lose a bit of velocity but point being you know law of Physics I want to explain more than that so inside of my player car I'm going to implement a method which is going to be bounce say Define bounce self now all I need to do inside of Bounce is I just need to reverse the velocity so I'm going to say self. Vel is equal to negative S.B now this will work if we're going backwards or forwards because if we're going backwards the velocity is already negative so this will then make it
positive so we go forward and if the Velocity is positive then it just makes it negative right and then of course we'll just say self. move so that we start moving as soon as we reverse the velocity so now all we need to do is here say self. bounce and now if we hit a wall We Just Bounce and sorry this is not self this is going to be player car so if we hit a wall we Collide We Just Bounce backwards and we'll go in the same well actually the complete opposite direction as the
one that we hit the Wall so we will continue in 1 second but I need to quickly thank the sponsor of this video and this series which is algo expert algo expert is the best platform to use when preparing for your software engineering coding interviews they have over 160 coding interview questions in many different categories they have heaps they have arrays they have links list everything that you could imagine and that you need to prepare for your software engineering interviews is Available at algoexpert check them out from the link in the description and use the
code Tech with Tim for a discount on the platform okay so now that we have that let's run the code and see if this is working and let's try it out and notice that I am bouncing off the walls there you go that is what I would expect now this is a little bit glitchy I won't lie this isn't always going to work perfectly every single time and you'll notice that sometimes you will kind of Hit a wall even though you don't really see a wall that's just because my image is kind of messed up
a little bit the way that I had it and so you might be hitting some pixels that you can't actually really see anyways this is working good enough for me I'm I'm happy with the bounds and so we're going to move on to the next thing okay so we have now handled the collision with our walls and you notice now that you can't go outside of those bounds because well You just can't right if you hit any of the walls then you're going to bounce back inside so now we need to make it so that
you can hit the Finish Line right so let's start drawing the finish line on the screen let's handle collision with the finish line but you'll notice that this is a little bit trickier than it seems because we have to know what direction we cross the finish line from because if the finish line is where we start right kind of starting line finish Line if we just drive directly backwards we can't say that we've won the race we have to hit it from the other direction so we have to handle that okay let's go here though
we have finish now let me see if I need to scale this uh rather than just messing around with it let's see if I did scale it in my uh my code previously looks like I did not scale it so that's good we can just leave it where it is but I do need to determine the position of the finish line so I'm Going to say finore position is equal to and I've already figured this out for you is going to be 130 and 250 so now let's just draw this in that position and let's
see what it looks like so I'm going to go to my images here and I'm going to add that as one of the images so I'm going to say finish I'm going to draw this at the finish uhor position like that so now let's run the code and let's see what we get notice the finish line is right here all right so there You go the finish line is up now this looks fine however we can see it is kind of overlapping with our track so what I'm going to do is just draw the track
border over top of this so that way we get rid of any of these edges that are being cut off so this is kind of a neat solution that we can go with here what I'm going to do is just add inside of my images here and make sure you do it after the finish line by the way otherwise it won't go over top of the Finish Line I'm going to say trackcore border and we'll just draw this at uh position 0 0 uh not 0 m0 0 make sure we add our last bracket there
and let's run this now and parth does not match did I mess something up okay that looks good all right so now let's see this and notice that now the finish line is no longer overlapping the reason for that is it is actually overlapping but we're just drawing over top of it just the Track border so that way everything looks good and then there you go our car is now moving around let's see if we bounce and we do sweet okay so that is good now that we have done that we want to handle colliding
with the finish line so now we're going to do another thing down here we're going to say if player car. Collide and now we need to get a uh uh sorry what is this a mask for the finish line so let's generate a mask for the Finish Line we'll do that from up Here where is the Finish Line right here okay we're going to say finore mask is equal two pame mask. from surface and then finish okay we now have the Finish mask mask so now we're going to say player card. Collide we're going to
go with finore mask and then we need to pass the finished position but with an asterisk what this does is split the tupple that is storing this position so X and Y into two individual coordinates and passes this to the uh the function As two arguments so if you do asteris finish position this is the same as passing 130 and 250 okay they're identical but I figured I would show this to you because it's interesting python syntax anyways we're going to say again if that is not equal to none then what we want to do
now is just print finish okay so now let's see if we can check for collision with the finish line so I'm just going to go backwards and notice we get a bunch of finishes And then if I go up here we get finishes again so the thing is as I was saying we don't want to be able to just drive backwards and say oh yeah you finished in fact if we drive backwards we don't want to be able to go past the Finish Line we should only be able to go forward on the track we
shouldn't be able to go backwards and cross the finish line so this is where I'm actually going to use the point of intersection to determine what direction I hit the finish line from so rather than just printing finish here I'm actually going to store this and I'm going to say finish POI Collide uh yeah I guess that makes sense finish point of Interest Collide is equal to that and then instead of all this we'll just say finish POI Collide and we will print out the Finish POI Collide okay so let's run this and now let's
go backwards and notice that we get a bunch of zeros as we're going Backwards right so if I keep going back here let's go back back back let's just go slow here notice all of these are Z 0 0 0 okay and then as soon as I guess the top of my car kind of gets to the middle of the finish line here we get some actual values for the y-coordinate so what we can do is we can just check if the y-coordinate of the point of intersection is zero and if it's zero that means
we hit it from the top so coming down if it's not that means we Hit it from the bottom and we actually finished meaning we went all the way around the track so let me show you what I mean we're going to say if the finished POI Collide at index one is equal to zero then car. bounce so just like when we hit the wall this is actually going to be player card. bounce we're just going to bounce meaning we're going to bounce ourselves kind of up I guess if we're going backwards trying to hit
the Finish Line let's run this Notice when I go backwards now I bounce forwards because I'm trying to cross the finish line from the wrong direction now let's go all the way around and this will take a second here but let's see if we bounce when we go from the other direction okay we got to slowly make our way through the track we can just test my driving skills here while I try to fill in the silence because there's nothing to talk about okay looks good so far maybe we need to increase the speed Of
this car for debugging because this this could take a long time if I leave it at the speed of four okay almost there last two bends here all right coming around and notice we only bounce when we hit the top of the Finish Line right like I can go onto the Finish Line like that it's only when I get to the top that I'm actually bouncing so that's exactly what we wanted now we can just Implement what happens if we cross the finish line from The correct direction so I'm just going to put in else
here because if we collided with the finish line but our y-coordinate was not zero that means we actually finished so in this case we will just print finish and I'll actually Implement kind of the Finish behavior in the next video but for now we can add a few more methods to our cars so I'm going to go to my abstract car class here and I'm just going to Define another meth and I'm going to call this Reset now what this is going to do is reset our car position so kind of preparing for the next
level right so all we'll do is we'll say self.x self.y is equal to self. startor position we then need to reset the angle so self. angle is equal to zero we need to say self. velocity is equal to zero as well and then is there anything else that we need to reset uh I don't think so let's see rotation velocity Max velocity nope that looks good to me uh We can just do that okay so now how about we say that if we cross the finish we'll reset the car we'll set player undor car. reset
I'm just going to increase the speed of my car so let's make this a speed of eight and we'll go with rotational velocity of eight as well just so that we can turn at the same speed we can move forward and let's run this and let's see if we go any faster okay so we can indeed go faster but we do have to wait to accelerate and Oh gosh that's a crazy bounce okay maybe we should make the bounce bounce a little less harsh and maybe the lower speed was was better oh my gosh okay
all right all right let's uh try to get around this B here okay yeah so I think the speed of eight maybe is is too fast uh we also could just try spawning the car right before the finish line that that would probably be easier too but you guys can just watch me struggle here okay let's Go and you're noticing that sometimes we're hitting like a wall That's not actually there again kind of unavoidable but as you saw there as I hit the Finish Line we spawned on top of the Finish Line we reset the
car and everything was good great so with that that pretty much covers everything I need to go through in this video I'm trying to think if there's anything else I can show you but I think for now that is fine in the next video we're going to implement the Computer car all right so the computer car moving around and as I said in the last video we'll do all of the kind of logic of starting the different levels moving the speed of the computer car faster uh you know that nice fancy text on the screen
and really making the game an actual playable game hello everybody and welcome to the third video in this pame car racing tutorial Series in this video I'll be implementing the computer car so we're going to set up a path for This car to follow along with and then we're going to make it follow the path which is much more complicated than it seems let's get started so the first thing I want to do here is make a class for my computer car so I'm going to say class uh computer car like that it's going to
inherit from abstract car and then inside of here I'm going to define the image for my car as well as the starting position so I'm going to say image is equal to and this will be the Green car and the starting position will be 150 okay that's pretty straightforward for the computer car next I'm going to override the initialization so I'm going to say Define a knit self this is going to be maxvel and rotation V uh is giving me that very good and then I'm also going to take in a path which is going
to be equal to an empty list by default then what I'm going to say is self do uh not self actually super doore uncore nit Uncore uncore and I'm going to pass the max velocity and the rotation Bel what this is going to do is use this method right here to initialize all the values that I need and then I'm just going to initialize a few more under here I'm going to say self. path is equal to path path is going to be a list of coordinates of points that I want my car to move
to and I'm going to say self. current point is equal to zero because I need to know what point in my path I'm Currently at then I'm going to say self. Vel is equal to the maximum velocity because my computer car we don't need to worry about acceleration it's just going to immediately start at the maximum velocity and we'll move at that speed the entire time okay now we have the computer C the next thing I want to do is just Implement a method on this C that can draw all of the points in the
path just because this will be useful for us to visualize so I'm going to say Define draw points and then I'm going to say self and we'll take in a window and I'm going to say for point in self. path I guess we could have called that points two but that's fine and then we will say py game do draw dot Circle and we'll draw this on our window we need to pass the color of our Circle which is going to be red so in P game theor are RGB so red green blue so 255
is full red zero green zero blue then I'm going to pass the point This is the going to be the center of the circle that I want to draw and then the radius uh will go with five so that means we're going to have a diameter of 10 for our Circle so that should draw all of the points for us that's pretty straightforward okay now we have draw points next I want to make some feature that allows us to actually kind of click on the screen and uh I guess draw create select all of the
points for our path so that way we don't have To manually add them inside of this path variable so you see what I mean in a second but first let's create a car let's go computer uncore car is equal to computer car we need to pass a maximum velocity and a rotation velocity so for now let's just go with 44 we'll match our player although we will reduce this later and then for the path we won't pass anything right now because we're going to kind of dynamically create the path okay so now we've made computer
car Let's draw it so let's pass computer car to our draw function and then let's go to draw let's take in computer car and let's do computer car. draw and inside of here let's draw on the window and then what we will do is we will override the draw method in here so we'll say Define draw self win we'll then say super. draw so we'll call the draw method from the abstract class here so we'll do this but before we do that we will draw all the points or after it Doesn't really matter but we'll
draw all the points so we'll say super. draw we need to pass the win and then we'll say self. draw points and the window so now when we draw our computer it will also draw all of the points in the path for this AI computer whatever okay there we go now that we have that let's just run the code and see if the computer's being drawn and then we will continue okay great so the computer car is there that's all we were looking for okay let Me clear the console here now let's continue so the
next thing I want to do is make it so we can click with the mouse and that adds a point to our computer's path and then we can get all of those points at the end of the program so that we don't have to manually write them this is pretty easy I'm going to go inside of my event Loop here so for event and py game. event doget I'm going to say if event. type equals equals pame dot uh this is going To be Mouse button down like that and what we're going to do is
get the position of the mouse we're going to say pause is equal to py game. mouse. getor pause and this will give us the XY coordinate of our Mouse on the pame screen then we will say computer car. path do append position so we'll add that position to the computer's path okay that's really all we need to do except at the end of our program we're just going to print out the computer Car. paath just so that we can copy it and then save it in our file and use it for future use so let's
run the code and let's see what we get here okay we get our computer car now let's start adding some points so I'm going to add one here going to add one here and I will just add all these and then once I'm done it will be right back okay so I've added all of my points here you can see this is kind of the path that I've defined I've tried to spread them out as much as Possible uh but it doesn't really matter I mean just add the points and make them on the track
and you'll be good you could put them off the track because we're not checking collision with the walls uh but obviously the better you make your points uh the better this is going to be now I recommend you do spread them out a bit if you make them too close you're going to see it's going to look like all jittery when we're kind of turning and angling towards them uh Anyways that's fine okay so let's close this and notice when I close this it prints out all the points so what I'm going to do is
copy all the points and I'm just going to make a variable at the top of my program here called path and I'm going to have it store all of these points just so that I can use this uh with my computer right with my computer car so now what I will do is I will actually go to where I initialize my computer and I will pass that path so now that will be set for my computer and then I'm going to get rid of this mouse button down logic because I no longer need that because
my path has been set so now that I have the path let's just run this and notice the path is still printing out it's you know saved right because I have it in a variable great and then of course my red car can continue to move just like it did before awesome so now that we have that what I want to do is Hop over to paint and I want to show you or discuss how we're actually going to kind of solve this problem of moving the computer car towards these points and it's pretty complicated
to do this but I will try my best to explain so let's say our Target point is right here and our computer is right here okay this our computer car so let's just go see this is car now the first thing that's kind of have to do here is to draw a line between the top left hand corner and the Point that we want to get to now we're going to be using the XY is the top leftand corner of our car so keep that in mind that is pretty important for this and anyways there
we go so we have our Target and we have uh you know our car now how do we get to this point well the first thing we can do is we can calculate the displacement in X and the displacement in y right so we know the velocity but we do not know the angle and so what we're actually going to want To look for here is the angle between our computer and this point if we know the angle then we can tilt our car to that angle and then we can move in that direction easier
said than done but that's the goal we want to find the angle between our car and the point that we want to get to and then we want to set the car so that it's facing that direction and then just move the car in the same way that we moved our player car because we already know how to move The player car right that part is done we've implemented that logic so anyways we have X and we have y now we can easily calculate X and Y because we know the coordinates of this point and
we know the coordinates of this point we would just take this Point's X subtract by this Point's X that gives us the displacement in X this Point's y subtract by this Point's y that gives us the displacement in y now it doesn't really matter if we get negative or Positive values uh we could take the absolute value if we want but doesn't matter if we get negative or positive okay finding the angle is still going to be the F the same sorry and then we have our velocity now the velocity don't really need to use
but we know the velocity is going to be the hypotenuse of the triangle okay that's fine so what we're trying to do here is determine the angle we know x y and V so there's multiple ways to do this now remember Our equations are so uh this is going to be an H let me erase that so C and then TOA now in this case it seems intuitive to me to use TOA because we know the opposite and we know the adjacent so what we can do if we want to solve for Theta which is
the angle that we're looking for is we can write the equation tan and then this is going to be of theta is equal to O over a now we can do our substitutions and when we do our substitutions we see that o is y and That a is X so we know X and Y those are two variables that we know so now we want to solve for Theta so any of you that know trigonometry know that we have to take the inverse tangent of this and then that will give us Theta so we can
say Theta is equal to and then tan inverse of Y overx and then that will give us the angle that we're looking for and in fact this is actually always going to give us what's known as An acute angle now an acute angle is any angle that's less than 90° now it will give us either a positive or negative acute angle so we could get a negative value here or a positive value here if we get a negative value here that's indicating to us that are looking to the left if we get a positive value
then to the right anyways that's not super important right now but just keep in mind that this is how you calculate Theta and that this is always going to Give us an acute angle that that is important it's always going to give us something based on the way we're doing this calculation that is less than 90° okay so now we have found the angle so we found the angle between our car and our point so it should be simple enough right just set the car at that angle well it's not quite that simple the reason
why it's not quite that simple is because of our car is like facing this direction and we want to go over here if I just set its angle to that it's going to look like it's just teleporting over that would be the easy solution just set the angle and then that'd be fine but if we do that what happens is first of all we're going to have our car facing the wrong direction a lot of times we're also going to have the car flipping instantly which we don't want we want it to kind of slowly
transition to that angle by its rotational velocity we don't want it to just teleport over and Face that direction so now comes the problem okay we know that angle we know the angle our car is currently facing how do we determine what direction to turn the car to get to that angle that's really the problem now we know the angle we know the angle of our car now we just need to actually make this car get to that angle so there's a few problems here again the first problem is that we need to make sure
we aren't just teleporting so we have to kind of decide Do we want to go to the left or do we want to go to the right now this might seem easy when you're looking at an angle like this but there's so many different angles we could possibly have and sometimes we could take the unoptimal approach if we only ever went to the left or only ever went to the right when trying to get to these angles so for example let's say we have this okay let's just move this over a bit let's say our
Target angle is here okay And our car is facing this way so car is black and the target angle is red now what way should we turn to get to this target angle well we should turn this way however we might end up turning this way so this is kind of the problem we need to figure out which way to turn now another problem that we're going to run into potentially here is that we might have the angle be here so let's imagine this guy is is gone okay we might have it be here now
Theoretically me turning like this is actually going to make it look like we have the same angle I know this seems really weird but the way that this angle is calculated means that this could actually be this or other way around we could get this angle from this so we need to kind of put in some checks here to ensure that if we're actually moving downwards we're actually going to go in the downward direction we're not going to mistakenly calculate this angle the Reason why this is a problem is because these two angles are the
same right if you look at this angle and you look at this angle they're the same and so when I do the tangent based on the way that I'm doing it I could get this when my point is down here and so I need to make sure that I'm actually looking at what direction my point is in if it's lower or higher than where I am and based on that I'm going to need to make an adjustment to the angle I get to ensure That I'm going the right direction so I'm just trying to kind
of point out some of the problems that you can run into doing this and there's all kinds of other problems as well for example right like I was saying we might go and try to go like this when instead it would be more efficient to go like this so if we ever have a very large angle we'll actually want to reduce that angle to a smaller yet equivalent angle so that we end up moving in the I guess best Direction the quickest direction to get to it I also realized that all of my lights turned
off here I'm just going to turn them back on uh I'm sure you guys can still see my face fine but I have like these background lights that for some reason went off okay so that that's a bit better uh okay anyways that was kind of the point of this I'm sure this hasn't cleared everything up I haven't necessarily stated the solution I just wanted to show you PR s that can happen And really the main problem is what direction do we do we go do we go left or right that's the main idea so
let's now start trying to implement this so we will continue in 1 second but I need to quickly thank the sponsor of this video and this series which is algo expert algo expert is the best platform to use when preparing for your software engineering coding interviews not only do they have a ton of coding interview practice questions they also have mock Interviews a data structures crash course and a bunch of other awesome features to help you prepare to land your dream software engineering job with that said check out algo expert from the link in the
description and use the code Tech with him for a discount on the platform I'm going to go into computer car and I'm just going to define a move method now this move method is special because when I'm moving I need to move towards a point so the first thing I Need to do is angle the car in the correct direction and if I am in the correct direction then I can start moving towards that point and we already know how to move we can just use the move method that we have inside of here right
if we're angled in the right direction and we're going by a a static velocity then that's fine so I need to look at my other code here because it's very easy to mess this up so inside of move what I'm going to do is just make Sure that we have a point to move to I'm going to say if the self. current point is greater than or equal to the Len of self. path then I'm going to return this is just going to ensure that we are not going to get an index error by trying
to move to a point that doesn't exist that that's the point of this line after after that I'm going to say self. calculate and this is going to be Angle now we will write this method in a second but this is going to calculate The angle and shift our car in that direction the next thing we're going to do is say self. update undor pathore point now what this is going to do is see if we need to move to the next point because as soon as we hit a point we collide with that point
we then move to the next one that's it and then here we're going to say super. move so we're going to actually call manually the move method that we're overriding inside of car okay So let's start by implementing calculate area or calculate angle I'm going to say Define calculate angle self the first thing I want to do is calculate the displacement in X and Y between the target point and my current position once I do that then I can find the angle between my car and the point and then I can adjust the position or
angle of my car accordingly to move towards that Target point so I'm going to say uh targetx Target Y is equal to and then This going to be self. path at the self. current Point Index this is getting our Target point then I'm going to calculate the difference in X I'm going to say the XD is equal to the Target xcore x minus the self.x then I'm going to say the Y diff is equal to the Target y minus the self.y now I don't care about the absolute value because my tangent function will actually handle
any negative values here and it can Potentially give me a negative angle uh we will handle the negative angles the negative angle is just you know going to I guess the right instead of the left or the left instead of the right doesn't really matter okay so now that I have both of these I'm just going to say if Yore diff is equal to zero then the the desired uncore radian underscore angle is equal to and I want to say 100 180 but I want this to be in radians uh sorry not 180 I want
this to be 90 and So in radians this is going to be math. Pi / 2 because math. Pi is 180° two uh two math. Pi is 360 so the reason for this is that if the Y difference is zero I need to manually set the angle because my equation involves a division of the Y difference and I can't have a zero division error so you'll see what I mean here I say else the desired radian angle is equal to and this is going to be the math. arc tangent so the inverse tangent of and
then this is going to be math dot No not math sorry this is going to be X diff over y diff okay so this is going to give me the angle that uh is between my car and between the point and then same thing here this will give me that angle so if we have no difference in y then that means that we're horizontal right we're either 90° or we're either 270° now in this we'll just make it at 90° because 90 and 270 are equivalent angles um not in Direction but in like the magnitude
of the angle if you divide Them hopefully that's making sense but we just need to avoid having an over zero so that's why I'm writing this line here okay now that we have that what I want to do is I want to kind of implement a clause here that's going to fix this angle slightly if a certain thing occurs I'm being very vague but let's just write it I'm going to say if the target _ Y is greater than so is lower down on the screen than self.y then what I want to do is say
the Desired radian angle plus equals and this is going to be math. Pi so the reason I'm doing this is kind of what I discussed before we can potentially have a problem where the angle that we calculate is it's always going to be an acute angle right and so if the Target that we're looking for is actually lower down on the screen than where our current car position is the turn that we need to make is more extreme than what the angle is that we're getting maybe We're getting an angle of 25° right and the
reason we're getting 25 is because 25 kind of spans this whole horizontal line and so we're looking at it like this but what we really want is to add a whole math. Pi add 180 de to it so that we go in the complete opposite direction of what the angle is that we calculated because we're going down because remember we're always going to get an acute angle so we're always going to be going kind of this way or this way so we Need to figure out if we need to go the opposite direction down now
in that case well the case is this if if Target Y is greater than self-thought y we're going down so we have to add math. pi to the angle to ensure that we're going to go the correct direction I'm sure this is confusing but that's really the best way that I can explain it I'm not a math professor and uh I don't want to get too much into it cuz I'm sure I'll butcher the the mathematical explanations of the Angles anyways there we go okay so that's kind of the first thing that we need to
do now that we have that though we're going to say the difference in angles is or just angle actually is equal to self. angle minus and then the desired radian Angle now we need to First convert this to degrees so we're going to say math do degrees like this okay so remember this is going to give us the angle in radians so then we convert it to degrees and then we take Whatever our current angle is and subtract it by whatever the design desired angle is to get to and then based on if this number
is positive or negative we're going to know if we have to move left or right now another problem happens here what if the difference in these angles is really massive what if it's 270° what if it's 290° in fact what if it's anything larger than 180° well if the difference in the angle Is larger than 180° we are going to be taking an inefficient route to get to the angle so let me show you what I mean if I go to paint here and we zoom in so let's go come on zoom in control plus
does that not zoom okay let's just move this okay so let's say we have this example here right where we have some angle here and actually let's just do one here then we have another angle here now if we calculate the distance between this Angle or the difference between these angles maybe we get something like 220° okay that's fine but if we were to go in this direction to get to this angle we need to travel 220° whereas if we go in this direction to get to this angle then we have to only go 140°
uh is 140° correct yeah 360 yeah 140 I think that's right okay so we only have to go 140 degrees so obviously we would prefer to go 140° than to go 220 so what are we going to do if we have an angle that's greater than 180° well if we have an angle greater than 180 we know we're taking an inefficient route so all we'll do is we'll take this angle and we'll subtract so let's say it's 220 we'll subtract 360 from it now you might be saying well why don't you do the other way
the reason I'm not doing it the other way is because I want to actually get the negative angle by going backwards so if I have 220 by uh Minus 360 then what I'm going to get here is 140 which is what I want because I don't want to go 140 degrees this way I want to go the other direction 140° so that is how I'm going to kind of fix this problem of potentially turning the wrong direction is I'm going to simplify this or I'm going to do this this check to make sure we're going
in the the right direction okay so anyways we have the difference in angle and now we're going to say if the difference in angle Is greater than or equal to 180° and we're just going to say the difference in angle minus equals 360 so now we will turn the opposite direction so now that we have calculated the difference in the angles we don't even care what the difference is well we actually we'll use in a second but we just want to move in the right direction now to get towards the angle that we want so
we're going to say if the difference in angle is greater than zero so if the difference In angle is greater than zero notice we're having our angle first and then the angle that we want to get to we want to go the other way we need to go to I guess the right as opposed to the left and the reason for that is when we go to the left we increase our angle if our angle is already greater than the angle that we desire we need to go the opposite direction to get to that angle
so we're going to say self Dot and then angle is going to be minus equals and This is going to be the actually let me check here the minimum of self. rotation velocity and then the absolute value of the difference in the angle let me check that that's all good okay yeah that's what we want so the reason for this is that I don't want to potentially pass the angle going the other direction so let's say the difference in the angle 3° and my rotational velocity is 4° if I just straight up go 4° to
the right I'm going To pass by the angle that I want and then what's going to happen is I'm going to pass by it and now all of a sudden I'm going to be one Dee less than the angle that I want and so I'm going to have to move back the other way but I can only move by my rotational velocity so I'm going to move back by that so what's going to happen is you're going to be like shut you're going to be like stuttering back and forth like left right left right which
you don't want You want to just be you know steadily on the angle so the point of this kind of Min right here is that if the difference in the angle is less than the rotational velocity we'll move by that amount so we snap precisely on the angle we aren't going like above the angle below the angle above the angle below the angle that's that's the point okay so now that we have this we're just going to say else because if it's not greater than zero then it must be less than or equal To zero
and here we're just going to swap this to a plus now I think we can just leave the exact same thing in here yeah we can and that should actually be good that will actually rotate our car so that it's going to move towards the point so that is kind of the trickiest part right there um this very complicated method I'm sure this doesn't make 100% sense doesn't have to if I'm being honest with you I don't understand it 100% this was a lot of trial and Error to get this to work but hopefully what
I explained giv you some sense of why we're doing the things that we're doing angles are difficult that's the the moral of the story and of this tutorial series okay continue now that we have that what I would like to do is I would like to make sure that we move to the next point in our path when we are ready to do that so I'm going to say Define update uncore path Point like that and Then inside of here all I'm going to do is check for collision with the points that we have so
whatever point I'm currently on I'm going to see if my car has collided with it and if it has collided with it then I've hit that point we can go on to the next one so let me just look at my cheat sheet right here okay that looks good I'm going to say the target is equal to and this is going to be self. path at self. current point I'm then going to create a Rectangle from my car yeah that's what we're going to do we're going to say w is equal to P game Dot
and then this is going to be I guess it's just wrecked yeah I think it is just w p game. rect and then we're going to instead of doing Target we're going to say self.x self.y and and then we need to get the width and the height of our image so I'm going to say self. IMG doget width and self. IMG dogor hey so the point of creating this rectangle is that my image alone is A rectangle but it doesn't know its location right like the image doesn't know where it is so I make a
rectangle using the X and the Y of my car as the top leftand corner and then I get the width and the height of my image so now what I can do is use a built-in method in Python in pi game story to determine if a point is colliding with my rectangle now this is pretty intuitive but it is Collide Point like this and all it does is take a point so you have To call this on a rectangle but it takes a point which will be Target and tells you if you are colliding with
it now in fact it actually takes a x and y coordinate so what I'm going to do is pass asterisk Target which will then pass the x coordinate and the y-coordinate as separate arguments to this function if that's the case if I am colliding with that point I'm going to say self. current point plus equals 1 so if we've hit the current Point that we're going to then let's move to the next Point that's the idea behind update path point now let me just look and see if I've messed anything up everything looks good to
me what we can actually do now is we can start running the car like moving the car around and you will see that it will start moving on the path so let's see how to do that again I have to reference my code here okay it was easier than I thought we're just going to say computer car. move Okay so just like we have move player now we have the move car so let's do that uh let's run our code after we move our car Let's cross our fingers and let's pray this works and notice
our car is zipping around the screen here and it's actually following these points okay now you will notice that sometimes it might kind of Hit the edge right so you just saw right there it almost hit the edge of the screen uh keep in mind that it is aiming to get its top leftand Corner on all of these points so that's why it's taking these kind of wide turns you'll notice that the top leftand corner of the car is what's kind of aiming to intersect with some of these points okay so we just ran into
a problem there with this point right here so that is most likely due to the fact that that point was too close to this one right here and so we couldn't actually hit this point we couldn't intersect this point from this one Because we couldn't turn quickly enough so what I'm going to do is kind of fix up some of these points and then I'll be right back uh notice we're getting another problem here so in fact let me just look at this and see maybe where I made a mistake and I'll be right back
so the problem is what I expected the points that I have are just too close together so the car can't actually hit it now that will be fixed by lowering the velocity of the car because it can Turn quicker than it can move but to fix this we just have to remake the path so I'm just going to remake the path I'll be right back I'll show you the new path and then hopefully we should just be all good all right so I've just recreated the path here now I'm not going to lie it's not
perfect perfect it goes off the screen a few times not very badly but anyways point being I recreated the path you guys know how to make the path I showed you the code to do that it's Pretty straightforward so you can mess with it and design as many times as you need to now based on the way we have it right now if you just clear the path at the start and then you add uh values to the path the car will actually follow up until the last value in the path that's the way that
we've designed it so every time I was clicking it was actually going to that point which was kind of cool you could see how it kind of traced the path in real time now one of the big Reasons why it's hard for the car to actually hit some of the points is because of the turning radius right if you increase the uh rotational velocity then you won't have the same problem that I'm having here just because it needs to take kind of a wide turn to be able to get to some of the points now
that's going to change with speed so you have to be careful if you have a lower speed than your rotational velocity um it's not necessarily higher but you can Just turn more because you're not moving as quickly to each point anyways I just wanted to point that out okay so now I have this New Path so I'm just going to copy that into this path variable here so let's get rid of all that let's paste that and now let's repass path uh where is it right here so I'll just show you what I had was
I just added this code back in and that's how I was able to recreate the path and then I had just cleared the Path uh previously okay all right so now that we have all of that that our computer is going against the player so what I want to do now is get rid of the drawing of the path so I'm just going to go and comment out under draw this self. draw points because I don't want to do that anymore and I want to implement some collision between the computer and the Finish Line just
so I know if the computer gets the Finish Line first and then in the next video we'll Implement All of the level stuff uh but this will just be kind of a nice thing to finish off right now okay so just like we have this the fin POI Collide I want to go player underscore and I just want to preface this all with player because I'm going to do the exact same thing now except with the computer although with the computer I know it's not going to hit the Finish Line in the wrong direction so
all I have to do is just see if it hit the finish line and then I Know it crossed in the right direction so I'm going to copy this and I'll put it actually above here and we can go like this and instead of player we'll just say computer and then we will just change the player to be computer car and now this will tell us if the computer has hit the finish line so I can just do an if statement here and I can say if the computer car um computer Uncore finore Poore Collide
does not equal none and then I can print out computer wins exclamation point because in this case the computer would have gotten there before the player now we do need to reset both the player and the computer if the computer does win so I'm going to say player card. reset and computer car. reset and that reminds me inside of here I also need to say computer car do reset because now if the player gets to the Finish Line we need To reset the computer as well okay we can get rid of the print statement I'm
not going to test this because I'm just very confident this is going to work what I'm going to do now is take all of this Collision code and I'm just going to put it in a function again just to kind of clean things up so I'm going to say Define handle Collision now we want to take both the computer car and the player car So I'm going to say player car and computer car like that now inside of here we'll do all of this and then we can just call that function so I'll say handle
collision and then we'll pass the player car and the computer car and let's just run this here and let's test and see yep okay I can hit the walls just like I was before great so there we go that is all working and with that that's going to end this video so we're getting very close to finished here we Just haven't implemented the logic for the game and the nice text so in the next video we'll do all of that but this is the hard stuff what we're doing going forward is very simple we just
need to keep track of what level we're on we just need to reset the cars in you know the correct way and yeah all that stuff is pretty easy so we'll wrap that up in the next video hello everybody and welome welcome to video 4 in this pame tutorial Series in this video I'm going To be adding the finishing touches to this game making it a fully functioning game we have now implemented all of the physics and the logic to allow the players to move but we need something that tells us if we won if
we lost what level we're on all of that kind of stuff so that is what we will do now before I go any further though if you have made it this far give yourself a pat on the back and go leave a comment let me know what you've thought of the series so far Any feedback positive or negative is more than appreciated all right let's continue and let's get into this so we need to know levels that is kind of the first thing we need here the reason we need levels is because the computer is
going to start off very slow and then it's going to get faster and faster and it's going to determine its speed by the level so what I'm going to do is make a class here and we're going to call this class game info now this is going to be Responsible for exactly what it says the information about the game you're going to see why it's beneficial to do it in this way but rather than creating like 20 variables to keep track of all the stuff that we want we'll just do it in this class and
then it makes our code very very readable so I'm just going to say levels is equal to 10 so it'll be a constant we're going to have 10 levels in this game if you wanted more well then you can increment this then I'm Going to say Define a nit underscore underscore and I'm going to say self and then level is equal to one this is just indicating that we're starting at level one okay then we're going to say self. level is equal to level we're going to say self. started is equal to false indicating whether
or not the current level has started we're going to say self. levore startor time is equal to none the reason that we're doing this is actually We'll do it at zero sorry uh is because we want to know how much time has elapsed in the current level that's something that we're going to do in here okay so now we're going to say Define and we're going to implement some uh methods we're going to say Define Next Level now what this is going to do is say self. level and then plus equals 1 and it's going
to say self. started is equal to false because if we're going to the next Level then we don't want to start the next level yet we need to wait for the user to do that then we're going to say Define and this is going to be reset now inside of reset we're just going to reset everything so we're going to say self. Lev is equal to one we're going to say self. started is equal to false and then self. level start time is equal to zero as well I think that's all we need to do
then we're going to say Define Gamecore finished we have to spell finished correctly this will take in self and this will simply return self. level is greater than self. levels so if the current level is greater G than however many levels we have then we have finished the game and then we'll say Define and this is going to be startor level now all this is going to do is it's going to say self. started equals true and it's going to say self. level start time is equal to Time.time so that's why we imported time previously
here I'll go back to this so that you can read it but the idea is we want to keep track of when the level started and then we can easily determine how much time has elapsed by checking the current time and subtracting it from this okay and then lastly we're going to say Define getor levelor time self and here we're just going to say if not self. started then return zero so if you Haven't started the level then no time has elapsed otherwise we will return self. Lev start time minus time.time okay I went through
that relatively quickly but that is the game info class you can almost see all of it right there pretty straightforward pretty simple but it's just going to make our life easier as we go through this okay so now that we have that what I want to do is kind of make something pop up on the screen when we first start The game that says like press any key to begin level right so every time a new level happens I want to say like press any key on the keyboard to start the level that's all I
want to do so the way I'm going to do that is I'm going to go right after my draw here I'm actually going to put another wall Loop now this wall Loop is going to wait until the level starts and once the level starts it will get out of it and then allow all of this stuff to happen so you won't be Able to move the car the computer won't move until we start the level so let me just go down here so I have a reference on my other screen and this is what we're
going to do while not and then this is going to be gameinfo do started now we need to Define game info so I'm going to say gamecore info is equal to game info like that and while not gameinfo do started so we not started the current level we are going to blit some text onto the Screen so I'm going to say win actually I'm going to do something else which I'm going to describe now so what I want to do is write a function that is capable of writing any text onto the screen directly in
the center of the screen it's a very useful function to have so to do this we first need to Define what's known as a font so if you want to write text onto the screen in pame you need a font so what you're going to do is at the top of your program you need To make sure you do this at the very top you can say py game. font. init you know obviously after you import pame then what I'm going to do is I'm going to actually Define a font object this font object is
what you can then use to render text with that font so I'm going to say mainor font is equal to py game. font .s font not system font just Sy font and then inside of here there's a bunch of options but you guys know that I always Go with comic Sands and then you can put the size and for now I'm going to go with 44 now this is the text size change this obviously to whatever you want 44 is a good size though for like some title text which is what we're going to have
okay so now we have our font this will only work if you initialize the font so if you're having an issue just make sure you init the font first and now that we have the font we can use that to render some text so I'm going to Go in utils.py I'm going to make a new function I'm going to say Define and then this is going to be bitor textor Center and this is going to take in a window it's going to take in a font and it's going to take in some text all right
so inside of here I'm going to say render is equal to font. render and then we're going to put the text that we want to render the anti-aliasing which is one and then we're going to put the Color which is going to be white so 255 255 255 and in fact uh let's make it let's go with like 200 200 200 just so it's gray because we have white on the screen already actually is this going to give me white I'm not sure what this color is going to be you know what we'll experiment with
200 200 200 and we'll see what that gives us in case you're curious uh you just put text you want to render you put anti-aliasing just always put one for this I won't Really explain it just you always want one here and then you're going to put the color and then you can actually blit this text onto the screen just like an image say wind. blit render and then we need to put the position we want to render this at the top leftand corner by the way that's where you're putting here so what I want
to do is I want to render this at the win. getor width uh why did they fill all of that in okay that's fine divided by two and then this is Going to be subtracted by and this is going to be the render _ width over two so what this is doing is let's go to paint and I will show you so let's say we have our window okay we obviously have some width and we have some height and then we have the text that we want to render and I want my text to be
here now I need to calculate this position not this this would be easy enough I just take width over two I want this so the way you do it is the following this Is width over two right W over two so you subtract from this half of the text width pretty straightforward but if you just subtract half of the text width from half of the screen width you get the top leftand Corner position of where the text should be drawn from so that it's going to fill the entire screen and be directly in the center
like that now you can just do the exact same thing in the height and well that will give you the coordinate for y that you want this To be at right so it would give you it you know around here okay uh actually it would be probably close to around where I have it right now hopefully that makes sense but that's my quick paint explanation and let's go here wind. getor height over two minus uh render doog get getor height over two okay so it filled that in for me that is great so that's going
to render my text on the screen in the middle we're going to use that a few times that's why I wrote that Now we want to import that so from utils import blit uh text Center and then we're going to go down to our where were we our while loop inside of here and we are going to render this so we are going to say blit text Center like that and we're going to make an F string only available in Python version 3.6 and above by the way I'm going to say press any key to
start level and then inside of here I'm going to say game info. level exclamation point okay now that's The text that's actually the last last thing that we're going to pass the first thing is win the second thing is our font which is main font and then our text if you're unfamiliar with FST strings the way they work is you can embed Expressions directly inside of curly braces you just put a lowercase or uppercase F before the string so now whatever the level is we'll say press any key to start level one two three so
on and so forth okay now win needs to be Capital forgot about that and now that we have blit that text onto the screen what I'm going to do is do an event Loop I'm going to say for event imp game. event doget I'm going to actually copy this seems inefficient to rewrite this but it's simpler than trying to come up with a cleaner way essentially and I'm going to still have this kind of quit Clause except instead of run equals false I'm just going to say py game. quit Okay and then here I'm going
to say If event. type equals equals pame do key down this means you pressed any key down then what I'm going to do is say game info. start level so we're going to call that start level method that will start the current level which means this while loop will now exit and then we will go on and well we will have the level now I'm wondering if I'm missing anything I am the one thing I'm missing is I need to manually update this display here so py game. Display. update to ensure I actually show this
because we're going to be skipping this draw function hopefully that kind of makes sense but we're drawing everything right and then we have this wall Loop and this is only going to run if we haven't started the current level so if we haven't started the current level we put this text over top of everything in the middle of the screen and then as soon as they press the key down we're going to exit out of This wall Loop and then start the game and the current level will start and then if I go here let's
just make sure start level looks good inside of this class okay all good so let's run the code and see what we get okay notice says press any key to start level one maybe we want to move it up a tiny bit because it's kind of hard to read when it's over top of the white but for me that's fine press any key and then notice the car starts going and we Can start moving all right there you go so that is how we start the current level so we will continue in 1 second I
need to quickly thank the sponsor of this video and this series which is Alo expert algo expert is the best platform to use from preparing for your software engineering coding interviews they have over 160 coding interview practice Quest questions mock interviews a data structures crash course all kinds of other great features of course I am an Instructor on the platform so you know there's going to be some quality content and well with that said you can check them out from the link in the description and use the code Tech with for a discount on the
platform now that we have that I just want some text in the bottom leftand corner displaying the current level displaying your current velocity and displaying the amount of time elapsed in the level which is actually pretty easy to do so inside of The draw function now what I'm going to do is also take in my game info so now I'm going to go inside of draw and I'm going to start rendering some text and drawing some stats onto the screen so let me go to my code here just so that this will be a bit
faster for me to code out and I'm going to start by saying that my level text let's go like this levelor text is equal to and then this is going to be main font. render and I want this to say level and then game in Info do level like that and then I want the anti-aliasing one and the color of white 255 255 255 okay now I'm going to render My Level text so I'm going to say not render sorry I'm going to display it on the screen window blit level text and then where do
I want this I'm just going to tell you the position but you can feel free to uh to mess with it all you want I'm going to say 10 and then I'm Going to say height minus and this is going to be level text. getor height minus 70 this is because we're going to put two other things below this now the reason I'm doing this is so that it's Dynamic so if I ever decide to change the height of my screen then I don't need to change this right here because it's based on the height
of the screen which is height and the height of whatever this text is here so again if I change the height or sorry The size of the text I won't need to modify anything this will just automatically adjust itself and put it in put itself in the bottom left hand corner Okay so I'm just going to copy this now because we're going to do the same thing for velocity and time so I'm going to say time text time text and this will be time text like that the minus here is going to be 40 because
we're going to have 30 pixels offset that is something that we Manually would have to update but that's fine and then here I'm going to say time colon and it's going to be equal to game info. get level time like that okay that looks good to me now let's copy this and we're going to do the same now with our player velocity just so we can see how quick it's going I just figured that would be a cool stat to add so now we're going to say Vel and then this actually let's add a second
here too let's add an S just so it says seconds uh but for Velocity I'm going to go with uh this is going to be player car. velocity and then we'll go with PX per second standing for pixels per second just so we have some unit there we'll go with white again now instead of time text this is going to be called Vel text so we'll just change these all to be Vel so this is going to be V and then rather than minus 40 we're going to go minus 10 so 70 40 10 the
pattern is 30 less every time all right there we go That's it for drawing that text on the screen now let's run the code and let's see what we get uh draw takes four positional arguments but five were given good call I forgot to import my game info or to add this as a parameter so do that and now we should be good remember I passed game info into the draw function here okay let's run the code and notice that now we get level one time 0 seconds velocity 0 pixels and when I start this
now notice we have our Time now that's kind of ugly and it's negative which means I messed something up so we're going to have to fix that in a second but then you can see the velocity gets updated here as well great so that's fine but what I want to do is I want to round first of all the velocity so let's do that let's go to my velocity and let's just round this to one significant digit so round and then comma one and then let's go to our game info class here and let's see
where I Messed up so I did self. level start time minus time.time the reason this is incorrect is because time.time is going to be after the start time so I need to flip this around and say time.time minus that and then I will as well round this but I'm just going to round this uh to zero places so just do a whole number because this is going to give me the displacement in seconds or the difference in seconds okay so let's run this now and let's see what we get and Now notice that the velocity
is all good and so is the time perfect there you go okay so that's all we need for those stats okay so now that we have that we have the Velocity we have the time we have the level showing up what I need to do is make it so that my computer gets faster every time I beat a level so what we need to do is go inside of our computer car here and we need to write a method that's going to allow it to update its speed based on the current Level so I'm just
going to say Define nextore level and what we will do is say s now when we go to the next level what we need to do is reset this car now we could manually call reset outside but the first thing we'll do is say self. reset like that so that this is going to go to its start position it velocity is going to get updated all of that however after we reset the car we then need to change its velocity based on the level so I'm just going to say level inside of Here so we're
going to reset the car then we're going to say self dovel is equal to and then we'll go with whatever the self. maxvel is that was passed plus and then this is going to be level minus1 multiplied 0.2 now 0.2 is how much I want to increase the speed of this car every level we could put this in a variable I'm just going to hardcode it in for right now you also could Change this and make it something like 0.5 the one thing to keep in mind is you do not want this car to ever
be faster than the player car if it's faster than the player car there's no way the player will win it's just impossible because this car will take assuming you did a good path the best possible like line around the track and so there's no way the uh human's going to be able to beat it especially because it doesn't have to worry about acceleration it just starts At the maximum speed so you need to make sure that whatever you're incremented here is that that multiplied by the number of levels that you have plus the maximum velocity
you start with is not greater than the player speed you could make it the same but even if you make it the same then the player still can't win so this is fine I'm saying level minus one which means on the very last level I will have 9 multiplied by 0.2 so 1.8 so the speed will be 3.8 so it'll be 0.2 Slower than the player hopefully that is good let me just make sure that that all makes sense uh yes and then the last thing we need to do is say self. current point is
equal to zero although that should really go inside of the reset method so where is reset ah reset was in the abstract class okay so we can leave self. current Point here all right that should be good uh now we just need to see where we should call Next Level so what I'm going to do now is go to my Handle Collision handle Collision now needs to take game info as well and so when we call handle Collision we need to pass game info and now we're going to start kind of working on what happens
when the computer wins or when the player wins so if the computer finishes we are going to reset the player C reset the computer C that looks fine okay and now we here to when the player finishes well if the player finishes then rather than computer car. reset we're just Going to say computer car. Next Level and we're going to pass game info. level but first we're going to say game info Dot and then next level like that so we're going to increment the next level for game info if the player has won we're going
to reset the player car and then this will reset the computer car and change its speed for the next level so that should be good now by doing this it means that this will automatically trigger for the next level because the Game will now not have been started we'll be waiting for the next level to be started okay that's fine the only thing we need to handle now is if the computer wins so if the computer wins we need to put a message on the screen saying hey you know you lost whatever and then we
need to reset the game so we'll actually go game info. reset and before we do that let's just put some text on the screen so let's say blit text Center and then this Is going to be what do we want to say here you lost exclamation point and we'll do this on the window and we'll pass the main font okay then we need to manually this is going to be capital win like that we need to manually delay the game the reason we need to delay is so that we have time to see this text
because what's going to happen is we're going to show you lost we're going to delay for many seconds you want I'm going to go With 5 seconds and then as soon as that delay is done it's going to automatically restart the game for us so I'm going to say p game do time and then weight and you put milliseconds in here so 5,000 milliseconds is 5 seconds so we're going to do that okay that should be good uh the only other thing we need to handle is what happens if the player wins the game but
we're going to do that here so after we move the player and after we Move the computer and after we handle the C then we're going to say if the game info. game finished we want to do a very similar thing to what we just did here we want to reset all of this stuff so we'll do that and we want to blit text you won the game like that okay so that's actually all we need now I'm going to get rid of this print statement and I believe that we have just finished the game
Now obviously I'm not that confident because we have not tested it right now but scrolling through everything looks good and I think we've just handled everything that we needed to and I'm also realizing how much code we have here so again a massive props to you guys if you stuck around because this is a lot of code to digest over video all right let's run the file and let's see if we can win a level here okay let's press any key to start and never mind I Remember that the guy my computer did I start
him at a speed of two or did I start him at a higher speed let's see what speed he's at uh yeah it's at four okay so I need to put my computer car speed to two otherwise I'm going to have no chance here okay so let's round the code and let's see that's better okay so now let's try to get a win here and we'll see if the levels are working okay look at this driving skill Nice nice [Music] all right almost there see we can finish before the computer I'm hoping [Music] so and
there we go okay so level two and it says press any key to start level two okay so let's do level two let's just make sure it goes to level three and then I will kind of fast forward as I get to the final level and we'll make Sure that this actually works if the computer wins and if I win okay but let's just get through level two first though to ensure that we're going to get on to the next level okay almost there I forget what the time was on the last one I should
have kept track of that then I could have seen if we were going faster this time oops okay looks like there's an invisible wall there that's guess that's Going to happen and let's try to get up here and okay press an to start level three we're on level three so now what I'm going to do is let the computer win I'll fast forward through that assuming that works then we'll see and make sure that the game actually ends when we hit Level 10 all right so here we go home stretch of the computer you can
see I haven't really moved until now let's see what happens when the computer wins and nothing okay so that's actually A good thing to run into because oh it says press any key to start level one so I guess it lagged for a second uh okay let's see what the problem was here I'm guessing the problem has to okay this makes sense so what happened was we delayed for 5,000 seconds or 5,000 milliseconds so 5 seconds but we forgot to update the display to actually show this message so I have to say py game. display.
update and now this will work I'm not going to test it I know that This will work now and everything will be good because it did actually reset back to level one so with that I believe everything should be working uh I'm not actually going to go through and test the fact that the player wins works properly I have faith that I've coded this correctly especially because I have the finished code on my other side and these two pieces of code are identical although if for some reason it doesn't work please do let me know
I'm sure the Error is uh very easy to fix if there is one although I I doubt there is all right so with that said I'm going to end the video here I just quickly want to thank everyone who got through all of this I hope that you learned something from this I hope my explanations were decent enough for some of this complex code it is difficult to do a video where you know you have about 300 lines of code that's kind of what we ended up having here right tons of code lots of Code
in different files as well all kinds of classes all kinds of functions we used a lot of different python features so again hopefully you learned a lot and you enjoyed this video hello everybody and welcome to a brand new tutorial Series where we're going to be building the checkers game in Python with py game now if you don't know py game that's totally fine it's a module in Python that lets let us build 2D games what I'll be doing in this series Is walking you through everything that we need to do to build a full-fledged
checkers game now I'm actually quite excited about this because this is going to be leading me up to another series I'm going to be doing which is talking about the minia max algorithm to actually make an AI that we can play checkers against so let me give you kind of a demo of what this should look like I've already built the game out and I will be not necessarily copying from my Other screen but just having it up as a reference to make sure I don't get too lost you can see this is kind of
the game Checkers the human player is red and then the other player obviously is white and you can see that we have an AI so the AI will automatically move based on the move that you do so let's see if I leave myself open here the AI oh decided actually not to capture me because I would capture it back and if we play this for a few minutes I won't Go through all of it you'll notice that the AI is actually pretty decent uh and it actually can play pretty well against us so I'll be
talking about how we can build this kind of AI of course after we've built the game in a separate Series so stay tuned for that all right so that being said that's pretty much it all I want to say quickly is this is not a beginner tutorial series if you're an intermediate you've worked in Python before that's awesome I'm going to try My best to teach you guys some new more advanced stuff in this series so yes we will be going through and just building the game but I'll be kind of throwing in some more
Advanced Techniques and explaining how those work so you're definitely going to learn something other than just how to build Checkers if you want to follow along with this all right so let's go ahead and get started the first thing we need to do is just install a package this is called pame so We need pame again which is the module that we're going to use to do all of the graphics so what you can do is open up a command prompt or open up a terminal and what you need to do is type pip if
you're on Windows or pip 3 if you're on Linux or if you're on Mac so pip or pip 3 depending on your operating system and then the word install and then P game so of course you need to already have python installed on your system for this to work but type pip or pip 3 install py My game that should go through and install this you can see for me it was already installed it says defaulting to user installation blah blah blah we already have it installed anyways uh if this did not work for you
for some reason that probably means that pip is not in your system path so I will link a video in the description as well as I'll put a card in the corner here that will tell you how you can actually install and fix pip uh so follow along with that It won't be titled like how to fix pip but just trust me in that video it goes through and it explains how to actually fix pip okay so once we've done that and we've installed py game the first thing we're going to do is make a
new python file you can see I using VSS code for this tutorial series which is just the editor that we're going to use and let me just zoom in a bit so you guys can actually read what's going on uh but what we're Going to do is make a new python file I've named mine main.py and I'm putting that inside of this Checkers tutorial folder here and I'm simply going to type import py game like that and just make sure that this works so if you're working in vs code what you can do is install
the python extension so if you go to this extension tab right here it's on the leftand menu bar type python click here and install it then you'll be able to debug Python scripts you'll be Able to run Python scripts and everything should work out well for you so what I'm going to do here is just press this run button and this will simply run the current script that I'm on you can see that it says hello from pame and that means that everything is working and pame has been installed properly and we're good to get
started so what we're going to do here is we're actually going to try to build kind of a module around the checker game and then Add kind of like an API I don't want to use big words to confuse anyone but an application programming interface on top of the game so that we can use it with an AI later on so you'll see what I mean by that as we go through but what I'm going to do right now is just make a new folder inside of my Checkers folder and I'm just going to call
this one Checkers like this so inside of here what we're going to do is actually make a new file I'm going to call this uncore uncore Anitore underscore dop so two underscores and nit twocor dop What this will do is initialize this folder here as a package or a module or whatever you want to call it and that will allow us to actually import stuff directly from this package in kind of a special way uh which we'll be doing later on now what we're also going to do is do an underscore uncore nit uncore dopy
inside of our upper level directory so I have main do high a knit up high and then Checkers again that's inside of a folder right here um so it's inside of this Checkers tuto tutorial folder that I have open and once we've done that we can go back to the main.py script and now we can start actually writing a little bit of code so the first thing that I'm going to do here is I'm actually going to set up a pame display this is where we're actually going to be drawing everything onto then we're going
to set up like a basic event Loop and What that's going to do is check if we press the mouse or if we press a certain key or whatever we're doing it's going to check for that and then once we've set up the main Loop we can set up some basic drawing so essentially draw the board for the chessboard draw all the pieces all of that and then start getting into the actual logic of the game so the first thing I'm going to do is I'm going to say win in all capitals because this is
going to be a constant Value is win. display do set uncore mode and inside of here I'm going to type width and then comma height now these are going to be two fa two variables that we are going to Define and what I'm going to do now is go inside of this Checkers folder that we've created I'm going to make a another python file and I'm going to call this oops it's lowercase constants dop so what I'm going to do is I'm going to put all the constant values inside of this file here So if
we ever want to change anything we only need to go to one file and we can really quickly see all of the variables and we can change everything that we need to so inside of constant. py I'm going to import Pi game we'll use that later on and now what I'm going to do is say width comma height equals 800 comma 800 if you haven't seen this type of uh way of defining variables it just means width is equal to 800 and height is equal to 800 now you can Define this To be whatever you
want but just keep in mind if you change this value you're going to have to change a few other ones uh accordingly so just maybe leave it the same but this is 800 pixels High by 800 pixels wide next thing I'm going to do is to find the amount of rows and columns we're going to have in our chess board so or checkers board sorry so we're going to have 8 by 8 that is a standard checker board so I'm going to say 8 by8 like that and then what I'm Going to do is I'm
going to say Square uncore size so essentially how big is one square of our checker board and I'm going to make that equal to the width integer divided by the rows now we could uh as well do the height divided by The Columns or or sorry what am I doing width sorry this should be width divided by calls not uh it's not going to make a difference but makes more sense to do the width divided by the amount of columns rather than the width divided by The amount of rows so now we have a few
constants here width height row calls Square size while we're in this I'm just going to define a few variables for some different colors we're going to use so in pi game when we use colors they are red green and blue uh so RGB color codes so for red obviously we're going to do 255 comma 0 comma 0 this means we're going to fill the entire amount of red we're going to have zero green and zero blue and just so we know red green blue Goes up to 255 inclusively so you can use any value for
these uh between 0 and 255 next we're going to do white white is simply 255 255 255 and then we're going to do black which is equal to 0 0 0 and finally we're going to do blue which we're going to use to figure out what squares the person can move to that was those little blue dots you were seeing before if you remember when I ran the game it's going to be 0 0 255 so pretty straightforward add a comment Here to just say RGB just so we understand that's what it's in and now
we've kind of filled in the constants we'll do a few other things here later but we can skip that for right now so what I want to do is I actually want to import the constants that I defined here into this main.py file so to do that is actually pretty simple what I can do is I can say from Checkers dot constants import and then I can import the variables that I want which are and Height now the reason I can do this and I can reference Checkers directly is because inside of checkers we added
this init.py file this init doop P file tells us that hey this folder is actually a python package and because of that we can import specific things from it so just to show you if I went inside this init.py file and I said from constants import Star so that means import everything from constants what I would actually have to do now if I wanted to import width and height is simply say from Checkers import width height the reason for that is because inside of the init Pi I import everything from the constants file so what
happens is as soon as I import this folder Checkers it automatically runs this which means it will automatically import all the stuff inside of constants now we're not I'm not going to do that I'm going to get rid of this just because I don't want to confuse anyone If that doesn't make sense uh but that's uh kind of just the explanation there and I figured i' show that to you guys so let's go back to from cheers. constants import with height okay so now that we have the window we're going to set a caption for
it so I'm going to say py game. display. setor caption and inside of here I'm just going to call this Checkers this is simply the name of our game and it will pop up kind of in the top little bar after that what we're Going to do is we're going to define a main function this main function is going to be what we run to actually run the game and in here we're going to create what's known as an event Loop that's going to run uh every you know x times per second that we'll check
if we've pressed on something it will update the display we'll do all that so I'm going to say run equals false like that or sorry what am I saying run equals true my bad I'm going to say While run and then inside of here I'm going to put the event Loop so the idea being that we're going to call the main function from outside it's going to start running all of this and then there's going to be a while loop inside of here which will do all the event handling and drawing everything so while run
which is just the variable we defined up here is true we will do this Loop the next thing I'm going to do is I'm going to define a clock so in pi Game if we want our game to run at a constant frame rate so like 60 FPS for example we can define a clock and the clock will make sure that our main event Loop doesn't run too fast or too slow this is good because in a game if you have like a really fast computer it would run faster if you didn't have this and
a slow computer would run slower obviously so you want everything to be the same so it can at Max run at what we're going to put it at so we're going To say clock equals py game. time. clock and then inside of the wall loop we're going to say clock. tick and I'm going to put all capitals FPS like that and actually up here right above win I'm going to say FPS equals 60 now some of you may ask why don't you put this in the constants folder the constants folder is going to be specific
to the Checker's game whereas this is specific to us actually rendering and drawing the game which Will make more sense later but that's that's kind of the idea of why I'm putting it in here rather than in the constant file from Checkers okay so now we have while run clock. tick FPS okay great and what we're going to do is set up our basic event Loop for p game so for event in pame dot if I could type this out event. getet what this will do is essentially check to see if any events have happened
at the current time if they have uh they'll be in this list Of the events doget and then then what we can do is look at the event and see if it is a specific type if it is say we us hitting the quit button we'll quit if it's like pressing a certain key we can do something else so we say if event. type equals equals pame Dot and in all capitals quit this just means we hit that red button at the top of the screen which we'll see in a second then what we're going
to do is say run equals false so that will end this Loop right Here and then at the very end of our loop we're going to say game do quit so essentially if we make it to this line of code so this while loop ends we will quit the game which just means get rid of the window that we're going to be popping up okay so now that we have that I'm going to say if event. type equals equals py game. Mouse button down so this just means we pressed any Mouse on our Mouse down
if we did that or any Mouse what am I Saying any button on our Mouse down excuse me if we do that then we will check to see hey did we press on a red piece are we moving whose turn is it all of that kind of stuff we'll do inside of here but for now I'm just going to Simply type pass all right so now that we have that we have a window set up we have the event Loop and let's actually go ahead and run this and see what we're getting so when I
run this you can see we get just a black box and it says Checkers at the top all right so I'm going to quit that and that means that we're doing things properly so far and now what we're going to work on is actually making it so we can draw that checker board on the display and we set up a few classes that are going to represent um you know all of the stuff that we need to draw on the screen essentially so I'm going to go inside to this of this Checkers folder here and
I'm going to create a new file and I'm Going to call this board. piy now this if you haven't guessed is where we're going to put a class named board and this board class is going to represent a Checker's board so what it will do for us is it will handle say all of the different pieces moving whose turn is it or actually it won't handle that but it will handle moving specific pieces deleting specific pieces drawing itself onto the screen that's what this class is going to do so we're going to say Import py
game like this and we're going to say class board like that and Define an AIT method uh that we will Define in just a second okay so let me just go over to my file here so inside of the init we'll actually just leave it with self and we're just going to define a few attributes of this board class so the first thing that we're going to have is an internal representation of the board so what I'm going to do is I'm going to make a bunch of objects which Are just like you can think
of them as just pieces right like red pieces or white pieces and we're going to store them in a two-dimensional list inside of this class so it would look if I can get get this working properly something like this right we might have like white zero meaning there's no piece there white zero meaning there's no piece there right white and then maybe there's a red one here and there's nothing and there's a red one here and there's nothing and There's a white one here that's kind of what this is going to look like we're not
going to use white and red but just to give you an idea we're going to have a two-dimensional list because we have eight rows and eight columns so we will have eight interior lists and inside of each of those lists we will have eight different elements and those elements will be pieces which will tell us if they're red if they're white if they're a king piece all the other stuff that we Need for um what do you call it for Checkers all right so now we have the board the next thing that we'll do is
we'll say self. turn equals 0 what I'm going to say here is zero will mean that um actually do we I don't think I even need to define a turn in here sorry I'm going to not Define that we'll do that in another class but we just need to keep track of is it Red's turn is it White's turn so we know who can move right next I'm going to say self. Selected piece equals none so this is telling us hey have we selected a piece yet have we not selected a piece let's define that
and then I'm going to say self. rore left equals self. whitecore left = 12 so the point of this is saying okay we want to keep track of how many red and how many white pieces we have in checkers we have 12 of each so we'll set a constant value up here or not a constant but we'll just set this equal 22 and then as soon as we remove a white Or red piece we can subtract from that next we're going to say uh self. redor Kings equals self. whitecore Kings equals 0 if you're unfamiliar
with with the syntax this just means these are both equal to zero like if Red Kings is equal to White Kings and white Kings is equal to zero then Red Kings is equal to zero right so that's what this means and that's all we need for the NIT the next thing we're going to do is we're going to define a draw underscore cubes um now We could call this something more meaningful maybe but we're going to say self win and what this is going to do is say okay give me some surface which is going
to be our window that's what wind stands for to draw the red and black cubes on in a checkerboard pattern so let me just run the other one and we'll have a look at it here to see what we actually need to do okay so we need to draw red first then black then red then black then red then black and so on in a Checkerboard pattern so we're going to need to write some code that can do that I will show you how we do that right now okay so what we're going to do
to start is we're going to fill the entire window so wind. fill with black now I need to import black remember from my constants file so what I'm going to say is from do constants import black now I'm using dot because when we are in the same package as something else we need to specify hey this is What's known as a relative import we're going to import from do constants which just means from something in the same directory as us named constants so we're going to fill the window with black and we're going to say
for Row in range and in this case we're going to just put up here rows so we know how many rows we have so for Row in range rows and then we're going to say for call in range Row mod 2 82 uh and not eight sorry this Will be rows now what am I doing here why have I done mod 2 well we want to draw a checkerboard pattern right so when we start the column here we either need to start in column Z or column one so let me just bring this checkerboard pattern
back up again so I can explain this essentially what I'm saying is okay if the row is zero then what we'll do is we'll say Row mod 2 which obviously Zer mod 2 is just zero so we will start by drawing a red square in column zero then We will step by two we'll draw a red square in column two and then in column 4 and then in column 6 now when row goes to one we're going to start drawing the Red Cube in column one because Row mod one if it's or sorry one mod
2 is one so we're going to start in column one and then we will skip over columns again and we will go uh 1 3 5 7 next what we going to start at because it's going to be two we're going to go again and we're going to say 0o 2 4 6 right that's kind of the Idea behind doing this and this is probably the simplest way we can actually write this code so what we'll do is we need to figure out where we're drawing this so we're going to say pame do draw. rectangle
we're going to draw it on the window we're going to draw with color red which we'll import from up here and while we're up here we'll actually import the square size as well because we're going to need to use that So what this is saying is okay draw a rectangle draw it on the window draw it with some color in this case which is red then we need to give what's known as a wrecked argument so a x y width and height let me bring back up the pame window so I can explain this a
bit whenever we start drawing something in pi game we draw it from its top left coordinate so top left in P game uh right here is 0 0 so if you can see where my mouse is kind of right beside This icon this is 0 0 as I go far to the right I increase in the X as I go down I increase in the Y so technically at the bottom here we'd be at 800 whereas at the top we're at zero so when I start drawing I need to pick where is the top left
of the shape I'm about to draw so if I said 0 0 it would be here and then I would draw 100 wide in a 100 tall to draw a square that is that Dimension at that place so that's how that works so for our X and for our Y what we're going To say we're going to say row oops row multiplied by square size and then call multiplied by square size and then for the width and height we're simply going to say Square size Square size now I know this is cutting off a bit
let me zoom out so you can see the whole thing okay so four uh for row and range rows for call and range rows py game. draw. on the window red and then of course this is going to calculate where the top left and right should be and then the Width and height okay let's Zoom back in all right so there we go that should be it I'm just going to check and make sure that's all we need to do and I think that should be fine for drawing the cubes so now let's test this
out and make sure that this is working so what I'm going to do is I'm going to say from Checkers dot in this case for import board so what we'll need to do is create a new board object so we'll have to say board equals board like that Inside of here and then at the end of every Loop and what is this telling me this error is here pame has no mouse button down yes it does what I'm going to do at the end of each Loop is I'm going to say okay board. draw cubes
and we'll just pass it the window that we want to draw it on and then hopefully this will draw it and we'll say pame do display do update so whenever we want to update the display in P game we have to call this method the way the Drawing works is we'll draw on top of each other so say I draw like a cube and then I draw a square after that so I have like one line that draws a cube and then another one that does a well Cube and square I guess could be the
same thing what am I saying draw cubes maybe we should call this draw squares yeah let's call this draw squares I realize my geometry is a bit off so if we draw two squares the one that we draw second is the one that we will see that's what I'm trying to say essentially uh if they were on top of each other but anyways we update the display after we draw the cubes so let's press the Run button and what is it saying has no attribute draw squares did I change this squares board object save draw
squares am I spelling something wrong it's no attribute draw squares hm okay let me look at this maybe I'm spelling something wrong I must be let's See Define draw squares save really telling me it has no attribute let's see again and there we go okay so I don't know what was going on there but now it seems to be working and we have red black red black so on and so forth and a perfect checkerboard pattern okay so there we go that is a good start next what we need to do is draw all of
the pieces so let's go ahead and do that so we have board. piy and now what I'm going to do inside of here Is I'm going to say Define creatore board now this is going to say self and we'll take a pass and what we'll do inside of here is well we will create the actual internal representation of the board and we will add a bunch of pieces to the list now of course if we're going to add pieces we need pieces so let's make a new class in another file here called piece dopy and
let's spell it properly like that so p.p I'm going to say class piece like that and Then we're going to say say Define underscore uncore netcore uncore we're going to say self row call and color so when we make a new piece we need to pass it what row it's in what column it's in and what color it is so we'll say self. row equals row self. call equals call Self docol equals color and that should be it we'll add a few more self. King equals false so this is going to tell us are we
a king piece if we're a king Piece that means we can jump backwards right if you're familiar with Checkers so we'll get to that part later but we'll just add that in now let me just check my file and see what else we needed uh we'll have self. selected that can be equal to false actually I don't think we need this either I have some code that I have written but we don't really need so I'm just filtering it out as we go and what else we need self. direction that is Important so self. Direction
equals hm we'll have to Define this here okay so the dilemma I'm having right now is I need to pick the direction for each piece right are we going positive are we going negative what way are we going essentially so what I can do is I can say okay well if we are and let me just run this look at the checkerboard pattern if we are the white pieces so we're at the top because I believe white is at the top we're going to move down Which means the direction we're going to go is positive
if we're thinking about the coordinate system system of P game where if we're red we're going to move up so the direction we're going is negative so let's do that inside of piece we'll say if self. color equals equals and now we have to import red and white from the constant so from do constant import red white so if self docolor equals equals red then the Direction is actually going to be negative 1 meaning we're going up up otherwise self. Direction equals 1 okay so that handles that and then next we're going to say self.x
equal 0 and self.y equal 0 and then what I'm going to actually do is I'm going to make another method that says calculate pause now what this is going to do is calculate our X and Y position based on the row and column that we're in so in this case we're going to need to know the square Size so that we can simply multiply whatever row and col we're in to figure out what our starting X and Y position should be when we draw this piece so that's what I'm going to call calculate position I'm
going to say self.x equals squar size multiplied by self do in this case is going to be call because we're doing X which is the horizontal axis plus Square size over over two now the reason I'm doing this is because I want to be right in the middle of the square When I talk about my X and Y position so we're going to have circular pieces right and circular pieces we draw them from their Center so we have a radius around a circle and that's how we draw a circle so our X and Y position
should be in the middle of the square so we'll just divide the size of the square by two that will give us 50 right so in this case this we could literally just put this as 50 if we wanted to and then we would be in the middle of the square All right so self.y equals the same thing Square size multiplied by self. row that's the only difference plus Square size over over two okay so what we'll do is simply call self. calculate position after this the reason I'm not just writing this code inside of
here is because we're going to need to do this a few different times uh if we change our row and column so it just makes more sense to have a method that can do it for us next I'm going to make another Method I'm going to say Define make undor King what this is going to do is simply change the king variable so self. King equals true and that just means you we'll literally just make this piece of King uh if we can next we're going to draw so we're going to say Define draw what
this will do is pretty straightforward we will draw the actual piece itself this is actually pretty easy to do but uh let's go ahead and do it so self win we're going to start by Drawing a circle and then we'll draw an outline for that Circle so that we can actually see it well enough so we're going to say p game do draw do Circle win self doc which is what we have to put here I believe self. col and then we need to pick our XY position for the center of the circle actually I
think this is the right way yeah I think it is so we're going to say self.x self.y and Then finally we're going to pick a radius so for the radius uh we need to determine what we want that to be and that is going to be based on how much padding essentially do we want let me just bring this up between the edge of the square and the circle so if you look here we have like maybe 10 pixels of padding on each side so we need to Define that and then we can derive what
the radius should be based on that so I'm going to Define as a class variable Here padding equals let's make it say 10 or something like that I'm going to see if that's what I use for the other one yeah we'll make it padding is equal to 10 and we'll Define a border which is essentially what do we want the outline to be so we could guess we call this outline so outline equals 2 all right so now when we draw what we're going to do is figure out okay the radius of our Circle should
be equal to first of all the square size uh over Over two right because the radius is not the diameter so we have to divide the square size minus the uh self. padding over over two so sorry I made a bunch of mistakes here this should just say self. padding not divid by two not multipli by two whatever I said uh this is the correct math is minus self. padding okay so if that assuming is that's the pading we want on each side so then I'll just put radius here and yeah I guess that's lowercase
variable and then that should Draw the circle for us now the next thing we'll do after that is we will draw an outline so we'll simply say py game do draw do Circle and we can literally copy the exact same thing we're just going to change the color and the radius so for the radius we're going to say radius plus self. outline the reason for this is whatever the actual radius of our button is we'll just go two pixels outside of that and actually we'll have to reverse how we draw this But we'll go two
pixels outside of that so we draw a slightly larger Circle and then on top of that Circle we're going to draw the interior one so it will look like it's a border but really what we've done is we've drawn a big circle and then a smaller circle inside of that Circle that's covering what that interior circle's color actually is if that makes any sense so I'm going to start by drawing the larger Circle which will be radius plus outline and then on Top of that I draw the smaller Circle so you only see you know
the two pixel difference in the radius between these as the outline now for the color we need to pick a color that is not the piece color and is not one of the square colors so we can actually see it so I believe that we can pick something I'm trying to think of like a decent maybe we'll go with a gray or something so let's just Define uh gray inside of our constants And we'll use that so inside of constants we'll say gray equals and we'll go 128 128 128 that's just a common color code
for gray and then instead of color here we will simply do gray and then we'll import that from constants okay great so now we have radius we have the actual Circle being drawn for the piece and I think for right now that's all we need to do I'm going to add one more method just to make it easier for us if we need to Debug this later and it's just going to be repper what this means is what is the internal representation of this object you may have seen before if you print out like an
actual object that you've created you get some weird like object at X blah blah blah location to avoid that we can simply make our own representation of the object and that's again just if we print this out or if we look at it it will show us this so I'm simply just going to say uh That we will use the color so return the string of self docolor so wrapper has to be a string so we'll just take whatever our color is and just turn it into a string so we'll see like 0 0 255
0 255 0 whatever the color of our object is so now we have piece and if we want to see them well we need to start creating some pieces so inside of my board class under create board I'm going to create a bunch of pieces we're going to start obviously by making the white pieces will be at The top and then the red pieces at the bottom so this uh is not too complicated but it is a little bit of a for Loop kind of IM uh indentation thing that you'll see here because we need
to obviously have them be spread out we're only going to have I believe four in each row and then they need to be staggering and then the white need to go up there they need to be a space and then it needs to be the black or the red sorry the white and then the red my bad All right so four row in range rows four call in range calls we can import calls up here technically again I mean I can change this here to be calls doesn't matter because they are the same value but
say we had a checker board that wasn't exactly Square then these would matter so four range or four row in range rows four call in range calls what we're going to do is we're going to start by saying Self self. board. append an empty list the reason for this is because we want to have uh interior lists for each row right so we want to have a list that represents what each row is going to have inside of it and we'll just do that by pending one for each row that we have next what we're
going to say is if call mod 2 equals equals a little bit of fancy math here row + one mod 2 uh what this is saying essentially is if the Current column that we are on modulus 2 so if it's divisible by two if that equals whatever the row plus one so say we're on row zero technically we're on Row one mod 2 then what we can actually do is we can draw the red or white Cube now if we look at the checkerboard I'll kind of explain to you how this works by going through
a few examples so on when row is I'm trying to be able to view the code at the same time so when jeez bring back my Pi game uh we've got two of them Open let's close one okay there we go so let's say row is zero we're on the first row then the uh row + one mod 2 is going to be equal to one right so that here that I can't highlight unless it will put away this uh is equal to one and then call so if we're on column zero in this case
call mod 2 will not be equal to that so that'll be this first Square here this red one so we won't draw the Checker or the I think that's what you call it like a checker piece I guess and Then the next Cube over right so the row stays the same but the column now is column 1 mod 2 so that's equal to it so we draw white all right move next now it's column two so we're not drawing that next we go column three we will be drawing that so on so forth now you
increment the row when you increment the row what happens is row plus 1 so 1+ 1 is 2 mod 2 is equal to zero which means we'll only draw on the even columns right and then the next one will draw on The odd columns so that's kind of how this is going to work uh and that's like the basis behind this math that I'm explaining okay so in this case uh we can draw so if this happens we can draw something but we only want to draw when we're in a certain row so we have
to say if row is less than three because 0 1 2 are the first three rows that we want to draw the white pieces in then what we will do is we'll say and we're not actually drawing here we're just Creating the pieces but same promise we'll say self. board row do append and we'll create a piece and what we what will we do here we'll say row column and then the color we're going to put here is going to be white so I think I imported white I did not so first of all let's
import calls properly and now let's import white okay so black row Red Square size calls white great and then we can append white in there L If row is um I guess we'll say less than should be 567 is where so if we say if row is less than four then we'll simply continue uh actually let's just do this if row is greater than four so if row is five six or seven then we can say self. board row do append piece row call Red so hopefully this makes sense uh and we need to import
pie which we'll do in a second but the idea being that we're just Creating this board we're going to do the checker board pattern and then obviously we're not going to do anything in the rows that are three or four what am I saying three or four yeah in rows three or four we are not going to add any pieces now when we don't add a piece though what I want to do is I actually want to add a zero instead so I'm going to say else and in this case we're going to say self.
board row do append Z the reason for this is That's just going to be like our blank piece like we'll have zero white zero white zero white so we can keep track of by looking at the board what row and column each piece is in uh by having these kind of blank separators next we're going to say else uh self. board row. append zero so essentially if we don't add a piece we are going to add a zero so that we can separate the pieces and be able to look at this list and Figure out
where the pieces are now we need to import piece so we'll say from dot piece import piece like that okay so that should be good that should create the board for us now what I want to do just to make sure this is working is actually draw the board so I'm going to make a new method here called Draw and what this is going to do is say self win and this will draw all of the pieces and the squares so this is going to say Self. draw squares so we'll draw the squares on the
window and then we'll Loop through all the pieces and draw those so I'll say for Row in oops range if we can do this here uh for Row in range all capital rows and then we'll say for call in range all capital calls we'll do is Loop through the board so we'll say piece equals Self. board row column like that we'll say if piece does not equal zero because if the piece is zero obviously we're not going to draw anything right so if the piece does not equal zero then piece. draw on the window so
I think that should be good let's test this so I'm going to go to main now and rather than board. draw squares I'm just going to call board. draw and let's just make quick test here and see if we crash Invalid syntax where is the invalid syntax okay so I don't know what Arrow I was having but I managed to fix it I think it was cuz I was actually in the python console accidentally but anyways when I'm running this I'm getting an error now that says list index out of range now the reason for
that is that we have this create board method but we we haven't called it so I haven't actually created a board so we have this draw that's trying to Loop through all these Rows and columns yet they don't exist in the board so let's actually fix that by saying self. create board inside of our nit so that right when this object gets created we automatically create the board let's try this now and P game is not defined okay so I guess I didn't import P game inside of some place here that would be inside a
piece so let's say import p game like that inside of our piece uh module file whatever you want To call it okay now we can run it and there we go we can see our red and white pieces and they look to be working fine now I'm not a fan of how big these are so I'm going to make them a little bit smaller we can do that really easily by just changing our padding right so if I change the padding to 15 and run this file now we can see they move down a little
bit and you guys can experiment with those make those bigger smaller whatever you like okay so I think That is good for right now next what we're going to do is we are going to actually work I guess on a bit of the logic of the game so we have now the ability to draw these things we can see everything now we need to actually move them figure out the valid moves for each piece as well as we need to figure out what happens if one of these pieces is a king so first thing I'm
going to do actually is start working on how we can draw the crown for a king piece we'll Test that out and then we'll get into the logic so to make a king first what we're going to need to do is we're actually going to need to download an asset for a little crown that we will draw on our piece if it is a king piece so let me see if I can bring this up for you I have an image of it I'm going to pop it over here you see this is what the
crown looks like it's a transparent background so go to the link in the description it will say like download Asset here or something you're going to download a compressed zip folder what you need to do is rightclick on that compressed zip folder press uh uncompress or unzip here so just make it so that you don't have that like zipped up folder anymore it's an unzipped folder and then take that unzipped folder it should be called assets and just put it inside of this directory right here so inside of this Checker directory so it's going to
go inside of The Checker directory uh not like inside of the root directory although you could put it inside the root directory but we're just going to put it inside of this Checker's directory so let me actually do that I need to grab that folder so I'm just going to look for it on my system so I have assets right here going to copy that and I'll put that into my Checkers folder like that so now we have the assets and is this inside of the right One yes it is now we should be able
to load it so what I'm going to do is inside of constants dopy I'm actually going to load that image so I'm simply going to say Crown equals py game. image. load and I'm going to load assets SLC Crown Dot and in this case I think it is PNG okay so we'll go crown.png now what I need to do actually is I need to resize this so it's actually too big by default we need to make it small enough that it will fit on The actual check uh checker pieces so to do that we're just
going to use a method from py game I just have to find it because I forget exactly what it is we're going to say py game Dot transform I think is it py game. transform or py game. image no I it's py game. transform. scale and what we do is we put the image first and then we put the resolution that we want to scale it to so I've just kind of hardcoded these Numbers in you could do this mathematically I guess but I'm going to go with 45 and 25 this relatively keeps the aspect
ratio of this image and it makes it's small enough that we can actually put it on the direct Center of all of our pieces and we can tell them hey you know this is a king piece so I'm going to make this sry Capital again don't know why I made that lowercase and now let's go to piece and from constants import red white square size gray and Crown inside of the draw we're going to add a really basic if uh the piece is king So if self. King then what we will do is we'll say
win do Blitz the crown Blitz simply means put some image onto the screen or put some surface onto the screen that's what it's saying these are just special pame methods to draw directly onto the display whereas this one we you know just blitting the image and then we need To pick our XY position that we want to put this on now I want this to be perfectly centered so I'm going to use a little bit of math here to do this what we're going to say is self.x minus crown. getor width get underscore width is
going to get the width of the image now we already know what the width of the image is but what I'm trying to say here is that uh let me actually just go to a kind of drawing whiteboard so I can show you what I mean if we have a square Okay got it let's come on let me draw why can't I draw okay so apparently uh windows or Microsoft Inc just doesn't work so I can't draw the thing for you right now I don't know the solution to that what I'm trying to say is
imagine that the X and Y position you don't have to imagine the X and Y position we have is in the middle of the square so let me just load the other game and at least I can maybe show this to you so the XY position is right in the middle so where My mouse is now we want to draw the crown right in the middle so it's perfectly centered but if I just draw at the XY it's going to move the crown it'll be kind of to the right because the XY is the top
left of an image when we're drawing it other than a circle right where we have the radius so I can't can't just draw it at the XY I need to draw it someplace to the left and up a bit such that it will be perfectly equal distance from this left Side and the right side of the circle so all I have to do is get the width of the image and subtract half of that to figure out where the starting X position should be because that will say okay from this point if this is the
center we just move half of the image's width to the left and that will mean that it's being drawn perfectly Center in the cube or on the circle same thing with the Y position we can do that as well to make sure it happens perfectly in the center So that's what we'll do we'll say self.x minus crown. getor withth integer division 2 just so we don't have any rounding errors then we'll say self.y minus crown. getor height over over two great so that should draw the crown for us in the middle so what I'll do
is just set all of these crowns to be true just so that we can make sure that this is working and test it out uh hi game. transform has no attribute scale well it would help if I spelled scale Correctly so scale there we go all right let's che check this now cannot load assets crown.png okay so let's try to fix this um I believe the issue we're having is something to do with kind of the path system in Python so what I'm going to do is just take this folder and put it outside so
put it in the main route directory rather than inside of the checkers directly directory and now it should probably load so let's try this Now and there we go that is working just to reemphasize what was happening there this I had asset crown.png I had that folder inside of this Checkers folder I specifically told you to put it there but I was wrong so what we need to do is take it out and just put it alongside the Checker directory so it's in that root directory because when we run this main.py file that's not inside
of the Checker folder the path that uh python will look at to load images will be in This directory where we loaded main do high so I would have to say Checkers slash assets slash if I wanted to load the image the way that we were doing it before without moving this folder anyways not a huge deal but hopefully that's loading for us and I think that this is working fine we can see the crown on all of the pieces again perfectly in the center all right so let's go back and remove that now so
piece we no longer want to draw the Crown so we will say false and now I got to figure out what we are going to do next so I'm thinking probably what we should do next is actually set up a way to move pieces around and delete pieces so from board what I'm going to do is I'm going to make a move uh method so I'm going to say Define move I'm going to say self and I'm going to say piece so you tell me the piece you want to move and what row and column
you want to move it to now what we'll have to do to Move the piece is we'll have to delete the piece from where it is and we'll have to change its position so that reminds me that we actually need to go to piece and we need to add a move method as well so Define move like this self row call so what will happen when we move a piece well we're going to have to say self. row equals the new row right cuz this needs to say updated so self. call equals the new call
and then self. Cal position so remember Cal Position which is right here simply tells us what the XY position of our piece should be so we have to recalculate that when we change our row and column so we have move now on piece so board what we'll need to do is we'll actually need to first of all move the piece within the list right because we have this list that represents all our pieces and then we'll have to also actually change the piece itself so piece do move to wherever it's going to Go to update
on the pieces side all right so what we'll do is we will say uh self. board and we're going to say piece. row piece. call comma self. board row call equals and then we're going to say self. board and we're literally going to copy these Just In Reverse so so I'll talk about how this works but this is a easy way to swap things uh in python or swap positions in a List so what I'm saying with this line here and I'll zoom out so you guys can read it is essentially that the uh piece
that's in the position uh piece. row piece. call so the one we want to move and I need to spell piece correctly and then the piece that's in the position that we want to move to we are going to swap their values by simply reversing it like this so this piece here will move to this one here so row call and then the Other one will move to this one so they'll essentially swap that's just how this works and this means we don't need to make like a temp variable delete something read it in all
that that we would usually have to do all right so now that we have that what we'll actually do is we'll say self do actually we don't need self we'll just say piece do move row column there we go so if uh or Not if but when we move this actual piece we'll just move it row column now I just want to look and make sure I've done this correctly I think we have uh but there might be some other things that we want to consider here all right so now we've moved the piece this
should actually work we'll test this out after but we need to do is make sure that we haven't moved well I guess we don't need to check that we need to make sure if we've moved into a position where we'll Become a king we become a king right so if we move and we hit the last row or the first row then whatever our piece is should become a king so what we can simply do is just check if the row column that we moved to is actually a position that should make us a king
and if it is then we will make that piece a king and we will also update the variables we have here for the amount of kings that we have so what I'm going to say is If piece. row or I guess we can actually just say row if row equals equals rows or row equals equals z what we can do is we can say self or not self piece doake not make move make King so this will make that piece a king and then we'll need to update the red or black is it red red
or white Kings so the reason this works is because if we move into a position that is zero or seven for the row that means that we are at the end or The beginning of the board now some of you might be asking well won't this break because we already have pieces in those positions that are the same color right so like the white piece is already in row zero and the red pieces are already in row seven or row eight whatever you want to call it so won't those just become Kings well no they
won't because they have to move into that position so we're not going to let them move backwards unless they're a King which means that they won't become a king uh unless they actually move to the other side of the board from where they start at now there will be a situation where a king will move into a not its own side and become a king again but that's fine if it's already a king there's no difference in making it a king again right it's not double kinging or anything like that all right so if row
equals equals rows or row equals equal Z peace. make King we need to Update the red and uh white king So if peace do color equals equals white then self. white Kings plus equal one else so if it's not white it must be red self. Red Kings plus equals 1 okay so that should be it for move what we can do now is check to make sure this is working so what we'll do is just simply put inside of this actually we'll just do it right here say board. move ah and now we run to
our first problem we need a piece right we actually need to pass a piece Object like this to this move function or move method so that I can move it so how am I actually going to get a piece well we'll write a method here that says Define getor piece and we'll say self row call so essentially you give this uh board object a row and a column and it will give you a piece back so this will simply return self. board row call all right so now let's just say piece Equals board. getet piece
and let's pass a row and column we know there's going to be a piece in so in this case I believe there's one in 01 because I don't think it starts in the top left corner so we'll get a piece at 01 and then we'll say board. move that piece right here and let's move this to I don't know where do we want to move this somewhere where there's not already a piece let's go row four Column 3 all right so that should move it into the center of the board relatively into the center of
board uh and what is it saying Oh missing one required positional argument column so oops I shouldn't have put these in a topple I should just have them separated out like this so 43 let's run this now and what is the other one piece is not defined well it would help if I spelled piece correctly where is it telling me this is undefined uh it is undefined Here looks like yeah piece of spelled wrong okay so let's go back to board let's go to move and let's fix that there we go okay run work and
there we go we can see that now that piece here is moved over here so this move method does work now we want to figure out a way that we can do it using our Mouse right so this will be a bit more complicated but very doable and the next part of this uh series here this video so what I'm going to do is I'm going to Make a method that says Define get row _ call from Mouse so this will simply take the position of our Mouse and it will tell us based on the
position of our Mouse what row and column we're in so we're going to say XY equals position because this is going to be a topple that will'll have the X position of our Mouse and the Y position of our Mouse and then based on the Square size we can calculate really easily what row and column we're in so We can simply say well we'll make it a bit easier we'll say row equals y into integer divided by square size so this is really easy right and we need to import Square size but if the square
size is 100 and we're trying to figure out what row we're in if our y is at 650 then we know we must be in row six right and if our Y is 700 we must be in row seven right it it it's pretty straightforward so that is how this works that's how we get the row and the Column just a little bit of division so we say call XX or divided divided by square size now we'll need to import Square size like that and we can return the row column great so get row colum
from Mouse position now what we'll do is when we press the mouse down we will get what row and column we're in we will select that piece and then we will move that piece uh to wherever we want to move so we'll be able to select the piece and then we can select where we Want to move it to so if pame do uh Mouse button down then we will say row call equals and first we'll say position equals pame mouse. getor pause this will get the mouse position say row call equals get row call
from Mouse position then we can get the piece associated with this so we can say piece equals and we can say board. get piece row column and we can Move it now what I'll do right now is just cuz I want to Cod everything is I will simply just move whatever piece we select to the same position so we'll just move it to 43 just you can see that this does work when we press on the piece um but we will obviously make it so that you're moving it where you want to move it afterwards
okay so let's just test this out and make sure this works so if I select this piece you can see that all these pieces obviously they're Going to be hidden by that white piece cuz that's there um but they get moved to that position position so when I press them they move there again obviously all them are moving to the same one so you can't really see but that is okay so now that we have this what we need to do is actually allow us to select the piece have it selected and move to a
valid square that also involves having to figure out where can we move to like what is a valid square Right and if we move and we say jump over a piece um how do we remove that piece how do we get rid of it you know can we jump and double jump like those are the stuff things we have to figure out now which are kind of difficult but obviously we're going to do them they won't be that hard okay so I'm going to make a another file inside of checkers and I'm going to call
this game. piy now what this is going to be responsible for is handling actually the game so Figuring out like whose turn is it did we select a piece is this piece good like can we move here can we move there that's what game is going to do uh and it's going to use board and a bunch of other stuff to do that for us it's also going to handle like drawing everything and and a bunch of other stuff all right so now we're going to code out the game class now the whole point of
the game class is going to be to let us actually interface with the board and the pieces And everything else with a few really simple methods so essentially I don't want this main kind of loop that's actually running and checking for us pressing buttons and stuff to be Associated at all with how this game operates I want this game to be able to be operated by in theory two computers right I don't want it to be linked in directly to us pressing buttons and all of that because later on what we'll do is Implement an
AI so we can play Against it right so we need to make sure that it's very clear that game just exposes um some methods that we can use but it's not like it's not dependent on the fact that we're pressing certain things or that two human players are playing that's kind of what I'm trying to get out here with the point uh with with this so let's define the class let's import P game like that and say Divine nit self and do we need anything else for game we're actually going to Take the window that
we want to draw this game on so we could put the window in here if we want like we could Define it in this game class I'm not going to just for the purpose that say we actually want to draw or play maybe like four or five chess games at the same time well we could in theory pass a window that is big enough that we could draw four chest games and then we could just pass subsets of that window to different games and play multiple games At the same time so I'm just trying to
keep things flexible um we could Define win here I'm not going to but just figured I'd tell you why so first I'm going to say self. selected equals none this actually reminds me that I want to go back to board and remove the selected piece because we're not going to use that inside of board we're going to use this inside of game to figure out what piece is selected by someone that's playing if they are and then next I'm Going to say self. board equals board so that means from Main here we're actually not going
to make a board we're actually just going to make a game and the game will control the board for us so rather than having to get the piece move the piece all of that all we'll do is use the game to say okay we selected this row and column move it to this row and column and that will figure all of that out for us so self. board equals board next we're Going to say self. turn equals red which which means we need to import constants so from dot constants import red white uh what else
will we need uh probably a few other things but we'll just leave red and white for now so self. turn equals red and after that we need self. validor moves equals a dictionary we'll talk about this after but this is going to pretty much tell us what the current valid moves are for whatever Player is playing so that we can draw those or can move those or whatever it may be next we're going to say self. win equals win so just store that window in here so we don't need to pass it every time uh
and then what we're going to do is Define an update method so update will just be like say we're updating the uh pame display instead we'll just simply call this update method so we'll say inside of update self. board. Draw and then anything else that we want to do to actually kind of update the game and then next we'll say py game. display. update so now right if we go back to main all we have to do actually is instead of saying board. draw and py game. display. update we'll say game do update like that
instead of making a board we'll say game equals game so now in theory we've just kind of wrapped some of this functionality in so I'm going to get rid of those two lines We're not going to use this right now uh and we need to import game but once we import game all we'll have to do is just use the update method the move method it's a lot simpler on this end when we do that so let's say from trackers do game import game and let's run this and see if this works okay so I'm
getting an issue ah missing a POS uh positional argument win so I forgot I have to pass the window to my game so let's do that And what is this now board is not defined ah so we need to actually import board into game so let's do that and now let's try it and what's the eror this time missing one required positional argument uh win okay so let's go back to uh game sorry guys and let's say self. win inside of the call to self. board. draw okay and there we go now it's working so
we can see that it all works the same we've just kind of wrapped it up and are using it a little bit Differently all right so now let's go back to to game and let's start defining a few other methods that we want so first I'm going to define a reset method this is pretty straightforward just say we want to reset the game and what we'll need to do is say self. selected equals none self. board equals board self. turn equals red and self. valid moves equals blank and in fact that looks really similar to
what all of this stuff is right so let's wrap This in a new method and let's just say Define and let's actually just call this a nit so inside of the reset method we can just call a nit like that and I'm going to make this private just putting an underscore uh beside it so that no one else can call this they have to call the reset method and then here what we'll do is we'll just call underscore anit so the logic behind this is that since we're doing the same thing twice but there's a
little bit difference in The init uh method here let's just put it in a uh method that does it and rather than having the user um just call a nit right what I will do is have them call reset the reason for that is that a nit technically is initializing the game but we don't want the user to have to call in a nit method when they want to reset the game right so just for it so it's more clear for them we make this private so they don't see it they only see the reset
and really all it's doing Is just calling a net which is also used by the initialization of the game so it's just about what we're exposing and showing to whoever is using this class yes we are are using this class but you have to imagine that maybe someone else is using it or maybe we're going to use it in a different capacity so it makes more sense to have methods that are name the right thing and then inside of a nit we're going to have self like that okay uh and this will be self. a
nit and Self. a nit my bad okay so now that we've done that I'm going to add a method for select so this will say uh select a row and column so self row call and we will have move so Define move self row call all right great so this is pretty much saying all right when you select something you will call this select method you will tell us the row and column that you selected and then based on that whatever information we're currently storing in the state of this Game will do something right so
if you already selected a piece then maybe we'll move it or if you selected a different piece we'll change that selection right that's what we're going to do so I'm going to say self. selected so if we have something selected cuzz note right now selected is equal to none then what we'll do is we'll say result equals self. move of row call now this won't make too much sense right now because we haven't defined this move Method but what I'm saying is okay if we already selected something then let's try to move what we've selected
to the row and column that you put in here the the point of this being that I'm actually going to make move private we only ever select something from the game so when we are like moving stuff around or when we're giving any input to the game we just call this select method we say okay I selected this I selected this I selected this blah blah blah and this Will handle what happens based on that selection so we don't need to call move and select we just call Select and select will determine whether or not
we should move something based on what you've already selected that's what I'm doing at least might not make perfect sense but anyways I'm going to say if not result then self do selected equals none and self. select row call so essentially what's going to happen from this move method is if we were able to Successfully move something so if the row column that we selected was valid because we already had something selected so we selected say uh you know a diagonal square that we could move to then we will actually move it but otherwise what
we'll do is select a different piece or at least try to select a different piece so we'll say um sorry let me re-clarify this so what this is doing essentially is saying okay if we have something selected already That means we already pressed on some piece so we're trying to move the piece that was selected to whatever row and column we just passed here now let's say that doesn't make sense like maybe we pressed a red square and then we pressed a white square well that's going to mean that result is going to be false
it's going to tell us hey no that wasn't valid like you couldn't move there so what we do is we reset the selection and we reselect a row and column so this is Going to call this method again except now we're going to get into the lse statement that I'll put here uh or not the lse statement but we'll get into the rest of the code that I'm going to put here which will essentially say okay let's select this piece let's do that let's whatever right that that's what it's going to do so we're going
to say piece equals and in this case we'll say self. board. getet piece row column so we've used this before but we're going To use it in here here we'll say if piece does not equal zero so if we're not selecting an empty piece we're actually selecting something that's red or or black and and not black sorry red or white and self. piece. CCO and actually it's not self it's just piece. color if piece docolor equals equals uh self. turn so whatever turn it currently is then what we can do is actually select that piece
so I say self. select Ed equals that Piece and we'll say self. valid moves are equal to self. board. get valid moves which is a method we're going to Define in a second and we'll simply pass in that piece and then we will return true to tell us hey this was right we selected something that's good otherwise we'll return false so this is just to tell the user hey this selection was valid so we're returning true to you if it's not valid we're returning false and that's The basis of how this works so again we'll
go through it if we selected something then try to move it to whatever else we just pressed here if that doesn't work so we get a false back then say okay get rid of our current selection reselect something else which means call this method again and that means we will do whatever happens here now we could put an else statement just to make sure uh in this case return false is fine just to make sure that uh Um we're not going to accidentally run this code after the self. select happens and we return back here
if that's making sense because this is technically recursive but anyways that's what I'm getting on so we can go over this again later but I think that's enough of an explanation okay so now we're going to do move so move is called um here and now we need to actually move something um if this is called so we're going to say piece equals self. board. getet Piece row oops comma column next if self. selected so if we have actually selected something and the piece is equal to zero and the row call is in valid moves
which is going to be self. validor moves so hopefully this is reading clean enough that it makes sense but essentially if we selected something and the piece that we selected is zero this is important because we can't move into a position that has another piece so only if we Selected something and what we selected is actually not another piece because at this point we've Okay so we've already selected something and then what the row and column that we pass here that we're trying to move to is not another piece if that's the case so actually
I can't I don't think I can say yeah if piece is equal to zero from row and column that we just pressed on and the row and column that we want to move to right is in the valid move mes then we can Actually move it so we can say self. board. move and we can move the piece which uh we would have had as selected so self. selected we can move the selected piece to the row and to the column okay so I double checked that I'm pretty certain this is right I've been confusing
myself because there's a lot of rows and columns and the same words everywhere but we will move the currently selected piece to the row and column that was passed to us Here and this will work we've already set up how the board moves the pieces and then what I'm going to say is this will be weird because we haven't seen this yet uh but skipped is going to be equal to self. valid moves uh you know what actually let's skip this because I don't want to confuse anyone if they um if they don't if we
haven't yet wrote the code that we're about to try to like work with if that makes any sense but otherwise if this is not true we're Going to return false and then return true if this actually works now the other thing we need to do is actually change the turn so I'm going to say Define change turn self and we're going to say if self. turn equals equals red self. turn oops self. turn equals white and otherwise self. turn equals red so change turn just to make this a bit cleaner to see and then we'll
call self. change turn all right so valid moves we Haven't looked at this yet but this is going to be a dictionary of the valid moves that we can take from any uh possible position and then we have change turn which is going to say okay if it's red we'll go to White if it's white we'll go to Red so pretty straightforward I want to see now if I can get select to work or if this is working the only problem is we're not drawing anything right so I won't really be able to see if
what piece I've Selected is working or not so we're actually going to have to keep writing code until we can really test this and make sure that we haven't messed anything up okay so now it's actually time for in my opinion what the fun part is which is trying to figure out an algorithm that can uh essentially be given any piece and determine all of the valid moves for that piece now unfortunately my um like drawing software isn't working I'm going to try To get it working if it doesn't then you'll be seeing me handrawing
something in just a second all right so now I got the drawing stuff to work fortunately so I don't have to actually go and get a piece of paper and film myself doing that uh but what I'm going to show you is essentially how we figure out what pieces or where what piece where what moves pieces can go to based on where they are uh that's a mouthful and I still didn't say it correctly but let's Say we're considering this red piece right here that I'm filling in so this red Checker essentially what are the
valid moves for this piece I'm going to draw them in green so one of the valid moves would be this another one would be this right to hop over this piece but if I move this piece so I remove this blue one then no longer is that a valid move the valid move is if I can go back to green this one right here so this is actually kind of tricky because it looks Simple it looks like just expand on the diagonals and figure out um where you need to move to just say okay is
there you know empty space on the diagonals if there is you can move there right but then again what happens if I add a checker right here so I add a blue one right here I can no longer move here I can only jump over top and if I add another blue one right here at the end now I can't even move on this diagonal at all so hopefully you can understand Kind of the complexity in this uh and why the algorithm we're about to write is actually kind of complicated to figure out where a
chest piece is or a checker piece is able to move essentially we need to look at all of the checker pieces on the diagonals of where Checker piece is and now imagine the situation in which this is a king so if we give him like a little crown or something that's sure this will be our King it's not really a crown but if it's A king it can move backwards right and it has the same rules applying to it ex except it can move backwards as well and then what happens when we can double jump
right so if we have a situation I can't even I don't think I can even set one up where we can double jump uh let me see if I can uh okay let's see if we can get a double jump set up somewhere just to show you an example if I have a piece here and I have a piece here and then Imagine that this expanded on technically a valid move is right here in this Square for this piece it can jump here and then it can jump over there and capture both of these pieces
and you need to keep track of what pieces we jumped over so that we know uh if we remove them so it seems pretty simplistic but actually moving these pieces is pretty complicated so let's consider the ALG that I'm actually going to run through uh I have it up beside me I'm going to bring it up beside me at least and I'll show you what I'm going to do so the first thing that we're going to do is check the color of the piece so is it red or in this case is it blue but
this would be white obviously I'm just doing it in blue because you cannot see white on this background okay so the color is it red or is it blue that determines the direction that we're going to move it in fact I think we already have the direction set on the Piece as either negative 1 or positive one so let's say that we're considering something that's red we can only move down in that direction so what we're going to do is look on this left diagonal and this right diagonal for any valid moves for this piece
we can only move diagonally again right so what are we going to do the first thing we're going to do is we're going to move down one row so whatever row this is on we're going to start from this row right here And we're going to if we're checking the left diagonal and the right diagonal we're going to check one at a time so I'll start by checking the left diagonal here I'm going to look to the square that is one left and one down so on the diagonal right here and say okay is does
this have a piece in it or does it not have a piece in it so the two things here are okay if it has a piece in it is the piece blue or is the piece red so is the piece the same color as our piece if It is we can't move on that diagonal so if this piece right here is actually red then we can't move here right because we cannot have a red move into a piece where another red is now if the piece is empty so if there's nothing there we can move
there that's a valid Square so if it's empty then we say check okay boom we can go there that's fine if it has the opposite color piece in it then we have to keep moving on the diagonal and see if we can jump Over this piece so if there is a piece on this diagonal we need to check the next piece here and see if we can move into that square so if there is not another piece in this next Square over doesn't matter what color it is then this becomes a valid move and we
can move into this Square now this applies the exact same way on the right side of the diagonal as well we'll move over one uh and to the right and we'll say okay is there anything here in this case There's not so we can move there but if there was we need to check the color of it if it's the opposite color we need to check continuing on the diagonal and see if we can move over top of that color to jump it right and if we do jump that we need to keep track that
this move would jump a piece so that we can remove that piece if we decide to take that move now where it gets a little bit more complicated is if you're double jumping or doing something else so actually let Me just erase all of this just and draw a fresh grid because it's getting kind of messy here and I'll talk about how we handle the situation in which we're double jumping so let's just say this is our grid uh it's it doesn't have to be even or neat it's just for the purpose of showing you
here and let's say we have you know maybe I we can change the colors you again we have our red Checker here then we have a blue one and a blue One and we'll expand this out like that okay so technically we should be able to move here to this Square to double jump so what I what I'm doing at least in my algorithm to check this is saying okay if we jump over a piece and we land in a square that doesn't have another piece in it from this Square check if we can jump
any other piece on the diagonals so we already know how to check if we can jump a piece but imagine that there's a piece here and here technically this is A valid move because if we move here we can actually jump over to the other side and jump the other piece so that's something to be aware of as well so as soon as we go here I'm actually going to run the exact same algorithm I ran before right except this time I'm only going to consider a move valid if it jumps over another a piece
for the double jump or triple jump or so on and so forth so as soon as we jump a piece we immediately consider if from the Current position that we jump to we can jump any other piece and if we can we add those moves to the valid mve set so that is how we're going to do this um I'll write the code for it which is more complicated than this uh and then that will be probably the hardest part of this video is writing this little bit of algorithm here all right so let's get
into it now bring the keyboard back get rid of all the wires for my drawing tablet and There we go okay so what I'm going to do is I'm going to say Define inside of board. py getor validor moves and this is going to take self and do we want to take a piece or do we want to take yeah or we'll take a piece instead of row and call all right so first I'm going to say moves equals an empty dictionary what I'm going to do in this dictionary is store the move as the
key so what place we Could potentially move to as a row call so like four five might be a available space that we can move to and I'm going to have this as the key being equal to any pieces that we jump to that move so say that we jump over the piece in 34 to get to 45 then that would be stored in a list that is associated with this key in the dictionary so you know more accurately be it like that so that we know if we move to this move we have to
remove that piece because we jumped it All right so moves equals empty uh dictionary I'm going to say left equals piece. call minus one oops because we're moving left one and then right oops equals piece. call + one so essentially just getting the um you know what's left and what's right cuz that's the diagonals we're going to start considering and then row equals piece. row like that all right so now what I'm going to say is actually I need to check something here Yeah the direction that we have on this piece is actually if I
can find it uh do I have Direction not going to be relevant so we can actually just get rid of it because we're not going to use that we have to do it another way that I forgot so inside of here what I'm going to say is if p color equals equals red or piece. King will do something if piece. color equals equals white or peace. King do something the reason I'm doing this is because we need To check whether we can move up or whether we can move down based on the color and based
on if this piece is a king that's what we need to do now what I'm going to do is I'm going to Define two more methods I'm going to say Define underscore Traverse uncore left which is going to look on the left diagonal for us because we're going to have to do this multiple times I'm going to say self pass and I'll fill in the rest of the parameters after and then next we're Going to say Define undor traverse uncore right which is going to move to the right so we have two methods here that
we're going to call from inside of here to kind of split up this algorithm and just make it a little bit more digestible and easier to see but for our Traverse left I'm going to say where do we start where do we stop how much should we step by and what is the color left and I think one more thing skip only equals that or skipped equals That I'm going to copy these and I'm going to put them inside of Traverse right now let me just explain why I've added all these so start stop step
is going to be for the four Loops we're going to put inside of here the step is the most important because essentially it's telling us okay do I go up or do I go down when I'm traversing through the rows for the diagonals am I going on the top left diagonal or the top or the bottom left diagonal right am I going on The top right diagonal or the bottom right diagonal skipped will tell us okay because we're going to call this method recursively which you'll see in a second have we skipped any pieces yet
if we have we can only move to squares we skip another piece right that's what this is telling us and left sorry this should say right introverse right is telling us okay where are we starting in terms of the column uh when we're traversing to the left okay so that's what this is Telling us so inside we're going to fill in Traverse left and Traverse right and then we'll use them inside of get valid moves so Traverse left I have to look at my other screen here because there's no way I'm going to be able
to do this just off the fly I have to say moves equals a empty dictionary last equals an empty list we're going to say for R in range R is going to stand for row start stop step so again the point of this is that I'm giving the Parameters for my for Loop in the uh or I'm guess I'm giving the arguments for my for Loop and the parameters so that I can simply just put them here and this will tell me okay what row am I starting at what row am I stopping at and
what am I stepping by awesome okay so start stop step next we're going to say if left is less than zero break so if we get to a situation where we're now looking outside of the board so our left is no longer in the range of columns that we Have uh cuz we're going to subtract from left every time in this Loop in fact we can just do that like this at the end then we need to Breck all right so We're looping through all of the rows and we're going to have a variable that
keeps track of left um for us that we just increment as we move through the rows this again will move us kind of on a diagonal pattern which is what we're trying to look for we're going to say current equals self. Board. getor piece and we're going to put R left like that so row and then left which is the variable keeping track of again the column that we're on going to say if current equals equals zero and now we need a more advanced thing inside of here and by the way we're going to copy
almost all this for Traverse right so once we do this there just a few minor changes so if current equals zero meaning the current thing we're looking At if it is zero then we need to check if skip uncore only and not last then what we will say is break okay so to explain this is kind of complicated but what we're going to do and maybe it actually would be easier if we call Traverse left first just so that I can kind of illustrate this better in fact that's what I'm going to do I'm simply
going to say here moves. update self doore Traverse left And then what I'm going to pass is row minus one I'm going to pass the max of row - 3 a uh and negative 1 and I'll talk about this in a second negative 1 piece. call uh wait is this correct sorry piece. color we need the color and left okay so what I'm saying is I want to update the moves with whatever is returned from here which is going to be another dictionary I'm traversing left I'm passing row minus one which means okay if we're
red we are moving up right so we need to move we need to check upwards to see if there's anything valid there so we're going to start remember this is the first parameter here start at the row above the current row that we're at we're going to say okay how far up are we going to look how many rows up am I looking well I'm going to look at row minus 3 or -1 so the maximum of that now1 pretty much says stop at 1 which Means look up to row zero right which is a
valid row and the reason I put row minus 3 is because I don't want to look further than two pieces away from where I currently am and if I start at row minus one and I move to maximum of row minus 3 right then what that means I'm only looking two above the current row that I'm at at most so that's why I'm putting row minus 3 Nega one is saying move up when we increment this for Loop or decrement this for Loop in this case The color obviously is the pce C and left is
where we're going to start for our column and what we're going to subtract as we move upwards that's what this move. update is doing now I'm going to do the same thing for moves. update with right except it's going to be changed a little bit so move. update Traverse right the start stop step is going to be the same p. color will be the same except instead of left we're obviously going to pass right now let's Do the same for white just to show you what I mean hopefully this will make it more clear in
this order of explaining and instead instead of uh yeah Traverse left is right except now instead of row minus one it's going to be row + one cuz we're moving down this time right and now instead of the max it's going to be the Min of row + three or rows right hopefully this is making sense and then instead of negative 1 it's going to be one and left and right Is the same so I think that's right let me make sure I did that correctly yes it is and then outside of here we'll return
moves so uh this method right here Traverse left and Traverse right will return us a dictionary essentially what moves. update is doing is merging this dictionary with the one we currently have uh so that we can have as many things as we want in that dictionary we don't have to say moves equals this and Then go through and add them automatically this this method doesn't Okay so hopefully that's making sense on how we're going up and how we're going down what I'm saying is if current is equal to zero and we skipped a piece and
we have not um seen a piece yet so it like we'll Define last in a second but if we've skipped a piece and last which is a piece that we would skip to move to where we're going to go is not defined Then break the reason for that is if the next Square we look at when we jump over a piece is a blank Square we can't move there because we need to jump to another piece uh jump over another piece to be able to actually make that a valid move now this will make more
sense as I complete the algorithm I like to explain things as I go but sometimes you just have to walk through all of it and then kind of uh go through Parts after so L if skip only uh we'll do something in a Second and else we're going to say moves and this will be R left is equal to last all right and then finally what I'm going to do not finally there's actually more to this I'm going to say if and last why is that an error I don't we'll see in a second so
if last then what we're going to say is if step equal equal 1 row equals the max of r - 3 comma 0 else row Equals the Min of R +3 rows so this is now doing the same thing that we did before because what I'm preparing to do essentially is saying okay if we found an empty square and last had a um a value in it so there was like we found something uh when we were looping which you know what I'm just going to keep going and then I'll explain this so if current
does not equal zero what I'm going to say is L if current docor equals equals color Break else last equals current and we're going to put this inside of a list okay now we're I'm actually almost done with this but I just need to code out a good amount to be able to start explaining this so if current is equal to zero that means we found an empty Square otherwise if it's not so if it has a c it wasn't equal to zero and it's equal to our current color so the piece we're trying to
move is Equal to our piece then we can't move there obviously we're blocked we can't jump over it so we break and we won't be adding any moves if that's the case otherwise we say okay if it wasn't our c it means it was the other color which means we could potentially move over top of it assuming that it's an empty Square next so we say last equals current so then what happens in this instance we're seeing if we can jump right which is the complex aspect last gets equal to Current we loop again and
we look at the next row and we move left and we look at the other diagonal piece say okay if current now so if this next piece is zero and if we skipped and not last break I'll talk about that after if skip only we'll do that but in the situation where it's zero and none of this was true we add this as a possible move so we say okay if it's zero and last existed right then that means we can jump over it so we say moves R comma Left equals last now in the
situation where we find this first and we don't just find um a like a a piece that is the other cutor in between we will add uh the move but we just won't skip anything because last will be equal to an empty list all right now we're saying if last so essentially if current was equal to zero and last which means that we had something that we skipped over now we can actually skip it we're preparing to see if we can double jump Or triple jump right uh so that's what we're trying to do so
what we do now is we say okay what direction were we going were we going up or were we going down because we need to recalculate and this shouldn't say r+ R say r + 3 we need to recalculate um where we're going to stop because now we're at a new position when we recall uh these two functions so what we're going to say now is moves. update and we're going to say self doore Traverse left which is the same one that We're doing here we're going to say R plus uh step so either we're
going up or down based on what the step is if step is negative 1 R will subtract one if it's one add one say r+ step we'll say row and actually is it row sorry this should be R plus step yeah row and then in this case step because we already passed the step so we know what direction we're going in then what do we need to pass after that we need the color okay we're going to pass left Minus one and finally we're going to pass skipped equals last okay so that's what we passed
for that and then we'll copy copy the exact same thing move down a line and do this now except Traverse right and instead of left minus one it's going to be left + one all right so let me make sure I did this correctly I think I did but the whole point of this is like once we get to a point where we've skipped over something so in this case we we found a valid Square we Skipped over something we figured out okay now where are we going to go to figure out if we can
double jump or triple jump what row do we stop at we call this again recursively which means just do it again and see if we can double jump or triple jump from this position and then we actually can just break here it won't matter if we put a break or not because based on the way that this for Loop is set up it won't run anymore but I'm just going to break Just so we're clear that after we do this there's no more valid moves in this current iteration uh and now I need to fill
in this pass here for skip only but it should actually just say skipped okay so let's go to skipped now if skipped we're going to say moves R comma left uh and yeah R yeah R comma left equals last plus skipped so essentially if we're in the situation where we found a valid move uh we skipped over something right uh now What we can do is we can actually sorry this isn't this is the situation where we're double jumping something we will combine the last uh Checker that we jumped with the Checker we jumped on
this move into this move's skip so that we know whether we can jump one or whether we can jump two and which ones we need to remove this is all going to make more sense as we continue doing it but just it's hard to explain this because it is a really kind of abstract Complicated algorithm without really a visualization now the reason we have this break here again is essentially we're saying if we've skipped over something we found a blank Square and we don't have anything that we can skip again we can't move there that's
what this is saying so that means all we have to do here is check if we've skipped because if we skipped and we did find another thing that we can skip over then we can update the move or add Another move that has the last plus this one if none of this is true if we didn't skip anything so we're on the first one as soon as we find an empty Square this is valid moves our left equals last right and there we go and then we check and do this Rec of call to see
if we can skip anym from that blank space um that is kind of how this works uh again hard to explain but that's what we have to do to get this work and now I'm going to go Traverse right I'm going to copy all of This uh and we're just going to update a few of the variables so instead of left is going to say right uh instead of right being less than zero it's going to be right greater than or equal to rows and actually not rows is going to say calls now current that's
fine instead of left again this says right so pretty much anywhere it says left just substitute with right and some of the minuses and pluses We'll have to substitute as well uh yep and this will say right instead of WR minus equals 1 this going to be right plus equals 1 instead of left so it's going to be right that can stay the same with + one and minus one and let's see if there's anywhere else I think that should be good and finally let's turn moves from this and from this okay so this is
the algorithm to determine the valid moves based on a Uh piece right so given a piece tell us all the valid moves this will do it I don't think I messed it up at all uh and now what we what I want to do is just add something that can draw these valid moves so we can actually make sure that this is working so next what I'm going to say is Define draw undor validor moves and why is this break giving me an error let's see what it says instance of list has no get piece
method current equals self. board oh oops sorry so this Should say self. board my apologies guys we're going to have to make quick fix here line 78 self. board R left because we're inside board not game I forgot so the internal representation is different and then here same thing self. board are right okay so that should be good now let's go to draw valid moves let's say self we can say do I should I say moves I'm just going to look at where I've Done this before so actually what I'm going to do is I'm
going to take this method story I'm going to put this inside of game just because game handles most of the drawing so inside of here we'll say Define uh draw valid moves self moves and then what we will do is we'll say okay we need to just draw squares for all of these valid moves so we'll figure out their row and their column and then just draw a circle there for each move So we'll say four move in moves and then we will get the row and column so we'll say row call equals move remember
all the moves are going to be a dictionary okay so we say row call equals move this Loops through all the keys of the dictionary which coincidentally is the rows and columns that are a topple for us there so row call equals move and then py game. draw do Circle we'll draw it on the surface which is self. Win and then what we will do is we'll draw it what color do we want we want blue which I'm going to import from here so blue like that we'll say self.x oops not self.x we have to
actually calculate self.x so I'm going to say row multiplied by square size row multip by square size minus Square size over over two that should give us the middle and then same thing with call so call Time Square Size minus Square size over over two we've already talked about how that works so I'm not going to go over it again and then we need the radius which in this case let's just hard code at 15 okay so Square size we also need to import so let's import that like that and I think that's all I
need to do for draw valid moves now inside of draw or inside of update sorry where is that got to find where the update method is we'll say oops Self. draw valid moves and we'll pass the self. validor moves or self. board. valid moves okay so I think that is or no we have it stored inside of here what am I saying sorry guys after an hour and almost two hours of recording the brain starts to go when I'm talking and doing all of this but anyways self thought valid moves which is stored in here
which should be updated when we select a piece And now I apologize it's been like 40 minutes since we've tested this but I'm going to run this and see what is happening uh oops what is this going on here let's go back here okay so now when I select something nothing is showing up which is great and let's just chess check this okay so I realized why nothing is showing up because I just looked at this here we have not called the select method of our game at all so we need to actually call the
select Method so what we're going to do to do that is we're simply going to say uh game. select row call whenever we press on something and that should be good let's check that out and actually what I'll do here is say if game. turn equals equals red so pretty much just make just let us select the red ones is what I'm saying here cuz later we'll make the we need to import red later we will make the white ones the AI but let's run this And see now if we get anything okay so I've
select and okay so it's giving us some moves but clearly these are not valid so I'm just going to have a quick look at the bug that I made and then I will be back and we can discuss what is going wrong so I've made a stupid mistake here by mixing up inside of the draw move the draw valid moves uh the row in the column so I was like looking through all my code like what the heck did I do wrong like where did I break Something when in reality this just needs to be
changed from call and row because I'm drawing the row uh on the I'm drawing like the X and Y reversed so I was like this looks like it's like getting it right just drawing it Opposite that's exactly what it was doing so I did some debugging and and figured that out out I'm trying to figure out where else I think I printed some stuff out that I want to remove uh maybe not anyways okay but That was the major issue also there was a small mistake I had a break statement I think I went over
this but on line 91 uh 92 The Brak stand was indented just needs to uh in and I guess in indent is that what you want to call it out here so it's in line with the if statement same thing here in Traverse right so let's look at this now all right so more error here in this draw method I just looked at I'm like what the heck what have I done wrong these negative signs Need to be positive signs so what I was doing is saying okay we're going to go to the edge of
the square so the top left Edge and then subtract from the top left Edge which meant we were going up into the other Square which is why it was going off um so that was the issue but now we change those negative signs to positive signs inside of here between the square size and square size over two and hopefully fingers crossed let's click something everything looks to be Working okay great so that's awesome so that is pretty much how this works to get the valid move so I apologize to everyone for uh butchering that horribly
and I'm trying to make sure that the white and red I think the checkerboard pattern is good now we need to worry about actually jumping over pieces updating the valid moves you can see that worked actually move where I moved it uh but there's a few glitches so let's fix that now all right so let's go Back into game let's go into the select method that I don't think I actually ended up finishing um and let's just check and make sure this is all good so first of all I need to get rid of this
else statement which I realize is a mistake and put it like that um I'm not going to explain exactly why but just don't add that lse statement that messes it all up you can read through this and and go back I think I explained kind of how this works okay so after that what We'll do is go back into move and now I'll make it so that if we skip over a piece we actually capture that pie so we're going to move the position is what we've done we'll change turns but what I want to
do is check if the position we moved to had a piece skipped so I'm going to say skipped equals self. valid moves and not piece we're going to say valid moves and inside of here we're going to say row column now we say if skipped then what we need to do is say Self. board do remove skipped like that and then actually we can just put change turn at the end because I think it makes more sense to go afterwards rather than before and looking at that I think that's all we need inside of here
just double checking looks good now we need to add this remove method inside of the board uh class here so what I'm going to do is say Define remove self pieces and and what we'll do is Loop through all the pieces and just remove the ones we need to so we'll say four piece in pieces and then simply say self. board and we'll say piece. row piece. call equals z so that should be as easy as it is to remove all of these Loop through all the keys that are In this uh because it's going
to be a dictionary or not dictionary it'll just be actually a bunch of pieces and we will simply just remove those pieces so we'll just set them equal to zero which you know at the same time we'll remove them okay so now that should work uh let's see how this works now if we run okay so let me go here now let's see if I can move white oh I can great um and what's something that's happening here so I notice that when I'm moving it Doesn't at the end of the move remove these valid
moves so we have to do that so let's actually do that now let's go to move and yes at the end of valid move here where it says self. change turn let's go inside of change turn and let's say self. valid moves equals a blank list okay so that should hopefully fix that let me close this and restart it and now let's test some stuff out so first of all I can't move to any places that aren't valid moves right so click On a piece and try to move it somewhere else you can't you can
only move it to a place that is valid so I can move it there now I can't move these pieces or even select them cuz it's not my turn but I can select the white so if I select this one here now let's go with the red and let's see if we can jump over and looks like it's working when we jump it actually captures it so really with that this is the finished checkers game what we have to add as well now Would be checking if someone has one so I'll show you how we
do that quickly and actually let's just make sure that the king pieces work properly uh before I say that that we finish the tutorial all right so we capture there capture there I'd like to set up some kind of double jump and make sure that that's going to work at some point too so let's do that as well actually um not doing a great job at setting it up though okay let's move this Here um whose turn is it now my turn okay let's go here we can go there I'm trying to move this I
guess I can't move it down uh I wanted to move this one so we could double jump but anyways let's see if we can just get a king piece first as well okay so let's move that there this can go here that can go there all right move you here here go there and King okay that looks like it's Working and now it's white and when I press the king I can jump backwards over the other pieces okay so that's great to see that looks like that is somewhat working now let's move this guy here
and it's hard to play the same game against yourself I'm just trying to get a double jump set up so let's move that here and let's see okay so it looks like I can double jump and that this is indeed valid now it' be cool if I could have done a triple jump in fact maybe let's Let's see if we can get a triple jump and just really test ourselves out here uh and see if that's working so to get a triple jump I'm going to make this guy a king and it looks like something
went wrong so good job we testing that list index out of range board R right so actually when I moved to the last Square we had an issue so let me just look at the code and see what's going on there so first the mistake is here I had row equals equals rows obviously that's Never going to be true because we can't move into rows we uh which is eight we can only move into potentially row 7even but based on the way indexing so I'm saying if row now equals equals row minus one then in
that case we can make this a king so that should fix the fact that that guy didn't go to a King but now I'm trying to figure out what the issue was with that index out of range and let's have a look at that aha so I found the culprit here again this Max on Line 69 should say Min so what happened was we were maxing row plus three or rows which meant we were going to use um whatever the larger one was so we'd use row plus three when we were traversing which meant we
would try to go down um from when we moved into that position and obviously that wouldn't work because there was no more rows to look at so let's just kind of run through and test one more time I'll add one thing to check if someone's a winner and then We'll pretty much be done okay so let's do that let's do that see you go there you can jump I just want to move a white to the other end to make sure that all of that is working okay let's just keep going and white okay so
now he's King and now it's the Red's turn and there we go he can move here okay so that seems to generally be working I'm going to test just one more time and see if this Double jump works so this is crazy look he can go boom boom and if I go there it actually captures both of those pieces so this is working properly great so I am satisfied that this is functioning that the game is working we can move around of course you can add some music sound effects make it look better I'm not
focused on that I always focus on the function first and now let's add one thing to check if someone has one and let's go actually back to board let's go To remove and let's update that method because I remember that I forgot to do something so now when we remove a piece I want to actually check if that piece P does not equal zero first of all and so if piece does not equal zero if p. color equals equals red then remember we have this count up here uh for the red and white left that
we need to update so now what we'll say is okay if P.C color equals equals red then self dot I believe it's red left minus equals 1 else self. white left minus equal 1 now we can even add a winner onto here so we say Define winner and this will return to us the color that won if they W so we'll say if self. red left is less than or equal to zero return Red L if self. white left is less than or equal to zero return oops sorry this should be the way around return
white and return red and then finally return none in the situation where no One W so return none like that now I'm not going to actually like program anything related to that but what I'll do is simply just say if game. winner does not equal none then print game. winner could simplify that but this is fine for now and this is pretty much I'm just trying to show you if you want to check if they win just do this and then inside of here you can do something Specific in my case I'm literally just going
to print out the col of the winner because I can't be bothered to add any more to this now so with that being said this has been Checkers all right so I am back and is the next day and I just read through this code and tested it and I realized that I made a kind of small mistake at the end so I just wanted to hop in here quickly and fix it for you guys in case any of you were running into problems so essentially some of you Probably noticed this but when I said
if game. winner I didn't actually add this winner method to the game class I added it to the board class so that's fine we can just add another one to the game class that simply use as the one from the board class really easy fix but I just wanted to hop in here and show you how to do that so we're just going to have to Define winner inside of our game class we'll take self here and we'll simply just return self do board. winner So that's it let me just run this and make sure
that everything's working now and we can see that it is and we're good to go so let's get back to the original video uh if you guys made it to the end of this video give yourself a pat on the back because I hardly did it is much more difficult than you would imagine to go through and explain about 400 500 lines of code especially because I'm doing this pretty much in one take only cutting out like any major mistakes I Make so if you guys appreciate this please do leave a like subscribe to the
Channel all the code will be a aable in the description in casee your game isn't working or something is messed up and yeah let me know what you thought of this series and hopefully you're looking forward to adding to the AI to this which we'll be doing shortly hello everybody and welcome to a brand new tutorial series on creating an AI for the Game Checkers using what's known as The Minimax algorithm now in these next few videos I'm not sure how many there will be I will not only explain to you how the Minimax algorithm
works but I will then go ahead and show you how we can implement it specifically on our own game that we've already already created which in this case is Checkers now don't worry if you want to use this minia Max algorithm on something else you totally will be able to in fact there's only a few minor changes you'll have to make But since we've already made a tutorial series or I've already made a tutorial series on how to make the checker game I figured it would make sense to implement the AI on this game as
we've created ourself so let me just first show you the game I will note that you can download all of this code which you will need if you want to follow along exactly with this tutorial series from the link in the description there'll be a GitHub link as well as a download link you can Check out either one of them but the idea is that this is the game of checkers we can move pieces around right like this we can capture pieces and we want to make an AI that can play as the white pieces
and can essentially beat us right can be better than we are and in fact the AI we make will actually be quite good uh it might not be able to win in every single scenario but it will be at least competent and it will make moves that make sense now to give you a Quick demo of what that might look like I have kind of a half implemented version here this is another Checker's version I have and you can see that when I move give it a second and the AI will make its move now
let's say I Leave Myself vulnerable like that maybe if I move over here he'll decide to capture me I guess he decides not to because he'll see that I'll capture him right back if he decides to capture me all right so let me move over here let's see If this AI decides to grab me no it doesn't it moves over there and I'm just going to keep kind of moving around and just we can see what movements we're getting okay so the AI decides to make a capture there I'm going to capture back here let's
see what he does he captures me there and you know we can keep moving forward but it is competent it's making moves that makes sense and I've played against this quite a few times and it seems to do a decent job anyways let's Get started this first video what I'm going to do is simply explain how the Minimax algorithm works and then in the next ones we'll actually start coding and going through the implementation all right so let's start explaining the minia max algorithm now I've just drawn a really rough checkers board here just so
we can do some kind of illustrations and examp in some situations and demonstrate to you the complexity of actually creating AIS that can play Games so Checkers is actually a game that has a lot of different potential moves not as many as chess or go or some other games like that and that's kind of why we're actually going to be doing this it's a little bit easier than something like chess but uh there is still a high degree of complexity in fact let's just consider the amount of possible moves that this AI can make in
its current position so let's assume the green is our AI so you know Green like That and it is its turn to move so where can we actually go I'm just going to put blue dots where valid moves are and you can kind of infer where uh which pieces would go there so obviously this piece could go here that piece could go there so we get a blue dot one could go here here and here this guy could jump over here he could jump here this guy could move here and he could move here so
these are all the potential moves in this position we have 1 2 3 4 and 1 2 3 4 eight potential moves so just thinking about that um that's actually not that many moves right we could potentially just run through and look at all of the different moves and see which one would be the best and if we did that we would probably consider that the best move to make would be to actually just capture this piece here with either this one or with this one in fact these moves might be rated the same they
might get the highest score per se if we were going to Score the moves and that was would be what we would do if we were just going to look one move ahead right so if our AI was just really based we didn't Implement any crazy algorithm and all we did is say okay look for a move where we can capture a piece if we can't do that maybe make ourselves a king piece if that's possible and if we can't do that well then we'll just pick some other random move we could Implement that as
an AI and that would be a somewhat Competent AI but it would make a lot of captures that don't really make sense so now what we have to consider is okay how do we make this AI more complex rather than considering just all of the moves it could make we actually have to consider what the out come of its move might be so essentially what will this red player do when we make the move that we just make we have to consider what the other player may do to make sure that for example say if
I capture over Here that I don't just get captured back by this red piece and well we cancel out or maybe I set myself up up to be double jumped or something crazy like that right and in fact if I actually were to capture right here this piece will be able to double jump me like that right it could go here and then it could go over top so So that obviously would be a bad move and well we wouldn't see that if we weren't considering other moves from the other player so the way the
Minimax algorithm works is it assumes that our player the person we're playing against is going to make the best possible move that it can so actually what we're going to do is consider every single possible move that we can potentially make and then for each one of those moves we're going to consider every single move that the other player could potentially make against us essentially what we'll say is okay we want to either maximize a score or Minimize a score and the other player wants to maximize or minimize be the reverse of what we're doing
so now we have to talk about what a score is in every single position so every single possible position of this board we can give it a score now the score will be defined by something that we come up with but a really easy way to determine it is just to Simply count the number of green pieces and the number of red pieces so we can say that the score is Going to be equal to the number of green minus the number of red so if that's the score of our board then obviously green wants
to make this as big as possible it wants to maximize its score and have the most amount of pieces and red wants to minimize that score so that is where we get this minia Max name from so we have to assume that when we make our move we are going to maximize pick the move that has the best potential score and red will pick its Move that has the minimum potential score so what we have to do in the algorithm is consider the fact that we want to maximize our score and red wants to minimize
its score and what we can actually do is draw out a tree and I'll show you that in a second and kind of illustrate how we actually um derive what the best possible move is because that's going to come from a combination of what's the best move for us and what's the best move or actually the Worst move for US based on what red is going to do so hopefully that is kind of making sense that's just like the basis for the explanation and now I'm going to get into actually talking about kind of how
this algorithm works and I'll draw out some more stuff so to start explaining the Minimax algorithm the first thing I need to talk to us about is the decision tree now we're not actually going to make a data structure that holds this tree so don't worry About that but this is kind of the way to visualize how the algorithm actually works and how it searches through the potential options for the moves that it should make so we're going to start by drawing a node here and this is going to be known as our root node
and what this will represent is the current position that we're in so say red moves now it's Green's turn remember green is our Ai and right now this represents the position that green is in so technically We would have a score for this position but we're not going to really worry about that because what we want to do is look forward and say okay what is the best score that I can get based on the Move I Make from here so what we do now is we say okay we need to make a move what
are the potential moves that we can make from this position position well we could go here we could go there we could go whatever right we have a certain amount of moves that we can make and We're going to draw out all of those moves onto their own separate Branch so imagine that this green that I'm drawing here is all the moves that our a AI could potentially make from this position these moves will be different uh they'll all be unique but these are some of the moves that they could make all right so this
is Green's move now after green moves well red has the potential to move from each position that we potentially move to right so Each of these moves are going to now have a new position where the piece that we move will be changed and from there this board will be given some kind of score right and then red will get a chance to actually move as well so what we'll say is okay in this position maybe red has say two moves like this right or maybe it has three moves we can draw it like that
from this position maybe red has two moves and from this position maybe red has say four moves that it Could potentially make all right so these are the moves that it makes and you can imagine that we can continue this tree on to whatever depth we desire in terms of how many moves forward we want to look so maybe we continue on again and we say okay after red moves from this position we can potentially move to here here here or here to keep this simple I'm just going to keep this at a depth of
two uh to explain it to start but we can of course uh put this To a higher depth if we want so just imagine this is kind of how we're looking for it it goes red move or it goes green move red move green move red move and that's how we consider based on every single move we make where the other person might go now remember that when we talk about Minx red is trying to minimize its score and green is trying to maximize its score so let's say we reach the depth that we're satisfied
with we're only going to go depth two or Depth three whatever you want to consider this depth being now what we start doing is evaluating all of the positions so here when it's Red's move at depth three or depth two or whatever this is we'll just you know put a line here uh at this position here red is going to get some kind of score for whatever move it decides to make so let's say that one of the moves score is maybe like -3 maybe another move score is like ne1 and another move score is
Four so we're going to assume the red is going to take the minimum of these potential scores right so it's going to take whatever is going to favor it the most so it will move into the uh position that has a -3 score so what we do now is we draw -3 here here which tells us okay if we make this move uh whatever it ends up being red is going to take this -3 score because that is the minimum score that it can get based on the move that we just made right if We
move into this red position uh or green position Now red has three potential moves it can make it's going to take3 all right so now we'll do the same thing over here so we'll say okay negative3 is scored there now red has two moves based on what move we make here and maybe those moves are like two and three three those are the scores that red can get for moving into those positions again red is trying to Minimize its score so we know that red is going to take the score that has the lowest value
which in this case is two so we draw two Here and Now same thing we move over here maybe we have a negative - 1 netive -1 maybe we have a three and maybe we have a four well we know red is going to take one of the negative one scores it doesn't really matter to us which one they take so we write ne1 here now we're looking at this level because we evaluated all of the Positions that red could do based on the moves that we can make and hopefully this is kind of making
sense or it's starting to click now it's Green's turn right so based on any of these moves that we make these are the score that's going to happen based on what red will take after so what we want to do is obviously pick the move that's going to give us the maximum possible score so we would pick two and we would put two right here which would mean we would Decide to move here and we could assume that after that red would decide to move here then we start this process all over again Red's made
its move it may or may not have decided to go where we thought it goes so now we consider again at our current position all of the moves we could make all of the red all of the moves red could make based on all of those moves and pick the best possible move for US based on what red decides to do hopefully that makes sense but that Is the basic explanation of the Mini Max algorithm red tries to minimize its score and and green tries to maximize its score and we make the Assumption in this
that red is going to take the best possible move that it can make from any position now it may not do that but we're going to assume that it does just to make sure that we're set up for the best possible position that we can be now this actually a really powerful algorithm and you can potentially say if We extended this depth even further right and we had okay now green can go here green can go here you can do this to an infinite depth but that also means this gets exponentially larger right we don't
know how many potential branches we're going to have and we're branching off you know potentially 10 or 20 times off every single move so as soon as we add another depth we're really add we're increasing this exponentially which means that this is going to be a lot of Computations uh if we go to a depth that's too high so for us considering about three moves ahead is totally fine that's probably what we do which will mean our tree will look something like this so we'll consider what red will do after our move and then what
we'll do after Red's move and that will tell us what the best potential move should be so hopefully that explanation makes sense there is a way to optimize this it's called Alpha Beta pruning I'm not Going to talk about that in this video just because we don't need to do it uh and it's something that I kind of want to leave for homework for you guys if you care to add it I'd rather add the kind of default algorithm first and then discuss how we would go about what's known as pruning the tree so removing
potential path maths that we know wouldn't be any good essentially that's what Alpha Beta pring is okay anyways that's the explanation for Minimax Algorithm hoping it makes sense and in the next video we'll actually go ahead and implement this and get into the code hello everybody and welcome to part two of the checkers AI tutorial so in this video we're actually going to be implementing the minia max algorithm now the first thing I want to do though is make sure you guys are set up with the code so please go to the description and download
all of the code so this is what it's going to like here I'm going to Walk through it quickly just to make sure everyone's clear on how all of this stuff works but if you want to see how you actually build all of this code again I already made a series on just walking through and building this checkers game of course if you're interested in the AI then just download the code and we'll go from there but anyways when you download the code you'll see that there is a main.py file there's a Checkers folder an
assets Folder and some init.py main dopy is actually how the game is played in terms of the UI side so this allows us to select certain pieces move so on so forth now we're going to be modifying a few bits of this code so the first thing I want to do is just kind of explain to you how this works so in main.py it's pretty simple this is really just what is actually getting the user input so you can see we kind of have a main game Loop here it's checking if someone has One if
it does you know it's printing the winner and actually what we should do in here is say run equals false which means we're going to quit the game so this is the first addition we can make on line 27 if someone has won the game now what else we see is we have game do select game. update game is a class and that represents the state of the game so game is actually kind of like I don't want to call it an API but it kind of is just an API that we can use to
play a Game of checkers if you go ahead and look in this class you can see we have an update method this simply updates the display and draws it we have winner we have reset we have select which will allow us to actually select a piece or potentially move a piece we have the move method we have draw valid moves and then we have change turn so we can use all of these things um with in this class like any ones that don't have an underscore before them we can use them And essentially that is
just kind of how we actually play checkers So within this class we actually create a board from this init method a board is another class that we've set up the board handles the state of the board so holding all of the pieces allowing us to check what the valid moves are it's the actual checker board whereas the game is more handling like okay can you move there uh do can we allow the board to move over here whose turn is it that's Kind of what the game is handling whereas the board is handling more of
the state of the actual game and it's less concerned with what the users actually doing so if we have a look here inside a board we can see we have some stats related to how many kings are left how many pieces are left as well so red left and white left um we have some methods to draw the squares so the actual checkerboard squares we have this move method which will actually move a Piece to a certain row and column we have get piece which given a row and column will give us the piece that
is at that row and column we have create board obviously this is setting up the board we have draw which is drawing everything and then remove uh that's obviously going to remove a piece or pieces we have get valid moves which given a piece will tell us all of the valid moves that this piece could move to we have Traverse left and we have Traverse right Which is handling how we actually determine where we can move to and that's it for board finally we have piece this represents One Singular piece it stores simple things like
the C if this piece is a king uh it's XY position um it allows us to draw it and to move it and that is kind of the basic setup now we're going to concern ourselves mostly with this game and board class uh we'll just need to use them because as the AI right we're try trying to build This AI we need to know first of all well where can the AI actually move from this position okay we need to have a board that we can use to score right so we're going to need some
way to evaluate the positions we need to figure out all of the pieces that could potentially move so we need to actually add a few things to this code to allow that to work uh we'll do that uh actually maybe we'll do that now maybe we'll do that after in fact let's do it now so the First thing that I want to do is I'm going to go inside of this board class again go inside of here if you just downloaded the code and what we're going to do is simply add an evaluate method now
the evaluate will tell us given the state of this board what is its score now we we'll use a really simple evaluation method which is going to take in take into account how many kings we have and how many pieces we have so Define evaluate self now this means if We have a board object we can just call evaluate on it it will return to us some number positive or negative telling us the score of this board now in the last video I told us that to score a board we would simply subtract the amount
of white versus the amount of red now we can do that if we want so we can return self. white left minus self. red oops uh red left like that and that will give us a positive negative score White's going to be our AI so if white has more pieces Left obviously this is going to be positive now that's fine but I would like to incentivize our AI to actually try to become a king if it can if I don't do this it means that it's not going to prioritize moving to the end of the
board it's just going to kind of slowly move its pieces upwards so if we actually prioritize it becoming a king then it's more likely that we'll see a forward progression and that it actually will try to become a king which Obviously is an advantage advantageous piece to be so what I'm going to do is simply subtract this and then I'm going to multiply the um Red Kings and the white Kings by a negative and positive number and add them together so what I'm going to do is I'm going to say Plus in this case the
self. white Kings left multiplied by 0.5 so that means if we have or sorry not white we'll say white Kings my bad so self. white Kings multiplied by 0.5 and then we'll Subtract here the self. Red Kings multiplied by 0.5 so what this will do is essentially just give us uh another value right so if there's more Red Kings than there is white Kings then obviously this will be zero minus this means we'll actually be subtracting whatever the amount of Red Kings times 0.5 is um from this evaluate or from this score sorry hopefully that
makes sense but this is what we're going to use feel free to tweak this mess Around with it make it more complex if you want the better we make this function at evaluating the board the better our AI is going to be all right now that we have that the next thing that I need to do is actually make a method that can return to us all of the pieces of a certain color the reason I need this is that we can simply use the board if we have a look here it says get valid
moves to get all of the valid moves for a specific piece but if we Want to check all the moves that a possible color could make what we need to do is determine okay what are all of the pieces on the board that are this color and then check all of the valid moves for all of those pieces right if we have 10 pieces all of those 10 pieces could potentially move so we need to actually get all of those pieces so again don't be too concerned about this because this is code that you guys
haven't written yet I wouldn't expect You to understand it but just a few things that we need to add so Define get uncore allore pieces like that that we'll put self in here and we'll say color now what's going to happen is we're going to pass a color in here an RGB color so either red green blue whatever the piece color is and we will Loop through all of the pieces that we're storing in this board and return the ones that are that color so I'm going to say pieces equals a blank list And just
try to follow along here although this code will be in the description as well so not only the old code but the final new code and I'm going to say four in this case row in self. board so if we have a look here this board has an internal representation of all of its pieces it's actually a twodimensional array it looks something say like this where you know let's just imagine it was like a 3X3 checkerboard it would have like a piece Object it would have a zero if there wasn't anything there it would have
a piece object it might have zero piece zero so essentially if there's a piece in that square it stores a piece on object otherwise it stores a zero we can figure out where a piece is by looking at its position in the list in this case this piece would be at 0 0 because it's in the zero withth row and the zero with column this would be at 01 because it is in the zero with row uh or sorry uh this Would be one zero if we're going to go row columns this would be in
the first row and the zeroth column all right so that is kind of how that works hopefully that makes sense but we're sa for row in. board and we'll save for for piece in not self in row and we'll say if piece does not equals zero and piece. col equals equals color then pieces do append piece return pieces all right so make sure I spell piece correctly our pieces Correctly hopefully this is pretty straightforward again just looping through all of the rows for each row we're going to Loop through all the pieces if the piece
is not zero we will check and see what color it is if it is the color that we requested we will add it to the list and we will return it okay so that is I believe all we need for the board we now need to go to game and I'm just going to add one method here cuz we'll need to do this I'm going To say Define getor board and all we're going to do here is say self and then return self. board now actually I'll add one more thing as well so get board
is just saying okay we have this board object right that's stored here we were going to want to get that when we actually start using the algorithm so we'll just add a method to return that next what I'm going to do is say Define aior move now this is a bit um preemptive uh you're not really going to Understand why we're doing this right now but essentially when our AI makes a move what it's going to do is just return to us the new board after its move so rather than saying like oh I'm going
to move this piece here which we could do but that will be kind of complicated what I'm going to do is just make it so that we can just pass a new board object to the game and it will simply update the game with that new board object so all we're going to say Is self. board equals board and we're going to say self. change turn so we'll simply change turns right here um after we get this board or after we update the board because obviously if it's White's turn well we need to change it
to red and you can see that that is what this does okay so now that we've done that uh we're looking good what I'm going to do is add a new folder inside of this directory not inside of the checkers directory Sorry but inside of the like upper level directory that I'm in and I'm going to call this Mini Max now inside of Mini Max I'm going to add a file this isore init.py what this is going to do is make minia Max a package which means I can import stuff directly from this Minimax folder
inside of here now what I'm going to do is make a new file I'm going to call this algorithm pi and you can assume what's going to go in here obviously the algorithm that We're about to write now I will be referencing my other screen just because uh this is a complicated algorithm somewhat and I just don't want to mess it up for you guys so I will be looking over there if you see me kind of peering to the left anyways what I'm going to do is start by importing a few things I'm going
to say from copy import deep copy we're going to use this in a second but what we're essentially going to do is copy the board a bunch of times what Deep copy does is we'll make a actual it's kind of hard to say this but you can make what's known as a I don't think it's a I think it's called a shallow copy or a deep copy a shallow copy will simply copy the reference to a object whereas a deep copy will copy not only the reference but the object itself so essentially said I do
did something like this right xals list yal X if I modify X or Y it will modify both of the variables like if I say x0 equal 1 then That means y0 will equal 1 as well obviously L we don't want that when we're going to be doing this algorithm so if we said something like y equals deep copy of X then what would actually happen is if I modified X or Y now they won't modify each other that's the basis behind deep copy but we'll talk about that after I'm going to import P game
and I think that's all I need for right now I'm also going to define the two colors we're going to be using so I'm Going to say red equals 255 0 0 by the way if you don't have pame installed on your system you will need to install that to get this to work I'll quickly show you how to do that what you can do is open up your command prompt or your terminal if you're on Mac or Windows and what you need to do is simply type pip install py game if you're on Windows
this will be the command you need to run press enter obviously you need to have python on your system for this to work And if you on Mac or Linux type pip 3 install py game for some reason this doesn't work for you I will leave videos in the description that say how to install py game on Mac and how to install P game on Windows and I will also leave cards to them in the corner it should be the top left or right hand corner where you guys can have a look at those and
follow along with that then come back install P game and be good to go all right so we have Red now I'm going to say white now in pi game when we Define colors we Define them with RGB obviously all red zero green zero blue is going to be red and all of the colors is white so 255 255 255 now what I'm going to do is I'm say Define Mini Max and inside of here I'm going to say position depth Max underscore player and game now position is going to stand for the current position
that we are in so what position will actually be is a Board object so we have boards like this right and what we will do is we'll pass different boards to the minax algorithm and say okay based on this board give me the best possible board after this that I should move into as the white player or as the red player so we have position which stands for really the board it's telling us okay this is where we are what current position we're in depth is telling us okay how far am I making this tree
how far am i extending this tree We're going to decrement this and this is going to be a recursive call which means every time we call this the depth will decrease by one next we're going to have Max player this is going to be a Boolean value that tells us okay are we minimizing the value or are we maximizing the value so if max player is true then that means we are trying to maximize if Min player is are is Max player's fault we are trying to minimize again that means we technically could Use this
AI to have the AI play against each other white and red which maybe we'll show later next we have game game is the actual game object that we're going to get right from here in this main.py file we're going to pass that to the algorithm and what that will do is then strip out anything it needs from that in potentially um draw some stuff on the screen if we want to do some visualization all right so the first thing to do inside of the minia max Algorithm is to determine what our depth is now remember
that we only evaluate a position when we reach the end of the tree so in our previous example we had the root node and then we had two side nodes right and then or two or three um nodes after that and then after all those nodes we had other nodes right so it went like the red move or it went the white move and then the red move and we evaluated at the red move and bubbled up those evaluations upwards so we're only Going to actually make an evaluation if the depth of our tree is
at zero so if we're looking at the last node essentially in the branch that we're on so I'm going to say if depth equals equal Z or position. winner now remember that if we look at board we have this winner method that I put somewhere maybe at the top uh I think I had winner yeah winner is right here so we can check if someone has won the game so essentially if uh Position. winner we can just say does not equal none then what we're going to do is return position. evaluate and position now I'll
talk about why we're also going to return position afterwards but the point of this is essentially to say okay if the depth is zero so we're at the last node in the tree meaning it doesn't we're not going any further than this let's get the actual evaluation of that position and then let's return this current position alongside of its Evaluation so we know what evaluation goes with what position now when I say or position. winner does not equal none what I'm trying to say is well if we've won the game then the game is over
there's no need to continue uh evaluating right so that's what this is saying all right so now I'm going to say if maxor player and else so the reason for this you can kind of guess is because well if it is the max player then we're going to do something Different maximize the score whereas if it's the M player we're going to minimize so these two um blocks here the if and else will be similar we can actually copy and paste them and change some things but it's just because Max and Min so the first
thing I'm going to say is the max evaluation that I've seen so far is negative Infinity reason for this is because whenever we check a new position we're going to determine which one is the best and well if we don't Haven't checked anything yet then currently the best that we've seen is negative Infinity right meaning if if we see anything else then is a score higher than negative Infinity which they all will we'll consider that the current best until something else comes along and beats it next I'm going to say bestore path equals none you
can guess what or actually instead of best path let's say best move equals none you can guess what That means that's going to store the best move that we could make and then we're going to say four move in get all moves which I'm going to write in a second this is going to be a function what this function will do is get all of the possible moves for our current position so we'll pass it the position we'll pass it actually the color that we want to consider which in this case is going to be
white because the maximizing player is going to be the white player We're just going to hard code that in there and we will pass it the game in case again we want to draw anything for visualization purposes so actually rather than waiting before we write this I'm going to write this now just so that uh the get all moves function just so that it's clear and that we don't get too confuse and then go back to it so I'm going to say Define getor all underscore moves what this is going to take is a position
it's going to take A color and it's going to take the game now the point of this function is to get all of the possible moves that we could make from the current position so that is why again within this board class we just wrote that method that uh got all moves I forget where I put it but I think it was like yeah uh sorry get all pieces so that in inside of here we can get all of the pieces and then we can check all of the moves for those pieces and add those
into a moves list so I'm Going to say moves equals a blank list moves what this list is going to store is it's going to store the new board so it's going to look like this board and piece essentially it's going to say okay if we move this piece this is what the new board will look like if we move it to a certain position so this is the piece and this is the new board and then we'll have a bunch of these it'll say okay this is you know another new board so New board
and this is a piece that we move to get that new board so moves equals a blank list and I'm going to say for piece in board. getet all moves or not get all moves sorry get all pieces and we just need to pass it the color so we'll simply pass it color like that and what this will do is get all of the pieces of that certain color now I'm going to say validor moves equals board. getet all uh valid moves or get validor moves and we'll just pass it the Piece so hopefully this
is making sense Loop through all the pieces in the board that are the certain color get all of the valid moves for that piece on the board and then say for move comma skip which I'll explain in a second invalid moves. items like that now we're going to do something so valid moves. items is saying okay I want to Loop through since this is a dictionary all of the items now the items is a key value pair right and the key value pair is going to say Row column colon and then it's going to have
a list of all of the row col or sorry of all of the pieces that we would skip if we move to this row column so the way that I've kind of done this is that the keys are going to say okay if we move this piece to this position to this row column position we will skip over and need to remove these pieces that's say if I jumped over another piece then there would be pieces or a piece in this list to tell me which one I need to remove if I take this move
most of these won't have anything because most of the moves we make won't be jumping over someone else but they potentially could be right so that's what we need to consider all right so four move skip in Ballad move. items move again is that row column topple skip is a list of the pieces we would skip what I'm going to say is temporary board equals deep copy board so I need to do this and sorry um instead of we're Going to call instead of position I'm going to call this board it's really the same thing
but board I think is just more clear here so we'll say board but I'm going to deep copy the board because I'm going to be modifying this board in order to determine when I move to this position what the new board will look like so I don't want to modify the same board I want to make a copy of it every single time so that the next piece that I consider has a fresh board that it Could potentially move to um like hopefully that makes sense but we just can't have it be the same board
otherwise every time we move a piece it will move on the same board which means when we're running this algorithm the board will permanently move to all of the things that we're just trying out right which obviously we don't want so now I'm going to say new board equals and this is going to be a new method which we'll write in a second simulate Uncore move of piece move and then 1 second here we need to pass the temp board game and Skip now I'll write this method in just a second but imagine that what
this is going to do is uh or we haven't written this yet but this function sorry imagine what this is going to do is take the piece take the move that we want to make take the temporary board and then make that move on it and return to us the new board that's what it's doing it's telling us Okay if you make this move the new board will look like this and then we're going to store that and we're going to put that in our moves list so we're going to say all right moves. append
the new board like that and then comma the piece so we're going to say all right if this piece moves to whatever move it is then the new board will look like this and then we'll score that board from inside of here and we'll see which board is the is the best and we'll return that and That will be the board that we then set and like technically the move that we make so I hope that makes sense but in here I'm going to say return moves and now I'm going to write the function for
simulate move so Define define simulate uncore move like that this is going to take a piece it's going to take a move it's going to take a board it's going to take game and it's going to take skip all right so what we're going to do in here is simply just say uh if I can look At here board. move so what I'm going to do in here is now move the piece now if I go to the uh board method here and I have a look at move it takes a piece and a row
and column we want to move it to so what I'm going to say is board. move piece and we're going to move that to the move zero move one now the reason I have to do this is just because this is a tuple so I just need to split it up and make it zero and one so this means we'll get The row and then we'll get the column so we'll move this piece to that row and column and then I'll say if skip which means okay if we skipped over a piece or we jumped
over a piece then board. remove skip like that and then return this board so return board like that now technically we don't really need to return the board I'm just going to do it cuz it makes sense we could just actually not have new board equal to this and just use the temp board in side Of here but doesn't make a big difference so we'll leave it like this okay but that is the basics for simulate move and get all moves so now we can move back into our Mini Max algorithm we're actually almost done
but I have to write this core algorithm part now so inside of here what I'm going to do is I'm going to say move uh or sorry not move child comma underscore and in fact now that I'm thinking about it let me just Say um let me just leave move where it is actually and let me go here and just not add piece and actually just add new board because I'm thinking about it now and I don't really care about the piece that moveed because at least for right now I'm not drawing it anywhere if
we do decide to draw the piece that's moving and draw a circle around it and all that which we might do then I will add this back but anyways what I'm going to do is just say new board like that so I'm Going to get rid of the list that I had and just go back to new board all right so new board is there now we're back here I'm going to say four move and get all moves now what I'm going to say is evaluation so I would write eval but evaluation is what I
have to write is equal to Mini Max of the move the depth minus one I'm actually going to write false here and then for the game I'm just going to pass game again all right so before anyone gets Confused with this essentially what I'm saying is okay for every single move that I could potentially make I want to evaluate that move now how I evaluate that is I call Minx Minx will if this is the last branch in the tree so if depth is equal to zero it will give me that position's evaluation if it's
not it will go through and it will do what's about to be Co HP be programmed here again so it's a recursive call we start at the root node and then we say okay Well I want to consider the two moves I could do from here all right so I can go left or I go right imagine those are the two possible moves so from there we Branch down to those and now it says okay well we want to evaluate these so what can I do from these well I can go here and then says
okay well I want to evaluate these what can I do from here and then it keeps going and keeps going until we reach the depth that's desired where it starts evaluating those Positions and then they bubble up so it says okay well this is5 this is-4 so we're going to pick -4 and then that goes back and back and back and that's kind of how it works I hope that makes sense this is just kind of recursion it's hard to explain this with this example because it's kind of complicated but this is essentially getting an
evaluation for each of the nodes that we're considering all right so max valuation is going to be equal to the Max of Max eval and evaluation so this is saying all right well now we got our evaluation maybe it had to go all the way down to the left and had to check a bunch of different things but we know how good this move is so so we're going to see is it better than what we already have in here if it is we'll change that otherwise it will stay the same then what we say
is if Max eval equals equals evaluation we'll say the best path or The best move is equal to the current move and what this is going to do is keep track of okay so if the move that we just looked at is the best one that we've seen so far then let's set that in this variable so that we know that this is you know the best board that we possibly have the best move that we can make and then what I'm going to say is return the max evaluation and the bestcore path so what
this will do imagine if I Call this one time right I call this Minimax algorithm the first time if it's the max player it will go through all of this it will determine the maximum possible move we could make and the best path and return that to me now of course that's not going to happen until we do all of these recursive calls but after all of this stuff has finished it's been valuated we will know what the best path is and we'll be able to return that from here now we don't care about what
the Best path is um when we actually are inside of here so what I need to do is where it says Minx is I'm just going to take Minx of zero the reason for this is that Minimax returns to us a position or some board as well as the value for that position or board right it tells us the best or the worst one depending on how we're calling it so I'm just going to strip off the fact that it's giving giving me the path and just take the number only when I'm returning back to
The caller excuse me do I care about actually keeping the best path so I know this is confusing this is an advanced thing but let's just keep going and hopefully it's somewhat making sense so actually I'm going to copy all this now and I'm going to put it in here and we're just going to change some of these things to say instead of Max eval this is going to say minival this is going to be positive Infinity because the worst that we've seen so far is positive Infinity we're going to say for move and get
all moves instead of white we're going to say red and then we're going to say evaluation equals Mini Max of move depth minus one instead of false we're going to say true again the reason for this is that after we look inside of here right we're evaluating for the best player here so if we're going down another depth then we need to consider what it's going to be for the worst player so it's like flip-flopping so What will happen is it will start by going into this if statement then this will be called with false
which means will then go into this statement then say we Branch even more then this one will be called with true which will go into this statement so it's uh going back and forth between red uh white red white red white to figure out the Mini Max right of whatever nodes we're considering okay so and sorry not best path that should say best move and Instead of best path again this will say best move and now let's just change a few things so instead of Max eval it's going to say minival was the minival of
Minal and evaluation and we'll say if the Min eval equals evaluation then the best move equals move and we can return the best move so and instead of Maxi Val sorry return minival best move so believe it or not this algorithm is actually finished now I'll show you it uh Functioning in a second we do actually have to still call this but let me just run through one more highle time how all of this works so Minimax it takes some board which is telling us the details about all of the pieces on there some depth
which is telling us okay how many positions do I want to consider tells us are we looking to maximize this score or minimize this score and then the game game is relevant right now we might use that later which is why I kept it in but You can remove it if you want and then I'm going to say if depth equals zero so if we're at the furthest down that we can go and we're considering then uh what we'll do is say position. evaluate and return the position or of course in the situation where someone
has one there's no much there's no more further to go down we've won the game so we just return this position and the evaluation now the reason I'm returning both is again because just the way this Works we need to return two things so that we can get not only the best possible um number right so we get you know the highest number the lowest number but we also get what position corresponds with that so we know where to move to anyways it gives us that and then in the situation where the depth is not
zero or someone is not one we say okay are we maximizing or minimizing for maximizing we run this this says all right the Maxi Val starts at negative Infinity the best move yet we don't know and we say four move and get all moves first we get all of the moves related to the current position for the color white which is the maximizing player then what we do is we Loop through all these moves and we evaluate these moves with the Minimax algorithm we so we say okay well if we're only at depth say two
and we need to go to depth zero then let's check what the minia max of this move is right it's recursive so then we call This Minimax and we would go and we would repeat this process and we would then in this case go to the minimizing player if the depth was not zero then the minimizing player would do its thing it would return to us what the Min evaluation is it might potentially have to call Minx again and then all of a sudden we have an evaluation for whatever move we could potentially make now
we check okay is this evaluation better than what we currently have if it Is we set it and we set the best move if it's not we keep going until we've considered all of the possible moves works the exact same thing for M evaluation and hopefully that makes sense I think simulate move and get all moves are uh good enough and let's just make sure valid moves is spelled correctly okay lot of talking sorry I know this is complex I'm trying my best to explain now let's go into the main Loop and I'm going to
show you how we Can do this so right now the game currently works like we can select a piece we can move a piece blah BL blah blah now now if we just run this right now none of our algorithm oh it's telling me inval syntax one second our algorithm obviously isn't going to run because we haven't called it and right now you just play two players so what I'm going to do is simply add a thing inside of here that says if game do I think do I have get turn no I don't I
Can just say if game. turn equals equals white which means the computer then let's call the Minimax algorithm on the current board so let me start by importing it I'm going to say from and remember Minimax is in its own folder so I say from Minimax do algorithm did I call it algorithms No it should just be algorithm import Mini Max all right so now we have that so inside of here I'm going to say Mini Max and I'll actually say the new underscore Board I'll say value comma new underscore board equals the Minx of
the game.get board cuz we want to get the board from this game the color which is white and then we'll just pass the game object all right so value new board what is it saying here undefined variable white okay let me just import white from constants you guys can just add this right here comma white and then that should fix it for you all right so value comma new board equals Mini Max of game. Gboard white game now what we're going to do is say okay game. AI move new board what that's going to do
right is it's going to say okay well the AI has moved so let's update the new board to be whatever board this is and then that will actually change the turn for us and then it will allow uh the red player to move again okay I know this is a lot but let me just test this and see if I messed anything up and what did we get Mini Max missing one required positional argument game ah interesting so let me go back to Minimax and see what we've done ah I forgot to add the depth
sorry guys so what we need to do is say game.get board and we need to pass a depth I'm going to pass a depth of three you're going to notice if you're on a slow machine this will take a while go up as high as you want with the depth but that means the higher the depth you go technically the better the AI will be But the longer it will take to run so you know you can kind of pick your poison on what you want there but let me go and move and whoa okay
we got some crazy thing happening here so let me just quickly check what's going wrong notice that a bunch of stuff just moved when really only one thing should move all right so I've realized the error it's kind of a weird one it's also just based on how I program this game so my apologies to you guys that we're going To have to make this strange fix but essentially the problem that was happening is that these pieces are not copied but the board is copied so what's happening is when I pass piece in here to
simulate move and we move this piece it's changing the actual piece on the board so the board itself isn't changing but it's changing the piece that's associated with the board so what I need to do is get the new new piece that's copied inside of this board and use that Instead to pass here so I'm going to say tempore piece equals I'm not going to I'm not going to deep copy that piece but what I'm actually going to do is say tempore board. get piece because this will copy all of the pieces that are stored
within the board automatically and what I'll do is I'll say piece. row piece. call and then I'll pass a new piece here and now it'll work but or sorry not new piece temp Piece but what this is saying essentially is okay from this new board get the piece that is is the same is in the same position as where this piece would be and that should work I don't think we'll have any errors with that uh but let me run this and just make sure okay so I've just been playing against this for a minute
to make sure everything's working I think it's all working properly the white piece has actually managed to get a king piece I'm Not really playing uh you know the most properly ever uh but now we're running into an issue where it just keeps going in between King not King King not King uh maybe it just doesn't want to actually move so let me see what happens if I open myself up to be jumped he's still moving like that oh and now it decides to move there so maybe the AI is just way smarter than I
think and he actually is moving in some some of an accurate place all right so I've been Messing around with it it seems to work fine I mean you guys can play with it yourself and see if there's any bugs but what I'm going to do now is just show you how we can draw what's being considered by the AI and I'll actually make the depth four and just show you the difference in speed so now if I run this and I move we can see that it takes significantly longer to actually make the move
before it was happening pretty much instantly at least I'm not sure what you guys saw in the video but it was going pretty quickly now it's actually taking more time before it's moving and if I change this to five I almost guarantee it's going to take a really long time to move so let's see I move it there and look at this it's just thinking thinking thinking I can't even move it just Frozen right because adding that one extra layer makes it take so much longer so it eventually moved and that was the move It
decided on but it had to consider so much more so it will be a better AI but you'll have to tell your players hey you know you're going to have to wait for it because well it's going to have to take some time to think now we could add that optimization technique as I mentioned I'm not going to do that um but just wanted to be clear all right so now let's go to algorithm and since we have game inside of here what we can do is actually start drawing some stuff Related to the moves
that the AI is considering and I'll add some like time do sleeps in this so that we can see kind of what it's actually looking at so I'm just going to make a function here I'm going to say Define draw uncore moves I'm going to take a game a board oops b o a r d and a piece now what I'm going to do is I'm going to say validor moves equals board. getor valid moves for the piece this is kind of redundant we've done this before but anyways it's Fine it's just for the drawing
purposes I'm going to say board. draw and I'm going to Simply pass the game. window to it I'm just going to go through all this and then I'll talk about what it's doing I'm going to say py game. draw. Circle and I'm going to say game.win I'm going to say 0 comma 255 0 I'm going to say p.x piece doy and then I'm going to say 50 comma 5 now what what I just did is draw a green Circle around the piece so we're going to pass uh to this draw moves a piece a board
and the game and it's going to draw all the valid moves for that piece just so that we can see it uh and make sure we're not running into any like critical errors and you can kind of visualize how this is working next I'm going to say game. draw uncore validor moves I think that's what I called it and I'm going to say validor moves. keys and then finally I'm going To say pame do display do update and then oops py game. time. sleep and I think I passed milliseconds into this so I'm going to
pass 100 which means we'll sleep for 100 milliseconds now I know I just like rush through that valid moves gets all the valid moves for a piece board. draw redraws the board on the game window so game.win is just the window that we can Draw on P game. draw. Circle draw it on the game window color green that's what 0255 0 is p.x p.y this is the middle of the circle 50 this is the radius five this is the thickness of the outline of the circle then game. draw valid moves this will draw all of
the valid moves the reason I got keys is again because our valid moves look something like this we have like four five comma some piece object in here so we need to make sure that we just pass the actual row call We're not passing that piece object to confuse this method next py game. display. update that will update the display py game. time. sleep this will sleep it for 1 Mill sorry for one seconds so that we can actually see it being drawn let's run this and see what's happening all right so when I do
that nothing happens because I didn't call that method or that function so we need to call that I need to remember where I actually end up calling this From uh because I can't remember but I think I do it inside of the get all move moves that would seem to make sense simulate move get all move yes let's do it inside of here all right so I'm going to say draw underscore moves and I'm going to draw that with the game the board and the piece not important that I pass that temporary board or that
other piece we're not going to see them actually moving we're just going to see them considering these Specific moves all right so let's now do this all right main. Pi run and let's go ahead and move and what is happening py game has no attribute sleep I maybe I messed something up py game. time. sleep is that not an attribute okay you know what guys I don't know why that one's not working usually that's something ah sorry it's not sleep it's delay py game. time. delay all right that's what it should be okay let's look
at this now and we can see that it's going quite Quickly but it's showing us pretty much what it's considering and you can kind of see the pieces moving as it's ulating everything as we go through so this is really what's happening kind of in the back end is it's moving all these pieces it's checking okay if I move in this position what's the score is this the best position should I move here should I move there and notice that it's not only considering the white it's considering the red because it has to Consider all
of our moves based on all of its potential moves so this is obviously going to take a long time to run through and draw everything what I'm going to do is just quit out of this game so close the program it's not responding just because it's not threaded so I can't do that uh and what I'm going to do is remove this delay and you're just going to watch it literally like Zip through which I think is kind of funny to see so now what I'll do is Go like that and it just literally spams
the screen showing us okay we're thinking about where we're going and there you go the decided move was to go from here to here now of course you guys can add stuff to this play around with it but that is all I'm going to do for this tutorial if you guys have any questions as always please leave them down below but that that is how you make a Checker's AI using the minia max algorithm I apologize if any of this Went over your head it is difficult to explain this stuff because it is um you
know somewhat complicated stuff right this is not the easiest thing in the world hello everybody and welcome to another YouTube video in today's video I'm going to be showing you how to make the famous game pong in Python now this is a great project for beginner or intermediate programmers we are going to be using a module called pame to accomplish this however you do not need To know pi game and the features we're going to use from it are very limited a lot of what we need to code out is the logic related to moving
the ball around the screen having it bounce off the different paddles implementing score all of that type of stuff and you're going to learn a lot in this project if you are not say an expert python programmer already with that said let me give you a quick demo and then we'll actually start writing some code so in front of me I Actually have the finished code for this project whenever I do a tutorial I code it out first and then I reference that code while I'm teaching it to you guys and all of the code
that we write in this video will be available in the description anyways let me just run this here and then we can have a look at the finished product okay here we are so this is pong we have two paddles uh you can move one paddle with w and S and the other paddle you can move with the arrow Keys and you also would be able to implement this as a single player game if you wanted to code like an AI for one of the paddles Which would be pretty easy to do you can see
this is kind of the basics we have an implementation of pong and then of course there's scoring at the top and I've just made it so that when you get to 10 then the game is over now I'm not going to play through the entire thing but there you go that is the project and I'm going to show you How to make it so with that said let's get into the code so let's go ahead and get started the first thing we need to do is just set up our environment and install the pame package
now again I want to reiterate here that you do not need to know pame for this tutorial I will show you the limited features from it that we are going to use now if you want to learn more about P game and make some more advanced games I have tons of tutorials on my channel so feel free to Check those out you can probably just go on YouTube and search pame Tech with Tim and you'll see like 10 20 30 different videos all going through different P game projects all right with that said let's get
this set up so right now I'm in Visual Studio code this is the editor I'm going to use for this video feel free to use whatever you want you can use the default idle from python you can use Sublime Text really doesn't matter I'm just going to use vs code now I'm Using python version 3.9 you can use pretty much any version as long as it's above 3.6 other than that what we need to do here is open up a terminal or a command prompt and install pame now to do that we're going to type
in the command pip install pame like that now I already have this installed so I'm not going to run it but for you guys run this command it should install py game now this command does not work sometimes if it Doesn't work try the following Python and then you're going to do hyphen M and then pip install py game if that doesn't work try Python 3 hyphen M pip install py game and finally if that doesn't work try pip 3 install py game now if none of those commands work for you I have two videos
one for mac and one for Windows I will put them up on the screen and they show you how to install P game for the respective operating systems okay so we now have py game installed we can Actually start writing some code now we want to create pong so the first thing we're going to do here is just import pame we're going to set up what's known as a display so in pame we have a main kind of window or display and that's where we draw everything to once we have the display then we'll imp
Implement things like the paddle the ball the scoring uh handling Collision all of that type of stuff so I'm going to import P game at the top of my program And now I'm going to set the width and the height for my window now you're going to notice here when I'm coding everything out that I'm putting everything in variables this way our game will be dynamic and you can simply change the value of a variable and everything will just work and adjust according to that so rather than using kind of hard-coded values we're going to
put everything inside of variables use the variables for everything which will Make it a little bit more complicated to code out however it's going to be really nice cuz if you want a bigger window or a smaller window or a larger paddle or whatever you just change the variable so for the width and the height I'm going to go with 75004 right now by the way this is a way that you can declare uh kind of two variables on the same line in Python okay so now that I have that I'm going to set up
my window so I'm going to put This in a variable called win in in all capitals whenever I do something in all capitals I'm making a constant meaning that this variable is not going to change so to do this I'm going to say p game. display do setor mode and then inside of here I'm going to put a tupple and I'm going to pass the width and the height and I guess at this point in time it's a good idea to mention that you should have some familiarity with python of course you don't need to
be an expert You can be a beginner but you should know things like if statements while Loops for Loops because I'm not going to explain all of the very basics anyways to set up a window this is all we do p game. display. setor mode and then we pass a tupple so just the brackets like this with width and height great now that we have our window we can make a caption for it so the caption is just going to be the title of the window and to do that we do p game. display. setor
Caption and for the caption I am just going to call this Punk okay so this will just be the title at the top of the window when it's actually loaded up so now that we have this what I want to do is Implement what's known as the main Loop of my program or the event Loop of my program which is actually going to display the window and then draw something onto it so I'm going to define a function here I'm going to call this Main and inside of this function I'm Going to declare a few
variables that we're going to use to actually uh kind of show the display and handle all of the events that are occurring so I'm going to make a variable here called run going to make this equal to true and I'm going to do a while loop here and say while run now whenever we have a pame uh game I guess pame program we need a main Loop and the main Loop is just a loop that's constantly going to be running that's handling everything related to Our game so it's handling Collision it's moving the ball it's
allowing us to move the paddle so that's what this is right here so inside of this main Loop I'm going to write the following for event in py game. event. get now this will get all of the events like clicking your mouse clicking the keyboard closing the window that's what this Loop is doing here looping through all of the different events that have occurred we're going to handle those events and Then do something so in here the first event that I want to check is if we are actually quitting the window so I'm going to
say if event. type is equal to py game. quit with all capitals for quit here then I'm going to say run is equal to false and I'm going to break out of this for Loop now what this is going to do is check if we hit the red button in the top right hand corner of our window so the close button if we hit that we want to stop the main Loop so we Actually end up closing the program and then we want to break now outside of my Loop here I'm going to say py
game. quit and quitting is just going to quit pame and close the program for us okay awesome now one thing I need to do here is right after I import pame I need to initialize it so I'm going to say py game.it you should run this whenever you import pame just directly below it it just initializes a few things that you need uh and we'll use this later or this Will allow us to do some things later okay so here we go we have a basic program we have main we have run equals true we
have our wall Loop here which is going to be the main event Loop inside of this we're checking all of the different events and then what I'm going to do here is call the main function so I'm going to say if name is equal to main then call Main now what this does is ensure that we are running this module to call this function so Essentially if we were to import this module so the solution. piy file then what would happen is this would not run because the name of this would not be main now
I'm not going to explain exactly how this works but it really just makes sure that you're only going to run this main function if you directly run this python file not if this python file was imported from another project or from another file okay uh hopefully that makes sense but When we do this we should see a py game window pop up there won't be anything on the window it'll just be a black screen but that's the thing we need to start out with okay so there we go we can see it says pong we
have our P game window and when we click the X it should quit great there we go it quits okay so that's our starting thing now the next thing I'm going to do is Implement something known as a clock now a clock is going to regulate the frame rate of Our game so that it's going to run at the same Pace on every single computer so I'm going to say clock is equal to py game. time doclock and then inside of here I'm going to say clock. tick and I'm going to pass this an all
capital FPS variable which I'm going to Define up here as 60 now the FPS is the frames per second and when you put this inside of a wall Loop it makes sure that you cannot run faster than 60 frames per second or 60 ticks P per second which Means that this while Loop here is going to run a maximum of 60 times per second so that if you're on a really fast computer it's not going to be running quicker than if you were on a slow computer hopefully that makes sense but that's why we want
the clock it just regulates the speed of this wall Loop now it's worth noting that if you're on a very very slow computer this wall Loop may run slower than the FPS that you're putting here this is simply limiting the Amount of times it can run it's not making it run 60 times per second so on almost all modern computers it will run at least 60 frames per second or I guess exactly 60 frames per second but on a very slow computer you may run under this and so you may see some lag in your
game if it's a really slow computer just wanted to note that because some people have mentioned that in my previous pame tutorials okay so now we have our clock and the next thing I want to do is Implement something to actually draw some stuff onto the screen so I like to handle all of my drawing in a separate function so it's really easy to see where I'm drawing everything so I'm going to make a new function here and I'm just going to call this draw this is going to take in one variable which is going
to be the window that we want to draw on now inside of here all I'm going to do for now is fill the window with a specific color just to show you how that Works so I'm going to say wind. fill and then here I have to pass an RGB value now RGB is red green blue now I could just pass the RGB value directly in here but I like to Define all of my colors or RGB values as variables so I'm going to make one called White and this is going to be equal to
255 255 255 then I'm going to make one called Black and this will be equal to0 0 0 okay so those are my two colors up here and what do I want to fill the window with well we are Going to fill it with black but for now I'll just put white so we can actually see uh what's showing up now whenever we do some type of drawing operation in P game we need to update the display manually and then it will actually do all of the drawing so when I do something like a wind.
fill this is filling the entire window with white so it'll change the background color essentially to white but for this to actually happen I need to say pame do Display not clear but do update now this will update the display and perform any of the drawing operations that we've done so maybe I've done a few other drawing operations well I'm going to do all of those and then update the display and updating the display is kind of the most intensive part so doing the actual drawing does not take very long but updating the display where
it applies all of the drawing that's going to take the longest so you only want to do this After you've done all of your drawing okay I'll continue to explain that in a second but for now inside of my wall loop I want to call this draw function so every single frame we're continually redrawing the window so let's call draw here and let's pass to it the all capital win which is going to be the window here that we want to draw on okay hopefully that makes sense let's run the program now and see if
we're getting a white screen okay so notice we're Getting a white background perfect that is what we wanted because we are filling the window with white now I'm just going to change this to Black uh because we actually want a black background I just want to show you how wind. fill works so now that we've done that what I'd like to do is implement the paddles so I want to have a paddle on the left side and a paddle on the right side and then I want to see the paddles actually be able to move
when we hit the different keys on The keyboard so I'm going to make a class here and I'm going to call this paddle and the reason why we're going to do this is because we're going to have multiple paddles and we want their movement uh in different properties to be stored as an object so we don't have to kind of repetitively code this up now if you're un familiar with objectoriented programming I'll explain kind of the basics of what I'm doing here but I do have a ton of videos on my Channel explaining object-oriented programming
in Python okay so for the paddle I'm going to say Define a knit now this is essentially what's going to be called when we initialize a paddle or create a new paddle and what I want to take in for the paddle is an XY width and height now our paddle is just going to be a rectangle one will be on the left hand side one will be on the right hand side and they're going to have different X and Y coordinates on the Screen and we're going to change the y-coordinate based on where we're moving
right so if the user presses the up Arrow key we want to move it up if they press the down arrow key we want to move it down so I'm going to say self.x is equal to X self.y is equal to Y self. width is equal to width and self. height is equal to height now these are the attributes or properties of this paddle which means that each paddle I create will have different X and Y and Different width and height uh corresponding to what we passed here when we created the padle so there we
go we have our initial ization for the paddles now I want to write a method on the paddles Which is essentially a function you can call on them called Draw now draw is going to do exactly what it says it's just going to draw the paddle now our paddle is going to be a rectangle it's going to have the color of white so let's define a class Attribute here called color and let's just make this equal to White because this will be a constant it's not going to change so inside of draw I want to
use the window to actually draw My Paddle on the screen so I'm going to say uh actually pame uh let's make sure the indentation is correct py game. draw and then not. Circle we want dot rectangle like that and I keep messing up my indentation so let's fix that and when I'm drawing a Rectangle with python well this is how you do it py game. draw. rectangle and I need to pass to it where I want to draw it which is going to be the window right and then I need to pass a color well
the color is going to be self docolor that's going to reference this right here which which is equal to White and then I'm going to pass a rectangle now a rectangle is an X Y width and height so in P game when we draw something we draw from the top leftand corner so in pi Game 0 0 is the top leftand Corner okay of the screen so if I draw it something like 101 that's going to be 10 pixels uh sorry right and then 10 pixels down and then if we're drawing something like a rectangle
for example the XY that we're drawing the rectangle at is the top left hand corner of the rectangle then the width and height is well the width and height of the rectangle based on the top left hand corner so you'll see what I mean here when I draw this but I'm going To do self.x self.y self. width and self. height that's all I need to draw the rectangle okay so now we have our paddle so let's create two paddles and let's draw them so I'm going to go here and I'm going to say my left
paddle is equal to a paddle and I need to pass this in X Y width and height so for the X I'm just going to make this 10 so it'll be 10 pixels off the left hand side board of the screen then we're going to pass a uh a y the Y I want to Be directly in the middle of the screen so we're going to say height which is the height of our window we're going to integer divide this by two just to get a whole number and then we're going to subtract this by
whatever the uh height of our rectangle is going to be or the height of our paddle so I'm going to make a variable up here and I'm going to say paddle uh yeah paddle underscore height and paddle underscore width and this is going to be equal to just let me Look at my screen here uh 120 and I realize here that I probably want to go width first and then height second just to stay consistent with width and height up there so I'm going to say paddle width paddle height and we're going to make this
20 and 100 so that's the uh the values for our width and our height okay so we're going to use that now here and we're going to say paddle height divided by two now to explain to you why we want this let's Just quickly open up paint and I can show you so let's zoom in a bit let's say this is our window okay now as I said here is going to be 0 0 now I'm drawing with my mouse so just excuse me but let's write this 0 0 now our height is going to
be all the way down here so height is H this will be H okay so if our height is something like I guess we have 500 then this coordinate right here would be 0 comma 500 so the middle of this is going to be height over two Right so we have H over two but the issue is if I start drawing my rectangle here I'm going to draw it like this because the top left hand corner is where I start drawing it from so what I need to do is draw the top left hand corner
so that my rectangle will be perfectly Center so this will be the center of the rectangle hopefully that makes a bit of sense but to find this position here where we want to start drawing the rectangle from we need to Know the height of the rectangle because if the height of the rectangle is say 100 then what I'm going to do is take whatever the height of my window is divided by two and I'm going to subtract half of this height which is going to be 50 and that will tell me where I need to
sech drawing my rectangle so it's perfectly Center in the screen okay that hopefully again that makes a bit of sense we're going to take the height over two we're going to subtract the Height of our rectangle over two and then that tells us the correct height to draw a rectangle at such that it's perfectly in the middle of the screen okay so let's close this here and let's now Implement that so this is going to be height over two uh minus paddle height over two okay I guess we already have that and then what we
want for the width and the height is just going to be the paddle width and the paddle height now let's copy this cuz it's going to be Very similar for our right paddle so here I'm going to say right paddle except all I'm going to change is where I want the X to be because uh this is going to be different and I'm going to say this is going to be the width and then this is going to be subtracted by 10 subtracted by and then this is going to be the paddel width like that
now again the reason for this is that I actually have to go and paint to explain this if we want our paddle to be say 10 Pixels off the right border okay then what I need to do is make the x coordinate be here right so let's say we want this to be 10 kind of the gap between the right border then I need to account for the width of this rectangle as well as kind of the padding I want between the right border so what I'm doing is I'm taking whatever the width of the
screen is which is going to be right here okay so this would be uh width and then zero this position so I'm Taking the width I'm subtracting from the width this 10 which is the padding that I want and then I'm subtracting the width of the rectangle and that's telling me the exact X coord that I want to put this paddle at and then the height is going to be the same thing that's why I've left it the same okay hopefully that makes sense that is what we have for the right paddle and now what
I want to do is draw the two paddles on the screen so to do this I'm Going to pass to my draw function a list that contains both my paddles so I'm going to say left paddle and right paddle now I'm going to go to draw I'm going to take in paddles like that and I'm going to use a for Loop to draw both of the paddles so I'm just going to say four paddle and paddles paddle. draw and then we'll pass to this the window now why am I getting an error here indentation okay
let's move that over by one and now we're good all right so the Reason I'm doing a list is just because I'm going to do the same thing to draw both paddles so we can just do a for Loop and draw both of them and maybe some sometime down the future we add a third paddle a fourth paddle now we just pass it in the list it will draw all of them for us okay so let's now see if our paddles are showing up let's draw this and we got an issue pame draw has no
attribute rectangle uh am I spelling rectangle incorrectly let's see py game. Draw. rectangle um h ah my apologies guys this needs to be wrecked not rectangle uh that's actually how you draw the rectangle is with rect not rectangle okay let's try this let's run and there we go now we have our two paddles they are perfectly Center in the screen and they're at the correct x coordinates now we want to move the paddles so let's figure out how we can do that okay so to move the paddles we Need to change their y-coordinate right move
it up and move it down now we need a velocity to move the paddles at so essentially how much do we go up or down when the user hits a specific key so I'm going to add a velocity here on my paddle and make this equal to four now notice anything that's going to apply to all of my paddles I'm putting as a class attribute meaning I'm defining it here rather than inside of the initial initialization or inside of a method so I'm doing b equals 4 now I'm going to implement a method on my
paddle and I'm going to say Define move self and I'm going to say up is equal to true now what we're going to do here is call this method on the paddle and if I pass up equals true we're going to move the paddle up if I pass up equals false we're going to move the paddle down by the velocity so I'm going to do here say self.y and then this is going to be plus equals and then the self do velocity but That's only going to be the case if up is equal to false
so I'm going to say if up then we'll do something otherwise do this let me just copy this and then I will explain what's going on here okay so if self.y then minus equal self. Val so if we are going up and we want to move the paddle up now to move the paddle up we need to subtract from the y-coordinate whatever the velocity is right so we'll do that here otherwise though we need to move The paddle down so we'll say self that y plus equals whatever the velocity is so as the Y value
increases we're going down as the yv value decreases we're going up so this should now move the paddle up and down okay so now that we have this we need to actually call this but we're only going to call this when we are pressing the up or down arrow key now to do this we're going to have to get the keys that the user is pressing and then allow uh the paddle to move When they press a specific key now for this game I'm making it two player so we're going to have W and S
allowing the left paddle to move and then we're going to have the arrow keys allowing the right paddle to move now again you could Implement an AI for pong maybe we'll do a video where we'll Implement AI for pong let me know if you want a specific video on that but for now we're just going to do it with two players so I'm going to say that Keys is equal to pame Dokey. getor pressed and this is going to give us a list containing all of the different keys that have been pressed specifically it's actually
going to give us I believe a map uh it's either a map or a list either way I'll show you how we can access and check if a key was pressed so I'm saying Keys equals pame dokey. getor pressed now what I want to do is make a separate function that will handle moving the paddles for me because it's going to be a good amount of logic And I don't want it to kind of clog up my main Loop here so I'm going to call a function and this will be handle uhor paddle undor movement
like that we're going to need to pass to this the keys and we're also going to pass to it the left paddle and the right paddle so that we're able to move them okay so let's make a function now let's say Define handle paddle movement let's take in our keys and let's take in our left paddle and our right paddle okay so inside of Here we're going to check if the user is pressing the W or S key and move the left paddle and then the arrow keys and the right paddle so I'm going to
say if keys and then this is going to be pame Dot and this is a capital Kore W notice this a lowercase w so if we are pressing the W key then we want to move the left paddle up so we're going to say left paddle. move up is equal to True okay and then we'll say if keys and this will be py game. Kore s Then we want to do the same thing but we want to move it down so left paddle. move and then not down equals true but this is going to be
up is equal to false okay this is now handling the movement of our left paddle now let's copy this and do the same for the right paddle except we're going to do this with the arrow keys so just to note here when you want to check a specific key if it's a letter key or yeah I guess a letter key then you're Just going to do a lowercase of whatever the letter is so a q w whatever if it's something like the shift key or the enter key it's usually in all upper cases so for
the arrow keys we're going to say key underscore up or kcore up and for the uh down arrow key it's going to be Kore down in all capitals now all we have to do here is change this to be the right paddle and this one to be the right paddle as well okay so now this should actually be working uh handling Our paddle movement so let's see if this is working by running our code okay so when I run my code now I can move my paddles but notice that my paddles actually go off the
screen so now we need to implement something so we're not going to be able to move the paddle off the screen so to do that I just need to check to see that if when we move the paddle it's going to go off the screen or not if it's going to go off the screen when we move it then we're not Going to let the user move it right so what I'm going to do here is say we will allow us to move the paddle if we are going up so if we're hitting the W
key and the left paddle doy and this is going to be minus the left paddle. velocity uh is greater than or equal to zero okay so if left p.y minus the velocity because that's how much we're going to subtract from it when we move it is greater than or equal To zero which is the top of the screen then we'll let it move however if it's not going to be greater than or equal to zero so it's going to go off the screen even by a slight amount then we're not going to let you move
it okay okay now let's do the same thing down here except we're going to have to check if you're going to hit the bottom of the screen so we're going to say and the left paddle doy this time we're going to add the velocity right so plus the left paddle. V we also need to add though the paddle height so I'm going to say plus left paddle dot this is going to be height like this and we're going to check if this is going to be less than or equal to the height of the screen
so the reason we need this is because the Y that we're referencing is the top leftand corner of our paddle so moving up it's fine to check that because that's the top of the paddle but the bottom of the paddle is the left paddle Doy plus whatever the height of the paddle is right because that's going to give us where the bottom of the paddle actually is on the screen if we didn't have this then what would happen is we'd be able to move it all the way down until it was just barely off the
screen because that's when the y-coordinate is at the very bottom so we need to add the height to make sure that we're not going to look like we're moving off the screen right and now we're checking if it's Less than or equal to the height not great greater than right because if it is less than the height then that's fine we can continue to move otherwise it's off the screen okay so that's what we're doing now we're just going to check the exact same thing here uh except for the right paddle for these ones so
I'm just going to change this to be the right paddle and the right paddle and then same thing with moving down so let's copy this and put it here and now let's Go right paddle right paddle and right paddle okay perfect so so now this should make it so we cannot move off the screen CU we're only going to move if we are not going to move off the screen okay so let's run this and see what we get and notice now that it stops at the very bottom of the screen and stops at the
top of the screen let's just check the opposite and it is all good our paddles now do not move off the screen nice now That we've done that what I would like to do is draw a line in the middle of the screen just cuz I think that looks nice I want to draw a dashed line or a dotted line uh and I will show you how we do that so let's go inside of our draw function just need to reference my cheat sheet here because this is a little bit complicated to do so I'm
going to say 4 I in range we're going to start at 10 pixels we're going to draw up to the height and the increment for Our for Loop is going to be height over 20 now the idea here is that I want to draw a bunch of rectangles to represent kind of a dashed or dotted line now I want the space between the different rectangles to be the same and I want the rectangle uh I guess height to be be identical for every single rectangle so what I want to do is draw one rectangle not
draw a rectangle draw another rectangle not draw a rectangle and kind of have a gap between each of them so That's what this for Loop is going to do and you'll see how I Implement that so I'm going to say if IOD 2 is equal to one then continue now essentially what this means is that if I is an even number then I'm going to continue so I'm going to skip this iteration and I'm not going to draw a rectangle otherwise though I will draw a rectangle and the way I'm going to draw it is
the following I'm going to say py game. draw. rect I'm going to draw this on my Window the color is just going to be white so we'll draw it white and then the x is going to be in the middle of the screen so to do this in the middle of the screen we're going to say width over two but we need to subtract half of the width of the rectangle for the same reason we did that with the height when we were initializing the Y of the paddle so now if we're looking at it
horizontally right if we want to draw it right in the middle of the screen then The x coordinate can't be directly in the middle it needs to be whatever half the width of the rectangle is to the left of the middle so that it looks like it's directly in the middle so I'm going to say width over 2 minus 5 because the width of my rectangle here I'm going to make 10 actually let's see if that's what we're doing um I think yeah that's fine okay now for the y-coordinate I'm going to make this I
now the reason I'm making it I is because I'm saying I want To have 20 rectangles on the screen right so when I say height over 20 that means that we're going to do this for Loop 20 times times cuz we're going up to height and we're starting at 10 so we'll do it either 20 or 19 times either way though the reason I'm doing I is because we're going to be essentially picking what y value to draw at based on whatever the for Loop is currently at so we're going to start at 10 then
we're going to skip one then we're going to be At whatever height over 20 * 2 + 10 is because that's how much we're incrementing the for Loop by every single time and so this will make it so our rectangles are evenly spaced out cuz that's how much we're incrementing the I by every single time so I'm using I for my height so width over 2 - 5 I then the width of my rectangle is going to be 10 notice this value here is half of the width right and then the height of my rectangle
is going to be height over 20 Because that's how much I'm incrementing the uh for Loop by so I need to make sure that's my height so that we're getting kind of the correct spacing for our rectangles I understand this a bit complicated this is how you do a dashed line there is some other ways to do it but they take up a lot more code so I'm going to do it in this way okay so let's just see if going to work now before we go any further let's draw this and notice now we
get a nice dashed line or Dotted line through the middle of the screen uh the top and bottom spacing might be slightly off but for me this looks fine now you could make this a solid line if you want that would be a lot easier but we're going to go with dashed for now okay so I think that is all good now what I want to do is implement the ball so we want a ball that's going to be moving on the screen now let's just go into paint here and quickly discuss kind of some
theory Behind this because this is not trivial to do so we want a ball and this ball needs to move in two directions right it's going to be moving in the y direction and in the X Direction now it's also going to collide with paddles we'll talk about the Collision in a second but for now we want the uh the ball to move around the screen and to be able to collide with something like the ceiling now to move it as I was saying we need a velocity in the y direction And a velocity in
the X Direction now we'll start by moving the ball just in the X Direction and based on where it hits the paddle we'll change its y velocity but just understand that we have kind of two components of movement in the X Direction and in the y direction and we're going to have to calculate what those velocities are and then move the ball by that velocity every single frame so hopefully that makes a little bit of sense but that's Kind of the idea here behind the ball and I just wanted to explain that because that's what
I'm about to start coding out so just like we add a class for our paddle I'm going to do one for the ball we don't necessarily need one but it's just going to make things a little bit simpler so I'm going to say class ball I'm going to say fine underscore uncore nit we're going to take in a self XY and a radius okay we're going to do a Circular ball I know some pong games do a rectangular I guess you can't really call it Ball but a rectangular object moving around we're going to go
with the circular one so over here I'm going to say self. xal x self.y equal y self. radius is going to be equal to radius and then self. xor Vel is going to be equal to Vel it's actually going to be equal to something called Max Vel which I will Implement in a second and we're going to say self. Yore V is equal To zero I'm going to implement my Max velocity so I'm going to say Max velocity is equal to and we'll go with five now the idea here is that I want to initialize
the x velocity as whatever the maximum velocity is in the positive direction for our velocity we can have positive or negative and that will change the direction that we're moving right but I'm going to make this positive meaning it's going to be going uh actually to the right first I believe Yeah should be going to the right anyways I'm initializing the x velocity as the maximum velocity meaning that we're going to be moving to the right at the maximum velocity when the program starts then once it hits the paddle we will simply reverse the x
velocity and calculate the Y velocity based on where it hit the paddle at but the maximum velocity is telling us what the maximum possible velocity is in either direction so we'll always be moving at the max Velocity in the X Direction but the y direction velocity is going to change depending on where we hit the paddle because we're going to have to change the angle at which we want to move the ball okay again I know this getting a little bit confusing but hopefully that makes a tiny bit of sense now we're going to implement
a method called Draw so very similar to our paddles we're just going to say self win and we're going to go in here and say uh this will Be P game do draw Dot and then Circle we're going to pass our window we're going to have a color which we'll Define up here as just white again just doing this so we can very easily change the color and then we want a radius so we're going to pass the window drawn the color the radius and the X and Y position now I'm actually not sure if
this is correct I think we have to do the X and Y before we do the radius so I'm going to do Self.x self.y make sure that's in a tupple and then the radius comes after and I think that is correct perfect okay so now we have draw we have initialization and and let's Implement move while we're at it because this is pretty straightforward so we're going to say Define move and all we do to move is we move the X by the x velocity so self doore x self. xcore v sorry and then self.y
plus equals the self. Yore velocity okay so that's how we move the Ball uh this is our draw I think that is all good for now and the reason we can do plus equals is because if the velocity is negative then that will be equal to minus equals right it'll just move it in the other direction okay so now we have our ball we need to initialize our ball so let's go in where we have our left and right paddle and let's make the ball and say the ball is equal to ball now what's nice
about the ball is that the X and Y position for it Is the center of the ball meaning that if we want to put it in the center of the screen we can just actually calculate the direct middle and then place it there rather than having to do kind of the calculations here we did by subtracting you know half the width and that type of stuff so for the X and Y position of my ball I'm going to put it directly in the middle of the screen so I'm going to say width over two and
then I'm going to say height over over two Now the reason I'm doing two division signs here is because this is integer division it's just going to give me the rounded division because I can't draw at a floating Point position all right so we're going to go height over over two and then lastly here for the radius we're going to make a variable we're going to call this ball uncore radius and for now we'll go with a radius of something like seven uh and we can of course change that later on if we want So
let's now pass the ballor radius now we want to draw the ball so we're going to have to pass that to our draw function so pass the ball we're going to take in the ball here in draw and it's very easy to draw this because of the method we have we're just going to say ball. draw and draw it on our window great so now we have our ball this is the class uh and I think that's actually all we need for right now so let's run the program and see what we're getting And we
got an issue let's see what the error is says uh maxvel is not defined my apologies we need to add a self. maxvel here rather than just maxvel because I have to reference it from the class okay let's try this now and we got another issue it says ball object has no attribute maxvel ah we need an actual L here or an uppercase L rather than a lowercase one let's see if we get any other errors okay there we go so the ball is In the middle of the screen is not moving right now because
we're not calling the move function or the move method sorry but once we call that we'll see that the ball actually starts moving on the screen then we need to handle Collision so let's move the ball to do that we're going to go to under actually where do I want to move the ball yeah it's going to do it right here I'm just going to call ball. move inside of my main Loop here and now we're going to be Moving the ball every frame by whatever its velocity is okay so let's run this now and
let's see and notice the ball is moving to the right of course it's going to go off the screen cuz we're not handling any Collision let's run it one more time in case you missed it you can see the ball starts moving to the right now if we change the v y velocity it would move on an angle but for now we're just moving it in the X Direction so that's what's happened okay so now that We've done that we need to start handling Collision now I will admit this is not the easiest thing in
the world to do but of course I'm going to try my best to explain it to you uh and you will have you know Collision handled by the time this is done so let's go into paint again and let's just talk about how we're going to handle Collision first of all with like the ceiling and then we'll talk about the padels so we have this right here okay Now let's say we have a ball and let's say it'sa trajectory is here okay so it's kind of moving up in this direction and this direction and the
average of the components makes it so the angle it's moving at is here so if the ball hits here and it's going in this Direction with the Y all we actually need to do to make it bounce off of the wall is we need to kind of Bounce It Off on the exact same angle that it hit the wall at right so if you have like a wall Like this and you hit like this you go here right pretty straightforward if you hit coming pretty straight on you're going to come out going pretty straight on
as well if you head at a huge angle you're going to come off at a huge angle so that's how the Collision is going to work works either in the x or y direction now when we're talking about the ceiling all we actually need to do to implement this is we just need to change the direction of the Y velocity So here this y velocity would actually be negative because we're going upwards so to make it bounce off all we do is swap whatever the current y velocity is to the positive direction and then that
moves us down hopefully that makes sense that's all you need to do to actually handle collision with the ceiling which we'll do shortly now that's the easy part collision with the paddle is a little bit more difficult because we're not going to do this in kind of a Physics real way so let's say we have our two paddles here now in pong the way that the Collision Works at least my understanding of the way that the Collision Works is you're going to bounce the ball off of the paddle based on where the ball hits the
padle not based on the angle that it's coming in at now if the ball was coming at an angle like this if we're talking about real physics we should just bounce it off at the exact same Angle now the Reason why we don't want to implement it like that is because that means our games are always going to be the exact same assuming you can line up the paddle you never can change the direction of the ball whatever Direction it hits the paddle out is the direction it's going to come off at so we need
a way to actually manipulate that so we can have a game that's playable so the way that I'm going to do this is I'm going to figure out how to move the paddle BAS Based on its direction from the center of the paddle or sorry not move the paddle how to move the ball based on its kind of displacement or distance from the center of the paddle so if the ball hits here then I want to Bounce It Off on an angle like this okay if the ball hits here then I want to Bounce It
Off on an angle like this if the ball hits in the direct center of the paddle then I want to bounce it like that so the further away from the center it is the Higher the angle is I'm going to bounce it off on so we're going to you know have something along the lines of this and we'll calculate this using a custom function that'll show you how to write but that's the idea here with the ball so that's going to be more complicated to do but when the ball hits like here we're going to
bounce it off pretty much in the center because this is almost directly in the middle right so we'll bounce it a tiny bit higher than that But that's kind of how we're going to do the collision with the paddles so let's say we have a paddle here okay this is the middle of our paddle this is going to be the XY coordinate and then we have a ball and this is the center of the ball so let's just go through some of the math here so we we first need to figure out where the middle
of this paddle is so we can calculate the displacement between this and this okay so to do that we're going to take the Y-coordinate which is right here so let's call this y1 let's put a y1 here and we're going to add to this half of the height of the paddle so H over two okay so we're going to add H over two again I'm using my mouse here this is pretty hard but this is what's going to give us the middle so we can say uh this here is equal to M okay so this
is M the middle now once we have M all we're going to do is subtract M from the y-coordinate of our ball so we can call This Y 2 okay so we're going to take M and we're going to subtract Y2 now if this gives us a negative value that means we are above M if it gives us a positive value that means we are below M so once we have the displacement so we can call this D we need to figure out what the velocity should be in the y direction based on this displacement
that's where it gets a little bit more challenging and I'm going to dive into that math in a second but for now we Understand how to calculate the displacement once we know the displacement we just need to make it so that when you're at the maximum possible displacement uh in the you know up direction or the down Direction you're going to move at the maximum possible velocity whereas when you're at say a zero displacement you move at a zero velocity in the y direction okay uh hopefully I'm not confusing you guys too much I just
wanted to give a quick Rundown because now we're going to implement the Collision which which as I've said is fairly complicated so let's do a function here and we're going to say handle Collision now to handle the Collision we need the ball the left paddle and the right paddle Okay now what's nice is that we only need to adjust the Y velocity of the ball really that's the only thing we're going to do here but we need to handle it on the Left paddle right paddle and the ceiling so let's start with the ceiling because
that's the easiest so we're going to say if the ball dox are actually not X we only care about the Y CU we're going up and down right we don't care about the Left Right Collision right now so we're going to say if the ball. Y plus the ball. radius is greater than or equal to the height of the window then we're just going to say ball. ycore V multipli equal by1 so simply going to reverse the Direction now we're going to say l if the ball doy plus and actually minus sorry minus the ball.
radius is less than or equal to Zer then ball. Yore Vel this is going to be multiplied equal by1 now that's actually all we need to handle the collision with the ceiling so let's just look at this one here this is saying if we're going to hit the bottom of the ceiling right so the height we're checking the ball do Y which is the center of the ball plus the ball do Radius it's important you add the radius if you don't do that it's only going to check for uh collision with the center of the
ball we don't want that we want it with like the edge of the ball which is the radius right so if that's the case then we just uh what is it change the direction reverse the direction now we do the exact same thing in the other direction except this time we need to subtract the ball dot radius not add it because we're checking up not down okay There you go we're now handling collision with the ceilings now after we check that we need to check if you're hitting the left paddel or the right paddel let's
start with the left paddel so we're going to first check the direction of the ball because we're only going to see if we're hitting the left paddle if we're moving left right so so if the x velocity is negative that means we're moving left then we'll check if we're colliding with the left paddle Otherwise there's really no point in doing that so I'm going to say if the ball Dot and it's going to be xcore velocity is less than zero then I'm going to check if we're colliding with the left paddle otherwise I'm going to
check the right paddle so I'm just going to add a comment here so to check if the ball is colliding with the paddle we need to check both the X and y-coordinate and check if the y-coordinate is within the range of Where the paddle is on the scen green so essentially if the Y value of the ball is greater than the Y value of the paddle but less than the Y value of the paddle plus the height of the paddle that's going to tell us if it's where the paddle is on the screen essentially then
once we check that so if the Y coordinates are correct if it's in the right range we need to check if the x coordinate is the same as the edge of the paddle that's essentially what we Want to look at so I'm going to say if the ball doy we're going to say is greater than or equal to the paddle doy because remember this is the top left hand corner of the paddle and the ball doy is this is going to be less than or equal to the paddle doy plus the paddle. height so that's
the first thing that we want to check now after we check that we want to check if the x coordinates are correct now I could do this on the same line but just so it doesn't get too Messy I'm going to do another if statement and I'm going to say if the ball. X and this is going to be I need to think about this for a second minus the ball do radius and we're going to check if this is less than or equal to the paddle. X plus the paddle. width okay let me check
my cheat sheet to make sure I did this correct uh I think I did looks good to me okay so the reason we're doing this let's go to paint quickly is because we're checking the Left paddle so if this is the paddle right here we know the top left hand corner XY is here and we know the edge of the paddle in terms of the x coordinate is going to be the X plus whatever the width is so that's what we want to check now we have our ball this is the center of the ball
so we need to account for the radius which is what we're doing so we're taking the ball to X we're subtracting the radius which gives us the edge of the ball and we're Checking if that edge is less than or equal to this Edge right here if it is we're just going to change the direction of the X and that will then change how we move the ball off the pad okay so let's try this out let's go here and for now all we're going to do is change the x velocity we'll deal with the
Y velocity later so I'm going to say ball. xcore V multiplied equal by1 okay it's just going to change the direction so now we Move from the left to the right okay so that is handling the Collision for the left paddle now handling for the right paddle is a little bit different so we're going to say if the ball. Y we actually can copy this for the Y so we'll do this except we're going to check p paddle uh I keep saying paddle sorry this needs to be the left underscore paddle This needs to be
the left underscore paddle This needs to be the left underscore paddle my apologies Guys fix that so this will be left underscore paddle and then for here this makes it actually easier we just make this right paddle okay so right paddle and right paddle okay so now we've checked the Y for the right paddle now we need to check the X the x is a little bit different we're going to say ball. X Plus ball. radius and we're going to check if this is greater than or equal to the right paddle dox okay and if
it is we're going To say ball. xcore V multiplied equal by1 okay so the reason why this is a little bit different for the right paddle is because when we're moving to the right we're going to be checking the left edge of the right paddle and that is represented simply by the x coordinate of the right paddle because that's the top left hand corner whereas when we're moving to the left we're checking the right edge of the left paddle which means we had to add the Width now the reason we're adding the radius is because
we're moving to the right so the radius is going to be to the right side that we're checking rather than the left whereas here we were subtracting the radius hopefully that makes a little bit of sense but I think this is going to be good to allow us to move the ball left and right on the paddles let's check this out and then we'll deal with the uh Y which is a bit harder okay so let's see this now it Should bounce off the paddles okay so it didn't bounce off the paddle which means I
made a mistake here let me check the mistake and I'll be be right back all right so I found the error this is kind of a silly one I'm not calling this function so I WR this wrote this function but I didn't actually call it so of course the Collision is not going to be handled so we need to call this now so after we move the ball uh then we'll handle the Collision so we'll say Handle and then this will be Collision like that we're going to pass fall left paddle and right paddle okay
fingers crossed hopefully this should work now let's run this and let's see if it bounces off there we go so it bounces off and notice that it doesn't really matter where I have the paddle it's just going to bounce off at the same direction uh because that's all we're doing right now now if I move the paddle it should just go off the screen and it Does because while it's not going to collide with the wall we haven't implemented that great so there we go that is now dealing with the Collision now we want to
deal with the Collision in the y direction again a little bit more complicated but we need to calculate the displacement between the ball and the center of the paddle and then determine the angle that we want to Bounce It Off on now we don't actually need to use trigonometry because of the Way that I've implemented this but you're going to see the math is not uh not super straightforward so the first thing we need to do is calculate the middle y of the panel so we're going to say middlecore Y is equal to and then
this is going to be the in this case it's the left paddle so the left paddle. y then this will be plus the left paddle. height / two okay that's fine now the next thing we want to do is calculate the difference in y between The ball and the middle of the Y paddle or the middle of the left paddle sorry so I'm going to say difference in y is equal to and this will be the middle y subtracted by the ball. Y now that we've done that we need to figure out essentially how much
we need to divide this value by to determine what the velocity should be so let's go back to paint here and let's deal with some more math so we have a Max velocity so let's call this V okay the max velocity is Equal to I believe we had five okay that was a rough five that's better five so let's just call this MX for Max velocity equal to 5 now what we need to do is make it so when we're at the maximum possible displacement that's when we get this maximum velocity right so if we're
hitting the very very edge of the paddle so we hit right here that's when we get a maximum velocity of five now when we don't hit this we want it to be a little bit less right so I want the velocity to Maybe only be four when we hit here so essentially how do we figure this out well what we need to do is figure out what value we need to divide whatever the distance is to make it so that maximum possible value we can get is five and then any other value we get will
be smaller than five I understand this is a bit weird but we want it so that the distance or the displacement divided by some value gives us five when we're at the maximum possible Displacement value and then when we're not at the maximum it gives us something a little bit less than five and as we get closer to the middle it gives us a smaller value that should reach zero so our range is 0 to five we need to take our displacement and then squeeze it in the values 0 to 5 hopefully this following a
little bit um again not the easiest math in the world but we're going to have a maximum velocity of five okay that's our MV and our maximum Displacement okay is going to be equal to half of the paddle so if we're taking the displacement from right here then the maximum possible displacement we can have is that the center of the ball is right here at the very edge of the paddle which is just going to be half the height of the paddle okay so our maximum displacement is height of the paddle divided by two so
we have these two values and now we need to figure out what I'm going to call a reduction Factor and the reduction factor is how much we uh take the displacement between the paddle and the uh what do you call it and the ball and divide it by okay so now we also have D so let's write a variable D let's go back to this uh no I don't want a pencil I want brush okay D so we have D this is equal to the diff distance between the middle of the paddle and the uh
the Bol so the way that we figure this out is we say that our uction factor which I'm going to Call R so we want to have d/ R is equal to MV when when specifically D is equal to MD so when the displacement is equal to the maximum possible displacement that we can have and we divide it by R we want to get the maximum velocity that's what I'm saying here now it doesn't matter if it's positive or negative because we'll get either the maximum positive or maximum negative velocity anyways that's kind of the
equation that We have now fortunately we can solve for R because we have a value for D and MV now once we solve for R we just use r as the reduction factor and then that's going to give us what we need for the velocity for our ball so if we plug in D which is going to be MD which is just H over 2 then we have H over 2 over R is equal to MV and we know MV which is 5 now H over2 is going to be variable based on the height of
the paddle but I think we actually know that this value Is 50 anyways I'll show you how we solve just using the variables so if we have H over2 over R is equal to 5 and we're looking for R then what we need to do to actually solve this is we need to do the following we're going to have to flip R and H over2 so we're going to say R over H over 2 is equal to 1 over 5 okay because what we do to one side we need to do the other side then
we're going to take H over2 and we're going to multiply it by the one right here so we're going To have H over2 over 5 is equal to R okay so it's going to be whatever the uh the distance is the maximum distance over five in this case it would just be our Max velocity so that could potentially change is equal to R and then we take in the future whatever the displacement is divided by R and that gives us the value I know that was a lot I'm sure it's not 100% clear once I
write this maybe it'll make a bit more sense but I just wanted to go in and try To explain how that works okay so now I'm going to calculate the reduction Factor so I'm going to say reduction factor is equal to this is going to be left paddle do height divided by two okay divided by two and then we're going to take all of this and we're going to divide this by the maximum velocity of the ball so I'm going to say ball. maxcore Vel like that okay now we have the reduction Factor now that
we have this we need to use this to Calculate the Y velocity so I'm going to say the Y velocity is equal to the difference in y divided by the reduction Factor okay so now this is going to squeeze our difference in y within the range of 5 to5 which is now going to allow us to update the Y velocity so now we can say B yv is equal to the wal okay now it turns out that we do the exact same thing here with a few minor changes uh inside of this function we just
need to change left paddle to be right paddle And it will give us the exact same result now there's there is a lot of repetitive code here uh theoretically we could maybe write a function to calculate this for us but for now I'm just going to put it inside of here because I think this is fine so let's run this now and see if it's working so if I look at this paddle here it's actually bouncing in the incorrect Direction okay I need to fix that yeah same with the other paddle so it's Giving us
the reverse of what it should be uh so I'll show you how we can fix that but it is bouncing on an angle which is what we want so the reason it's giving us the reverse of what we want is essentially because we just need to multiply the Y velocity by NE 1 we're going to say 1 by y velocity and -1 uh multip IED by y velocity how did I mess that up twice okay let's Rewrite this1 multip by y velocity now it should give us in the other direction you can Look at the
math and you'll probably figure out pretty quickly why it's giving it to us but it's because we're taking the middle Y and subtracting from ball y if we do ball Y and subtract by middle y then we don't need to do this but I think this makes more sense so that's why I'm doing it this way anyways let's try this let's see what we get okay now it's bouncing in the correct direction nice that's what we wanted no when it hits the edge of the Paddle it's going to bounce more down okay there we go
we got it to Bounce Down nice awesome and it bounced off the ceiling completely fine so this is working as I anticipated now what I want to do is I want to make it so when it goes off the screen we actually increment some type of score and display that okay so let's get started on that our Collision is working properly as you notice the closer we got to the center the more the Ball bounced off straight and the further away from the center the more we had an angle that's why I was doing all
this math that's kind of how that works okay so now we want to implement some type of score so to do that we need two variables we're going to say left score and right score so the left score will be equal to zero and the right score will be equal to zero as well now to check the score we just need to see if the ball moves off the left or the right Hand side of the screen so I'm going to say if the ball. x is less than zero then this means that the right
player scored because it came off the left hand side of the screen so we're going to say right underscore score plus equal 1 L if the ball. x is greater than and this will be the width of the screen then we are going to say left score plus equals 1 now that we have both of scores we can pass those to the draw function so we can say left score like This and right score and then if I go to my draw function I can now take in the score so we'll say left score right
score and we want to draw them on the screen now to draw them on the screen I need something like a font right I need to actually draw text on the screen so to do that I need to write a font so to make a font you can do the following score font is equal to py game. font. Sy font like that now this takes in the type of font which I always just use as Comic Sands and then the size of the font which I'm going to go with as 50 feel free to modify
these values but this is the font you want and this is the size of the font and now you use this font object to actually render text that you put onto the screen so inside of my draw function here I'm going to use score font and I'm going to draw this uh at the top just so that the ball can be drawn over top of the score so whatever I draw first will be drawn First meaning that whatever I draw last is going to be on the very top so I want to draw the ball
last that it will be over top of my score okay so the way that I do this is I say the left score text is equal to the score font and then I call render and I pass to this the text that I want to render which is going to be an F string containing the left score okay and then I'm going to pass one and I'm going to pass the color which is just going to be white now one Stands for anti-aliasing just always make this one okay so you do the text anti-aliasing the
color and that's what we have now F strings allow you to just embed Expressions directly inside of a string so I'm just doing the score here directly inside of the string to avoid having to convert it to a string using the string function now for the right score it's going to be the exact same thing except right score okay so now this actually gives me a drawable object Now that I have a drawable object I want to draw it on the screen so I'm going to say wind. blit and I'm going to blit the left
score text and then I need to pass an X and Y location for it now I want the left score text to be exactly in the middle of the screen on the left half of the screen so this is actually fairly easy to do but I'm going to say width divided by four not divided by two because I'm trying to put this on kind Of the first quarter of the screen or the first half of the screen in the center so I'm going to say width over four and I'm going to subtract this from the
left score text. getet underscore width over two okay and then for the height I'll just pick a height of like 20 pixels now we'll do the exact same thing for the right text and then I'll explain why I'm doing this calculation so this is going to be right score but for the right Score I want this to be in the middle of the right hand side of the screen so I actually want it to be 3/4 of the width of the screen right that's the middle of the right hand side of the screen and I'm
going to subtract that from the right score text. getwidth over two so for this I'm going to do with and I'm going to multiply this by three over four okay so hopefully that makes sense I think I can actually just do it like this and say width multiplied 3 over 4 And then minus the right Square I get underscore width two that should work properly so to go to paint to quickly explain this again if we want this to be in like let's do this we have half the screen the middle of this half is
right here okay so this is width over four that gives me this x position then I have my text now if I draw my text here it's going to go like that I don't want it to be like that I want it to be directly in the middle so I need to draw It like this so I'm going to take half the width of the text and subtract that from this position that gives me the top left hand corner for where I need to draw now exact same thing over here this is 3 over 4
width right so I take that subtract it from half of the width of the text I'm drawing and I get it directly in the center of the screen okay and of course this is how you get the width of the text object you just use get width perfect so that should now Draw my score so let's see if this is going to work uh okay wait I think I'm in the python terminal here let's just quit that yes okay let's rerun and notice now that if we score the this goes up and it's going to
continue going up because I don't reset the ball so I need to reset the ball but you can see that is indeed drawing in the middle of the screen and it's changing uh based on what the number is right okay so how do we do this now so Once the ball goes off the screen we need to reset the ball so I'm going to put a method on my ball is called reset so I'm going to say Define reset and what I need to do in here is I need to reset the Y velocity as
well as the x velocity and then change the X and Y position to be originally what it was set so I'm add some new values here I'm going to say this is equal to self. originalx and this is equal to self do original y now let's make those lower Cases so the idea here is when I initialize my ball I'm going to store what the original X and original y value was in a separate variable so that's how you do this here and then I'll change the X and Y as I go through the program
but I'm storing the original X and the original y so I can reset the X and Y to be equal to the original X and original y when I reset so I'm going to say self.x is equal to self. original X okay and then we're Going to say self.y is equal to self. original y then I'm going to reset the Y velocity to be zero okay and I'm going to say the self.x velocity multiplied equal by NE 1 now the reason I'm doing this for the x velocity is if I go off the screen going
left then I want the velocity of the ball to be hitting my opponent when the ball resets okay now same the other way around if I go up the screen going right then I want the ball to go left and hit My opponent's paddle first you could change this if you want by just making it equal to the maxv or not even changing the XV you could do that that'd be fine but I'm just going to reverse the direction so if it just went off your screen then it will go to the other person hopefully
that makes a little bit of sense that that's what I'm doing with the x velocity here okay so that's reset for the ball so now uh if they score we want to reset so I'm going to Say ball. reset and ball. reset okay easy enough let's try this and see what happens okay so let's score and now notice it comes off and hits my opponent's paddle so that's what I'm trying to do just to give my other player some time to recover so if we score now it comes off on that side okay let's score
on the other side and see if our score goes up okay score goes up and then it comes Back to me all right now again you can change that if you want but that was kind of my idea here now one thing we could do is also reset the paddles uh when we score that might not be a bad idea uh for now I'm not going to do that but I think I've showed you how you would go about doing that just implement the same logic on the paddles and then call reset on left paddle
and right paddle okay nice now that we have that the last thing I need to do is handle Winning the game so if the left player wins I want to say you know left player wins if the right player wins I want to say right player wins so I need to first come up with a score that I want to end the game at so I'm going to say the winning underscore score is equal to 10 and now we want to check if either player has has a score of 10 after we increment the score
so I'm going to go here and I'm going to say if the left score is greater than or equal to the Winning score then we want to do something and I'll say l if the right score is greater than or equal to the winning score then we want to do something now the first thing that we want to do is we want to say ball. reset okay and we want to say ball. reset here as well now I actually want to reset the paddles if someone wins cuz we're just going to play a new game
so let's actually implement the reset uh method on the paddles because I guess we're Going to need that anyways so let's go to our paddles and in the same way that we did this for our ball we're going to say self. original X and self. original Y and then we'll just Implement reset so Define reset self self.x is equal to self. original X and self.y is equal to self. original y okay paddle reset done very easy so if one player wins I want to say let left underscore paddle. reset rightor paddle. reset and same thing
okay nice left Paddle reset right paddle reset now the thing is this is pretty repetitive uh so we could try to wrap this in a way where we're only going to write this code once in fact let's actually do something I'm going to say reset actually I'm going to say one is equal to false and then inside of here I'm going to say 1 equals true okay and one equals true and then I'm going to say if one do this so this is just handling all our Resets in one place now so we just have
a Boolean telling us okay did we win or did we not well if someone won then we'll do the reset and then inside of the left score and right score if statement will handle specifically what to do if the left player won and specifically what to do if the right player won now actually what I want to do is just put some text on the screen show it for 5 seconds saying Hey Left player one right player one and then Just immediately reset the game so to do that I'm just going to render some font
so I'm going to say wi text is equal to uh and actually yeah we could just do win text we could say left player one exclamation point we can say wincore text is equal to write player one so now that we have this in a variable what I can do inside of one is I can use that variable to render text depending on who actually won so I can say my wincore Yeah I'll say when actually let's just say text is equal to and then this is going to be the score font we could make
a new font I'm just going to use the score font do render we're going to render the win text one and then we're going to render this in white and we're going to blit this to the middle of the screen so I'm going to say win in all capitals do blit and I'm going to blit the text and then I'm going to blit this At when or I'm going to blit this at height no at width over two minus the text. getor width over two and it's going to be at height over two minus and
then this is going to be the text. get height over two okay so we're centering in the uh X position and the Y position then I need to update the display I'm going to say py game.is display. update and I'm going to say py game. time. Delay 5,000 and 5,000 is going to be 5 Seconds this is the number of milliseconds that I want to display the program by let me run through this because I know I went quickly we're saying the text is equal to score font. render so we're just rendering a drawable object
the text we're rendering is whatever we put here just so we're not repeating a bunch of code and doing this in both places right I'm rendering this with antiel sing one the color White I'm then blitting this directly in the middle of the screen I've talked about how we do the middle calculation many times so I won't go through this again we're going to update the display it instantly shows then we're going to delay by 5 Seconds we delay by 5 Seconds then we reset everything now when we reset we also need to reset the
score right so we're going to say left score equals z and right score equals z and I think that's actually all we need to do For reset then the game will restart and everything will just work as expected and when you hit X of course the game's going to end all right so I think that's actually all good that should really wrap up the program let's run this though and give it a test and see if it's working so let's just see if we can score 10 so I'll just kind of let this run and
then once it's done I'll be right back and confirm that it's working okay so we're at a score of nine let's See now if this is going to work okay it says WR player one perfect and then it should restart the program let's see perfect restarts awesome okay so that is pong we have finished the game now as I promised hopefully you learned a lot in this video uh I just covered Collision we covered some more advanced math drawing you know kind of separating the program out and how we have different functions handling different stuff
uh yeah I think this is a fun program again Great one for beginner or intermediate programmers and I am going to end the video here hello everybody and welcome to another Python tutorial where I'll be showing you how to build the game of 2048 in Python now this game was one of my favorite games as a kid and it's actually very interesting to code out I won't lie to you it is a little bit complex but I think that's what will actually make a great video I'll teach you some more advanced python techniques And how
you can actually structure a game like this so we'll go through all of the steps coding out the grid combining the tiles Etc and by the end of this video you'll have a fully finished game and you will have learned quite a few python features last thing to mention this video is not designed for complete beginners you should have some knowledge of python already but don't worry if you don't know pame which is the graphics Library we'll be using Here anyways with that said let's dive into the video and learn how to build 2048 in
Python all right so let's begin here by just walking through at a high level exactly what it is that we need to do and kind of come up with a bit of a plan before we just jump into the tutorial so as you can see here we have a grid right we actually have a 4x4 grid so we have at most 16 tiles that can be inside of the grid now these tiles can either be twos or fours we always start Out with two twos on the screen and then anytime we make a move we
will add one tile to the screen that will randomly be a two or four when the tiles have the same values and they hit each other so in this case if I go down they'll merge so you can see that we had those fours turn into eights pretty simple in terms of the rules here and eventually you will lose the game if there's no more room on the screen to add more tiles and you can't merge any of them together now This might seem like a simple game but it's actually a bit complicated because of
the movement of these tiles and making it look smooth and animated so what we'll Begin by doing is setting up the general grid we'll draw all of the lines we'll pick the different colors we'll start being able to generate some different tiles and then what we'll get a little bit more difficult is when we need to move and merge the tiles together so for now let's start by Setting up the screen we want to work on actually creating this grid system that you see here and then having some representation for our different tiles so we'll
pick the different tile colors Etc kind of get the drawing and hook up some of the different functions once we've done that then we'll actually go over to the Whiteboard and I'll explain to you exactly how we do the movement of the tiles and some of the more complex logic which I think is really Interesting and you guys will get some value from so let's hop in to our code editor here I am using visual studio code feel free to use whatever you would like now the first thing we need to do here is install
the P game module which is what we're going to be using for all of our Graphics so we're going to go into our terminal and in this case I'm on Mac so I'm going to type pip 3 install py game obviously this assumes you already have python installed now That should install the pame library I already have it installed so I'm not going to run this command if you're on Windows you can try pip install pame if you're on Linux it'll be pip 3 install py game and if none of those work you can try
python hyphen M pip install py game or Python 3 hyphen M pip install P game I also have two videos that I'll leave on the screen that will show you how to fix this pip import so for some reason it says pip is not a valid Command follow those videos they should show you how to install pame okay now that we have pame installed we just want to test this so I've opened up a new file here in vs code and we're going to start by just importing py game so we'll import pame and then
we'll simply run our file and we'll just make sure that we don't get any errors here it says hello from the pame community which tells me that we are good to go okay so now that we've imported pame we'll Import a few other modules that we're going to need to use so we're going to say import random and import math because we're going to need those and then we are going to say py game. anit this will just initialize all of the different features that we need now that we have this what I like to
begin by doing is defining some different constants on my screen let me just make this a little bit bigger so we can read it easier and These constants are values that are not going to change but that we'll need throughout the rest of the program so we'll Begin by writing those variables and we do these in capitals to represent that they're constant so first we're going to set the FPS now the FPS is the frames per second and this will allow us to dictate how quickly the game is running and to regulate the speed on
different devices so we're going to type FPS equal 60 we then need to specify the Width and the height so I'm going to say width comma height equals 800 800 because I just want this to be a square we then are going to determine the row size so we're going to say rows is equal to four and columns are equal to four and what's nice about this approach here is later on we can very easily change the width and the height and we can adjust the number of rows and columns we want if we want
to make the game more complex or a little bit different now The next thing we need to do is determine how large a tile is going to be or one of the rectangles is going to be that's inside of our grid so the way we do that is we'll say the with all capitals rectangular height is equal to the height of our screen divided by the number of rows that we have right in this case we have a height of 800 four rows meaning each tile will be 200 pixels tall we're then going to say
our rectangular width is equal to the width Integer divided by The Columns the reason we're doing integer division is so that we get an integer rather than a floating point value now there's a few colors that we're going to Define that we'll need for right now so we're going to say our outline color is going to be equal to kind of a nice gray now I've already found these RGB colors so I'll just type them out and you can copy them with me so this is 187 173 160 whenever you're defining colors in pi game
you Have the option to use RGB which stands for red green blue first value is the amount of red second is the amount of green last is the amount of blue these values can be in the range of 0 to 255 if we had 0 0 0 that would be black if we had 255 255 255 that would be white next we're going to say in all capitals again the outline thickness is equal to and then this will be 10 we can adjust this later this is how thick the lines will be on the screen
and then we're Going to have the background color and this will be equal to a different shade of gray which will be 205 192 180 don't worry too much about the colors again I already just found these next we're going to say font color this will be the color of the text on the tiles I'm going to go 119 110 and 101 for kind of a blackish grayish shade there okay so now that we've defined some of our constants we're going to create a pi game window so whenever we're coding in pi game we Have
a window the window is where we can draw objects and it's really representing the canvas of our screen so we're going to say in all capitals if I could toggle the Caps locks button for some reason is not working okay window is equal to py game. display. setor mode and inside of here we're going to pass a tupple that contains the width and the height okay so this will actually create a pame window for us so again py game. display. Setor mode then pass a tble make sure you don't forget the enclosing parentheses there and
by the way all of this code will be available from the link in the description in case you are getting confused or you want to copy it specific area next we're going to say py game. display. setor caption this will be the title of the window and I'm just going to call this 2048 which is the name of the game okay last we have two more constants that we need we're going To have a font now a font is something that we can use to render text onto the screen so we're going to say font
is equal to pame do font do with a capital Sy y font like that then we can put the name of the font I always use comic Sands we're going to put the size of the font which we'll go with as 60 for now and then we'll say bold equals true because we want the Bold version of the font lastly we're going to Define a variable here we'll use later called Move velocity this is the speed at which the tiles will move and I'm going to go with 20 pixels per second okay so that is
most of the constants that we need we Define our FPS width height rows calls rectangular height and width and then the different colors we need as well as set up the P game window just to make this a bit cleaner I'll move this down here so it's the last line we have our font and we have our move velocity and now we are ready to start coding out Some more components of our game so the first thing we usually do when we're working with pi game is we create something known as the main Loop now
the main Loop is an event Loop that's going to run constantly and check for things like button presses exiting the screen it's essentially what will just run the game okay it's the main Loop that's handling all of the different events so we usually put that inside of a function so we'll simply say Define Main and then What we need to do is obviously call this function so we're going to go down to the bottom of the screen and we're going to say if underscore uncore name is equal toore uncore maincore uncore then call Main and
what we're going to do is actually call this with the window object and we're going to take in window as a parameter here inside of the main function so we're just specifying okay where do we want to run the game well we want to run it on the window that we Just defined as a variable here and if you're wondering what this does this simply means we are only going to execute this function function if we are running this file directly I'm not sure if that makes a ton of sense but essentially if another file
were to import this file this would not run whereas if we actually run this file directly which is what we'll be doing then this will be true and we'll run this window that's all this name equals Main does just protects you in case you're reusing some functions in here and you don't want to actually run what's known as the main line okay so there we go we have main now inside of main we need to create a loop that's going to continue to run so the first thing we're going to do is set up a
clock object this will allow us to regulate the speed of the loop so we're going to say py game do time with a capital. clock we're then going to have A variable called run equals true which will set to false when we want to exit the loop we'll then say while run and we'll say clock. tick and then we're going to tick based on the frames per second which is this now this tick will just make it so this wall Loop is only going to run at most one time every 60 seconds it could run
less than that but the reason we put this here is so that people that are running on different speed of computers don't have the game Running at a different speed if you didn't have this clock here what will happen is you'll simply run the loop at whatever the fastest speed is you can run it at which means someone on a really powerful computer is going to see the game a lot faster than someone on a slow computer so always good idea to have this clock now that we have the clock what we're going to do
is create a simple event Loop that's just going to listen for all of the different key Presses and events that could occur so to do that we're going to say for event in py game. event. getet this will Loop through all of the events that have occurred and we can then check the event and handle it so we're going to say if the event. type is equal to pame dot with all capitals quit then we will say run in lower cases is equal to false and we'll break out of this Loop now what that's going
to do is simply say okay if we press the Exit button button that's what this quid event is we're going to set run equal to false so this Loop will stop running we're going to break immediately out of this event Loop so we don't handle it and then what will happen is we'll come outside of the loop and we'll run the command py game. quit which will simply quit the pame window for us so that is now the main Loop and what should happen is if we run this code we should actually see a window
appearing and if We press the x button we should be able to cleanly exit so let's go ahead and try that and you can see we get 2048 we get the window of our size 800 800 and I can click exit and I cleanly exit the code all right so now that we have that let's move on to doing some drawing operations so we can actually see some stuff appearing on the screen now I typically like to separate the drawing from the event handling just so it's a little bit cleaner so the way I'll do
That is I'll Define a function here called Draw you'll notice that in my code I'll write a lot of functions just to make sure everything is clean readable and easy to debug and we can quickly figure out where something's going wrong by just isolating it to a specific function this is good practice and something you can kind of take note of while I'm coding so in the draw function I'm going to take a window and what I'll do for now is simply set the Background color and then update the screen so I'm going to say
window. fill and this allows you to fill the window completely with a background color so we're going to say window. fill and then background color if we look at background color here this is what it is so we're essentially just kind of painting the entire window this color then what we can do is say py game. display do update now the way that P game works Is we do all of these drawing or paint events and then as soon as an update is called we'll actually apply all of those onto the screen in the order
in which we wrote them so what that means is that we're always going to fill the screen first because what that will typically do is it will actually override whatever was on the screen by before Sorry by painting over top of it then we'll do any other operations to draw the updated screen and then we'll update and then When we do the update we'll actually see that being performed on the screen I know it's a little bit abstract right now but it's just like we do all of these paint operations then we update then they're
all applied at once rather than happening one at a time so now we just need to call that function so inside of this Loop make sure you're inside of the wall Loop here at the bottom we're going to say draw and we're going to pass that window object and now We should be getting the background color on our screen so let's try this out and you can see that now it fills with the background color okay great so now that we've done that we want to start drawing the grid so to draw the grid we're
going to write a different function and we're just going to say draw uncore grid like that okay and inside of here we'll take the window object again okay so for drawing the grid what we'll need to do is we'll need To draw horizontal and vertical lines to represent the separation between tiles and then we want to draw kind of a border around the entire screen so that we get that nice border effect so let's begin with the Border to draw the Border we can simply draw a rectangle that's positioned at the edge of the screen
so to draw a rectangle say pame do draw. rectangle like that with reect for this we need to pass where we want to draw it so we want to draw it on The window we need to pass the color we'd like to draw it you can see I'm getting the auto complete here so we want the outline color and then we need to pass a rectangle that represents where we should draw the rectangle so the way that we pass a rectangle is we give the x coordinate y-coordinate and then the width and the height of
the rectangle now the X and the Y represent the top left hand corner where we want to start drawing the rectangle from now This will get into the pyam coordinate system which I'll discuss in a second but let's go 0 0 and then width and height now as well as that we have the option to either have the rectangle be filled completely in or to be an outline so in our case we want it to just be an outline we don't want it to fill in entirely we don't want to draw s solid rectangle Surry
we want one that's Hollow so what we'll do is pass what's known as the width or the thickness so I'm going to say width and then this is going to be the outline thickness which in our case I believe is 10 pixels so before we go any further let's draw this on the screen just so that we can see what it looks like so let's go here and in our draw after we draw the background we're going to say draw grid and we're going to pass the window so let's run this now and you should
see that we're getting kind of this outline it's a little bit faint on my screen but I Think you can probably see it maybe maybe not with OBS recording but I can see it at least here and we do have an outline filling the screen okay so that's how that works now actually let's run this again one thing to note here when we're talking about coordinates and XY values in pi game we always start at 0 0 which is the top leftand corner of the screen so rather than starting at the middle which is typically
0 0 it's the top left meaning as you go to the Right your x value increases and as you go down your y value increases so if we look at the bottom right hand corner that would be 800800 in terms of the coordinate grid in pi game so just keep that in mind um you you'll see as we go through here how we kind of do the positioning Okay so we've drawn that now we actually want to draw the outlines uh sorry so like the grid lines right so we can start by drawing the horizontal
lines so we can Say four row in range and then in all capitals rows so we're going to draw a line for every single row that we have and what we need to do here is simply calculate the y coordinate of the row or of the line sorry that we want to draw so we're going to say Y is equal to row multiplied by the rectangular height now the way this will work is we'll start with row being equal to zero and then it'll become 1 2 3 and then it will not be equal to
whatever the last row is Which is fine and in fact we can actually do one comma rows because we don't need to draw the very top line because that will already have been drawn by the rectangular outline that we drew anyways what we're going to do here is draw a line the line will go from the x coordinate 0o to the width of the screen and then what we'll do is adjust the y-coordinate so we're moving the line down every time the loop happens so we take whatever the height of one tile Is and we
multiply that by the current row and that tells us the y-coordinate for this line so we're going to say py game. draw doline similarly here to the rectangle we're going to pass a window we're going to pass the outline color and then we're going to pass zero and then y y is our Dynamic value and when we draw a line we pass the starting position and the ending position so the two points essentially for the line to be drawn between so next we're going to Say width and then y so we're constantly always going to
have the line starting at 0x and with X so that way we're filling the entire screen horizontally and we're just adjusting the y-coordinate so vertically where that Line's going to be drawn now again we need to specify the thickness we're going to put the outline thickness here also known as the width of that line so now if we actually go here and refresh you'll see that we get our vertical Lines appearing or sorry horizontal lines so now we can copy this exact same thing and paste it here and just adjust it for the vertical lines
so we're going to say for column in range one comma calls now this is going to be column times the rectangular width and we're going to change this to be X so now we're going to keep the Y values constant and adjust the X so this is going to become X and then zero and this is going to become X and height so you can see that we always have two fixed values right where we want to draw between and then what we're adjusting is the X position whereas here we were adjusting the Y position
and where we make that change is with call and the rectangular width versus row and the rectangular height now in this case the rectangular height and width are the same uh however they could be different which is why I'm doing this in two Loops because if we Wanted to have actual rectangles not squares then this code would adjust to that appropriately okay so let's run this and you'll see here that now we get our grid okay so now that we have our 4x4 grid what we want to start doing is actually representing tiles in those
grids and then drawing the tiles on the screen once we're able to draw the tiles on the screen then we can start moving them on the screen again uh as I said this a bit more complicated so we're Going to create a class here called tile now I want to use a class just because there's some methods related to each tile which will fit nicely inside of this object or inside of the class um so it just makes it a little bit cleaner so as a class variable I'm going to specify colors now what I'm
going to do is paste a bunch of colors in here I don't want to write all of them out because it's a little bit tedious and these are the exact same colors that are used in the Real 20 48 game now these colors represent from like 2 4 8 16 32 64 Etc so as we go up it just multiples of two or whatever double the last value is okay so that's kind of how I'm doing it I'll show you how we index the colors in a second and if you want this list of colors
obviously you can pause it and type it out or you can just view the code that's Linked In the description and rather than looking at everything you can just copy this colors variable Okay so again in the description you can find all of the code there should be a GitHub link and just go ahead and find the colors and paste them into your code if you're following along with me step by step so next we're going to define the initialization for our tiles so we're going to say Define uncore nit uncore uncore we're going to
say self value row and column now for each tile we need to know what the value of the tile is so is it a two is it a four is It an 8 Etc we also need to know it's positioning in the grid so what row is it at what column is it at and that will allow us to determine the X and Y position of where we want to draw the tile it also allows us to know what tiles we can merge with so that's why we're storing that value so we're going to say
self. value equals value and create that attribute and we're going to say self. row is equal to row self. column is equal to column and then at The same time we're actually going to set what the X and Y coordinates are for drawing this specific tile so we're going to say column times the rectangular width and self.y is equal to the row multiplied by the rectangular height now how does this work well if we were in row 0 column 0 then we would simply start drawing this tile at the position 0 0 right right that's
the very top leftand corner of the screen if we were in row zero column 1 then we would want to start drawing this from if I can calculate this correctly a yv value of zero but an x value of 200 because that's where we want to draw the tile that's in that First Column when I say First Column I really mean the second column it's because in programming we're starting indexing or starting counting at zero you'll see what I mean and actually I can just run this to explain it to you like if we want
to draw a that's where My mouse is here I hope you can see it in the position 1 one so 1 one is you Row one column one as opposed to 0 0 here then what we're going to do is start drawing it at the top leftand Corner position of this which is what we're calculating when we're doing the X and Y so we multiply the column by the rectangular width which brings us over here we multiply the row by the rectangular height which brings us here and then we would draw the rectangle in This
Square you'll see what I mean as we go through the code but hopefully that's an okay explanation okay so now that we have the initialization and we have some values that we need we want to start writing some other methods related to this object so before I write all of them we'll specify what they are so we're going to say well we want to be able to get the color that we're going to draw this tile in and that's going to be Based on its value we also want to be able to draw this so
we're going to say self and window because that's what we need to draw and what else do we need to do we need to be able to move this so we're going to take inself and some Del Delta which is how much we would want to move this by and I don't know what just happened there on the screen and then lastly we'll have another method called set position which will allow us to actually determine let me just pass this Here what position this uh tile is currently in while we're moving the tile we'll use
some of these methods later on but I just like to stub them out so we know what we're about to write so let's begin by writing the get color and the draw methods which are the ones we'll use for now so again we need to be able to determine what color out of this list of colors we're going to use for the tile and that's going to be based on what the value of the tile is so we need To have some kind of function that can essentially give us the following values so we have
a value of two we want to get the zeroth index which is the first color which is what the color of the value two should be when we have the value of four we want to get index one when we have the value of eight we'll want to get index 2 and when we have the value of 16 we want to get index 3 so you can follow this pattern here and you can actually come up with an equation Which will allow you to get this specific mapping of value so anytime the value of x
or the input doubles we want to then get the next value uh in our sequence hopefully that makes a bit of sense I'm sure this is bringing you back to math class well how do we do that well we have this wonderful thing called a logarithm which will actually allow us to figure out what the power is that's required passed on some value to get some other value right I'm sure you guys Are familiar with logarithms I'm not going to explain how the logarithm works and that was pretty poor explanation but we're going to say
the color index is equal to the math of log base 2 of our current value now if we look at the logarithm function we can see that if we pass F of two that actually gives us one however we want this instead to be zero so what we'll need to do is simply subtract one from whatever the value of the logarithm was that's returned now Just to ensure we're always getting an integer value and not a floating point value we'll first convert the result of the logarithm to an integer it will always be a whole
number anyways but this will just strip off any decimal point that might be there and then we'll subtract one so now we have a function that takes in whatever our values are and Maps it to the correct index in our colors list so now that we have the index we want to access the color so We'll say color equals self. colors at the color index okay and then we will return the color like that so this now will give us the correct color based on the value of this tile okay now we want to draw
the tile on the screen now when we're drawing the tile on the screen what we need to do is draw a rectangle for that tile we also need to then draw on top of the rectangle the value of the tile so what we'll Begin by doing is drawing the rectangle and then we will Draw the text on top of it so we're going to say that the color we want is equal to self. getet color and this is going to tell us the color that the rectangle should be we're then going to draw the rectangle
so we're going to say pame do draw do rectangle and we're going to draw it on the window what color do we want to draw it well the color that we just got and then we want to draw this at the self.x position the self.y position and with the rectangular Width and the rectangular height and that's it we want this to actually be a solid rectangle so this time we won't provide a width which means it will fill in the entire r that we provided here now that we've done that we want to generate some
text that we're going to draw in the middle of the rectangle so to do that we're going to use our font object so we're going to say text is equal to font. render so the process whenever you want to draw text Is you use this font object and you render some string into a surface is what it's called that you can then put onto the screen so we're going to say font. render and what we pass for this is the value so we're going to put an F string here or actually we can just do
string of self. value so we convert our numeric value into a string so that we can actually draw that we're going to pass one for something known as anti-aliasing don't worry too much about That and then we need to specify the color now the color is going to be the font color that we specified earlier now that we have the text object what this has actually done is created a surface that contains the text and now we need to specify where on the screen we want to put the text so to do that we say
window. blit blit is is how you put a surface onto the screen so it's a bit different than drawing the rectangles now what we pass is what surface we want To put on the screen in this case I want to put the text surface and now we need to place this in the middle of the rectangle now to place this in the middle of the rectangle we need to determine the top leftand Corner position of where we should start drawing the um what do you call this here the text so in order to do this
there's a little bit of math that we need to perform I don't know if I have a drawing tablet or maybe an ink thing That I can use here on Mac let's see if there's like a drawing surface or something okay I just found like an online drawing program that we'll quickly have a look at here just so that you can kind of see what I mean so let's say we have our rectangle right kind of a sketchy rectangle now we want to draw our number in the middle of the rectangle what we need to
do is figure out the location that we want to draw it in now naively you might think okay well If I want to figure out the XY position let me just figure out whatever the XY position is of this and then we'll just take whatever the width of the rectangle is and we'll start drawing it directly in the middle right so you'll just take okay we have W and we'll just take W over 2 and that's where we'll start drawing it the issue is if we do that then we're going to start drawing here and
the number is going to go to the right because it's the top leftand Corner that we're drawing from so what we actually need to do is offset this by the by half the width of the object that we're drawing so what I mean by that is we want to draw like this right so let's say the number is kind of in this box like in this bounding box we want to find this location that's where we want to start drawing the number from so the way we actually do that is let me just clean this
up a little bit I know it's very messy here we have some W right This is the width of the rectangle so we start by taking W over 2 which is going to give us this position so w over two we then want to make sure that the number is perfectly centered so we say okay well we have the bounding box of the number and this has some width as well we can just call this uh I don't know a okay so what we actually do now is we take a over 2 and we subtract
that from W over 2 and that gives us this position here which is the top leftand Corner position of where we want to start drawing this object from so quick clarification right we go to the middle of the screen we then subtract from half the width of the object we're going to be drawing and that means when we draw the object out it will be perfectly centered in the middle of the screen the same thing applies in the y direction so that's exactly what we're going to do here now I know that was really sketchy
but hopefully that's an okay explanation All right so now that we have that let's start doing our little bit of calculations here so we're going to say okay well we'll start drawing this at the self.x position of this current rectangle and then we're going to add to that what we just specified so we're going to take whatever the rectangular width is okay because that's the width of the rectangle that we're drawing inside of and we're going to divide that by two that gives us the middle of the Rectangle but now we need that top leftand
Corner position so we're going to say text. getor width this gives us the width of the text object and then we're going to divide that by two this now specifies that this is the X position that we want to draw now next we're going to do the Y position so we're going to say self.y plus and this is going to be the rectangular height if we can get our cap locks to work some reason my caps locks Button doesn't want to work very well so this is going to be the rectangular height over two minus
the text. getet underscore height over two okay and that's all that will actually blit this on to the screen for us okay so now we have the ability to draw our tiles now also notice the order in which we did this we first drew the rectangle and then we drew the text on top of the rectangle it's important you do it in this order otherwise the text will be Hidden because you'll be drawing the rectangle after so now what we'll do is call that function so inside of our draw function we're now going to take
in all of our tiles now we don't yet have any of those tiles but we will create them in a second and what we'll do is before we draw the grid we'll draw all of our our tiles and that way the grid lines Will Go On Top of the tiles and it will separate them and make it uh pretty easy to see so We're just going to say for tile in tiles and then we'll just say tile. draw and tiles is actually going to be a dictionary so I'm just going to say tiles. values I
know seems a bit weird because we haven't yet created the tiles but we'll just do a quick test and I'll show you kind of how it works all right so now we have that for drawing now we just need to make some tiles then pass those to our draw function so we're going to say tiles is equal to a Dictionary the reason we're going to use a dictionary is that we want to be able to index or locate all of the tiles very quickly by their row and their column so there's multiple ways that we
can go about indexing our tiles or storing them but what we want to come up with is a key that kind of represents the tile and then the value will be that tile class itself that we can index in here so to do that we'll simply say the following for now we're going to say 0 0 which is Representing the row and the column so like you could have zero hyphen zero but in our case we know we're always going to have uh what do you call it less than 10 or on digigit rows and
columns so we just go 0 Z so we'll say 0 0 colon and then we'll create a tile now for a tile we need a value a row and a column so let's go with a value of four and then let's go with a 0 0 for the row and for the column okay so now let me just change this to give you another example Let's say we have the tile 128 now we want this to be at row two column 0 so that would change this to be 20 0 okay the way this works
again is that we have a two-digit string the first digit represents the row the second digit represents the column and then that's associated with the tile object itself that we actually want to be representing and drawing this way we can always index a tile given its row and Column and we can find it instantly inside of the tiles dictionary this is opposed as if we made a list if we made a list and we wanted to locate a specific tile we need to potentially iterate through all of the tiles in the list and check the
rows and columns to find the one that we want whereas here we can always have instant access to a tile so kind of an efficiency thing that's why we've written it this way okay now we're going to pass tiles to The draw function and just make sure they draw correctly on the screen so let's run this and we got an error it's a draw is missing one uh required positional argument window okay so we're going to go here to tile. draw and pass window all right let's rerun this and now we should get our tiles
on the screen and we get them at the positions we specified right so this was what two and 0 0 we can do one more tile just as a test so let's go here and we'll say Maybe 02 and this will be with a tile and this will be let's go 64 and then 02 okay let's run and you see now we get the 64 tile appearing in the correct position okay so that's great however we don't want to actually start our tiles with some fixed ones on the screen we want to randomly generate two
tiles that have the value two that will begin as our tiles right so let's write a function that can do that let's say Generate tiles now for this all we're going to do is just randomly pick two positions that we can put the tiles um in okay and we'll just make sure they're not the same so we're going to say tiles is equal to an empty dictionary we going to say four underscore in range two if you're unfamiliar with the underscore this a placeholder value that we can use when we don't actually care about the
variable we put here normally you do Something like 4 I in range two but in my case I don't actually want to use I I just want to do something two times so I'll just say four underscore in range two we're now going to say row column is equal to and we're going to call a function which is get random position and we're going to pass our tiles and then we're going to say tiles we're going to do an F string and this is going to be at row column if we can do this is
equal to A tile and then this is going to be two row call we're then going to return our tiles okay let me slow down a little bit to explain we just did so we have an empty dictionary where we're going to store our tiles we're doing something two times and what we want to do is generate a random row and a random column to place our tiles inside of now we want to make sure that we're only doing this for a tile that does not yet Exist right we don't want to create a tile
that's in the place of another tile so that's where this function will come in which we'll write in a second it will make sure when we are randomly picking the row and column we don't pick one that already exists then what we're doing is saying okay tiles well this is a dictionary so we need to set the key the key is going to be equal to first whatever the row is and second whatever the column is so we use an F string Available in Python 3.6 and above which allows us to embed inside of curly
braces here any values that we want to be converted to a string so we're saying okay well we just want the row and the column which are numbers they're going to convert to a string that's going to give us the correct key and then we're going to make that equal to a tile object which has the value of two because we always want to start with twos in the row and the column okay now Let's write our get random position so we're going to say getor random underscore pause this needs to take in the tiles
that we make sure that we are not placing this in a position that already exists so we're going to start by saying row equals none column equals none because we don't yet know what we want and now we're going to say while true and we're going to continue to randomly generate rows and columns or a position for this tile as Long as this position already exists so what I mean by that is as soon as we find a position that does not yet already exist inside of our tiles then we will use that one otherwise
we're just going to keep randomly generating positions so we're going to say row is equal to random. random range and this is going to be in the range zero to rows when we use Rand range it means we'll generate up to but not including whatever the value is here which is four So we'll generate a random value between 0o and three inclusively we're then going to say column is equal to random. Rand range and then zero column okay so we're just picking what the random position is or what it should be what we're going to
attempt and then we're going to say if and same thing we're going to do an F string here row column is not in and then we can just say tiles like that then we're going to break now This is another advantage of using the dictionary we can instantly check whether or not this key exists inside of the dictionary because of that property the dictionary we have instant access to see okay does this key so does this position row column already exist if it uh does not sorry which is what we're checking here then we're going
to break right so then if we break we're going to return the row and the column from the function that we generated otherwise We're going to continue to do this until this condition is true allowing us to break out meaning we found a random position great okay so now that we've done that we will go over to our main and we'll say tiles is equal to generate tiles and that should generate two random tiles on the screen for us so let's try this now and you see that we get a randomly generated tiles let's run
it again we get more randomly generated tiles Etc okay so there you go we've now Generated the tiles and placed them on the screen okay so at this point we've written quite a bit of code and we have the main structure of the application setup now what we want to start doing is moving the tiles around so let me hop over over to the drawing tablet and explain to you that process it is a little bit complicated then we'll begin implementing it all right so I'm on the drawing tablet now and I'm going to explain
at a high level what it is that We're about to do now I can't cover everything conceptually here but I'll give you a sense of how to think about this problem now if you are someone who likes these problems feel free to try to solve it on your own uh first of all but you will see that it's a little bit complicated because of the fact that we actually want to animate the tiles and we want to move them on the screen so moving them is actually the difficult part doing the merges is not so
hard to Figure out what the new position should be it's more about getting to that new position and how we iterate and move so that it looks smooth anyways let's have a look here so we have a few different edge cases that we need to handle and we can go through them one by one so let's say we have the number two this is our tile and we decide to make a movement to the left keep in mind all the movements effectively are going to be handled the exact same so we can just look at
a case In which we're moving to the left but the exact same thing would apply if we're moving to the right there's just a few variables that change so we're moving to the left and we have this tile now there's a few things that can happen the first thing that can happen is there can be nothing to the left and we can simply shift the tile that's the easiest case right there's nothing to the left of us so we just move the tile until we hit the Border pretty straightforward we Take the X position and
we just shift it over and then once it gets inside of this Square here we just change the tile's position so then rather than being at 1 one it's now at 1 okay so that's the important thing to also keep in mind here we have an X and A Y which is the location in which we're drawing the tile and we also have a row and a column which will represent with r and C which tells us the current location of the tile in the grid so these values are Linked together however while we are
moving the tile the r and the column is kind of in between right for example at one point in time my tile might be in between two rows and columns in that case we don't know its exact location and we need to wait until it reaches some kind of boundary point to then reset the row and column to be the correct position based on the X and Y value so I just want to say that one more time because I understand it's a Little bit confusing we're going to have a tile that's going to be
moving could be up right whatever while it's moving this row and column we don't necessarily know what the correct value is so at some point we need to adjust this so that it represents where its location actually is on the screen and that's typically when the tile is no longer moving okay so anyways that's kind of the basics there so this is the first case we just simply move the dial over To the left now the second case is when we have a blocking tile that is in the direction in which we're moving so again
we're moving to the left that's where we've shifted and now we see that when we move to the left well this tile exists and it doesn't allow us to move so if that's the case we just simply stay put right right there's no movement that occurs for either of these tiles now it gets a bit more complicated right where we have this tile here so now in This case we move until we reach a tile that is blocking us okay so obviously I think that makes a bit of sense now the next instance is when
we are moving in a direction and we have a tile that contains the same value as us if that's the case we actually want to take this tile we want to move it so it kind of merges with this tile and then we need to update the value of the tile to the left so this becomes four and remove this tile so let's kind of do an X here So we no longer see it on the screen so this is the merge instance now the thing with this is that there's kind of two stages to
this merge the first stage is while the tile is actually moving into the position of this tile so to keep things looking smooth we don't just want to instantly merge the two tiles as soon as we see that they are going to merge what we want to do instead is we want to take this tile and we want to kind of move it inside of the other tile and Then as soon as it's fully uh emerged in that tile is when we remove it from the screen and then we simply update this one so it
now becomes the new tile value so those are those two situations right the first situation okay we know we're going to merge we need to keep moving it so it looks smooth then the second situation is okay we've already moved it inside of the other tile so now we'll merge it together so those are pretty much all of the edge cases again we have A situation in which there's no tile to our left or in the direction of which we're moving we just move the tile we have a situation where there's a blocking tile where
there's no movement that occurs and we have a situation in which there's a merging tile where there's two phases the first phase is to move into the square where the merging tile is and then to merge the two tiles and remove the other tile so that's what we need to handle however doing this is A little bit easier said than done because of all the things that could happen for example let's say we have something that looks like this right we have like 2 2 2 two well what we need to do is actually make
sure that we move the tiles in the correct order such that the merges happen appropriately so in this situation where we have four twos we want to ensure that we don't accidentally merge the two middle tiles because if we were to do that we would Be left with a result of 2 42 which is incorrect what we want instead although I guess you could Define this behavior however you want is that after we do this Movement we end up with two fours right so delete delete and we have four four so what that means is
that we need to make sure that we're going to start moving the tiles from the direction in which we're moving so if I'm moving left we're going to check the first tile then the second tile then the third tile then The fourth tile and at one step at a time move them to the left rather than moving the tiles from the right first cuz if we move the ones on the right then we're going to merge the wrong order so the merging order is important there's a lot of other factors we need to consider there
but I think that's enough in terms of the high level explanation so let us now get into the code and I'll start explaining it and again feel free to pause it Go reference Some of the other code if anything's going wrong and ask any questions you have in the comments down below all right so we're back now and we're going to start handling the movement so what we'll do is we'll Define a function move tiles which is going to allow us to move them so we're going to say window tille clock and Direction and this
will be one function that will actually handle the movement of the tiles in all of the directions now we'll start by just doing One Direction so you get the gist of it and then we'll handle the other directions which are just slight variance of one of them right so what we're going to do is create a variable called updated equals true and we're going to create something called blocks which I'll Define in a second pretty much this blocks set is going to tell us which tiles have already merged in a movement because we don't want
to be merging multiple sets of tiles I can Show you an example of what I mean in a second when we actually run the code but we create this set here so that we know which tiles already had a merge operation occur so we don't allow them to merge again which means we don't get this like huge chain of tiles merging in a row which is not how the original game behaves you can obviously change the behavior if you want but that's not what I want to do here okay so now what we want to
do is just handle what direction It is that we're moving so we'll just stub a little if statement here and we'll say if direction is equal to left we'll say l if the direction is equal to right and let's just do a pass here we'll say l if the direction is equal to up and we'll say l if after we pass just so that we have a stub there the direction is equal to down okay so now we're handling all of the directions the first Direction we'll go into is left So what we need to
do is Define a few functions and variables that we'll use in the main kind of block of our code so this is going to seem very abstract right now when I write this out but just bear with me and I promise you it will start to make more sense so we're going to say our sort function and we're going to use something called a Lambda if I could type this so we're going to say Lambda X and then x. column now remember that we Want to move the tiles when we're going left for example from
left to right so the first tile we move is the one that's furthest on the left and then we go to the right and then move the tiles in that order that way we merge in the correct order so we need to start actually moving from that left side so that means that we need to actually sort the tiles so that we know which tile we should move first because right now our tiles are stored in a dictionary and We're not going to necessarily have them in a sorted order so we're going to take the
tiles and we're going to sort them into a list and then we're going to move all of the tiles so that's why I'm say setting the key here equal to the column so I'm saying okay we're moving to the left which means we're going to sort the tiles by their column now if you're unfamiliar with this Lambda this is a oneline Anonymous function and it works the exact same as any other function so This that I just wrote right here is the exact same code as this uh oops not Funk Define Funk X and then
return x.com okay it's the exact same thing it's just so you can write it in one line and you don't need to define a name for it when you don't need that name okay so that's kind of all that does this is like okay we're making a function this is our parameter and this is what we want to return from the function it only allows us one line but That's fine that's all we need okay then we're going to have reverse equals and this is going to be false now this is going to tell us
whether or not we want to sort an ascending or descending order so we could actually change this to just be ASC like that standing for ascending uh or no that's going to look a little bit weird we'll do reverse instead sorry this is just again telling us okay do we want to sort in reverse order or correct order because when we're going to go in The right we want to sort again but we want to sort in reverse order so we start with the largest column Elements which are on the furthest to the right okay
next we're going to have a Delta now the Delta is going to specify how much we want to move each tile by each frame in this movement function so the Delta is going to be negative move velocity and then zero so we're specifying how much in the X Direction and how much in the y direction we're Going to move in this case I want to move negative in the X Direction which will move us to the left okay so reducing X moves to the left next we're going to have a boundary check now this is
going to be a function again and this is going to be Lambda we're going to take in a tile and we're going to check if the tile. column is equal to zero now if the column of the tile is equal to zero that means it's already as far left as it can possibly go so we're not going To move it any further to the left because it's hit the bounds of the screen so again same thing Anonymous function just tells us okay have we hit the bounds or not next thing we need is a function
that can get us the next tile so this is the tile to the left of the current tile we need to check that tile because based on its value we're either going to be blocked by it or we are going to merge into it so we're going to say get next tile is equal to a Lambda Function and this is going to take in a tile and it's going to say tiles doget and we're going to say f and then row and then column minus one so we're looking for and sorry this needs to be
the tile. row and the tile. column so what we're looking for is the tile to our left the tile to our left is the tile that has a column that's one less than us now we do dot get because we don't know if this tile exists so we don't know if there's actually one to Our left or not if there is one this will return that tile for us which allows us to use this indexing scheme otherwise it just returns none okay next we're going to have our merge check now this is a Lambda function
again and we're going to take in our tile and our next tile now what this is essentially telling us is whether or not we should merge the tile based on the current movement of this tile because you'll see what we're doing is moving the x Coordinate of our tiles until we reach a certain position in which case we then do the merge so we're going to say that the tile dox is greater than the next tile dox and then this is going to be plus the move velocity so what we're checking okay the tile that
we currently have so the one that we're moving to the left we're going to check if its Exposition is greater than the next tile's Exposition plus the velocity that we're about to be subtracting as we move What this is telling us essentially is okay have we moved far enough left that it now looks like we're in side of that other tile if we have then we can go ahead and merge if we haven't which is actually what this is checking story then we'll keep moving the tile you'll see how we use it in a second
but this is checking okay are we in the position to merge or not that's pretty much what it's telling us okay next we're going to have a move Check now this is going to be for when we're moving and there is a tile to the left of us however that tile is not the same value as the tile that um what do you call it that we're moving so so this is going to be Lambda tile next tile and this is going to be tile dox is greater than the next tile dox plus this time
the rectangular width plus the move velocity okay so why are we doing it like this now so in this instance if We're moving to the left and we have a next tile we want to stop moving as soon as we reach the border of that tile now the border of that tile is on the right side of the tile that's to the left of us so to get that position we take the next tile. X we add the width of that tile and then we add the velocity which we would be moving if we were
to continue the move um again you'll see how this works in a second I know it's it's fairly abstract okay lastly we're Going to have seal is equal to true now this essentially tells us whether or not we should round up or round down when we're determining the location of the tile after a move I know a lot of code very abstract but these are the different things that will be adjusted based on the direction that we're moving so you can imagine we're moving to the right some of these things are going to change right
like the move check the merge check the sort function is going To be a little bit different the reverse function okay so that's kind of what we're doing here in terms of this and then we have some general code which we're about to write which will perform the move based on these functions so this is kind of the cleanest way to write this so what we're going to do is say while updated now the idea is is while we've performed some kind of move update we need to kind of update the screen and redraw it
so it looks like We're moving as soon as we're in a position where nothing has moved we're going to stop this W Loop so when no update has occurred which is what's going to be indicated by this variable here then we'll break out of the loop so now we're going to say clock. tick and then we're going to tick by FPS and we're going to say updated equals false so it's our responsibility as we go through this Loop to update this variable and make it equal to true if an Update operation has occurred so now
what we're going to do is we're going to sort the tiles so remember I said we need to get the tiles in a sorted order such that we're moving them in the correct um order so that we get the correct moves so we're going to say sorted tiles is equal to a sorted function of the tiles. values we don't care what the keys we just want the values and the key is going to be equal to a sort function Okay like that and then reverse is equal to reverse so the sort function we defined here
reverse we defined here we're now using these to sort the tiles in the correct order we're then going to say 4 I comma tile in enumerate and we're going to enumerate over the sorted tiles this simply means get the index of the tile as well as the tile object itself first thing we're going to check here is okay we want to be moving these tiles so we're doing this for every tile Right we're going to going to check if the tile is at the boundary so if the boundary check of tile then simply continue because
if we're at the boundary there's no movement that needs to occur for this specific tile so we can move forward next thing we need to do is get the next tile so we're going to say the next tile is equal to get next tile and we pass the current tile that's going to give us the tile that is in the way of which we want to move so We're now going to say okay well if we don't have a next tile so if there's no tile in our way then we can continue to move because
we're not at the boundary and there's no tile next to us so let's just move our tile so we're going to say tile. move by our Delta and before I forget let's go and code out this function so move is right up here and the way we move is the following we say self.x plus equals Delta 0 and self. Y Plus equals Delta 1 and that's it very straightforward again if we go look at our Deltas here you can see that we just have the components of how much we want to move in this case
we're just going to move backwards in the X Direction because if we add zero to the existing value here in y doesn't do anything okay so that is move now we get into the more complicated cases so we say all right well if there is a tile beside us we need to check something we need to check First of all is this tile the same value as us so we're going to say LF the tile. value is equal to the next tile Dov value if it is now we go into those two cases so I
don't know what I just did there where we need to determine okay well if it's the same value we're either we're going to be merging with it right so we're either in the process of merging with it or we've just merged like we've moved the tile enough so we're going to say if merge Check and then tile if we can type this correctly and next tile then we're going to say tile. move and then Delta so this is checking okay are we in the process of merging if we are we can continue to move the
tile now if we are not then what we need to do is actually perform the merge operation so the merge operation looks like this we're going to take the next tile we're going to get its value and we're going to multiply it by two we're then going To remove the tile that merged with it which is the one that we're moving so we're going to say sorted tiles do pop at index I which is the index of this tile in the sorted tiles list we're then going to say blocks. add and we're going to add
the tile and we are going to also add the next tile or sorry we don't need to add the tile because we just removed it we're just going to add the next tile now what this is doing here is saying Okay well we've already okay so what this is doing here is simply saying all right well this tile just got merged with another tile so we want to make sure it doesn't merge again so we're just adding it into the blocks so that we can then use that set to ensure we don't don't do a
kind of double merge operation now where we'll actually use that is right here we're going to say and tile not in blocks and the nextcore tile Not in blocks when I save that we'll get the auto formatting but what we're doing here is making sure okay well if the tile. value is equal to the next tile. value so if it's the same and that tile and the current tile that we have has not merged with another tile go ahead and we can perform this operation now if it has merged with another tile we don't want
to do this we don't want to merge with it so we're not going to initiate that operation okay Next thing we're going to do is we're going to say l if the move check and this is going to be tile next tile then we're going to say tile. move by the Delta otherwise we're going to say continue all right so let me just quickly break this down here what we're doing is we're getting the next tile if we don't have a next tile we simply move now if we do have a next tile and that
tile value is the same as this value we're going to go ahead and initiate the Merge operation which we discussed now once we reach this LF we know okay we do have a x tile the next tile's value is not the same as ours so what that means is that we should move this tile until we reach the border of that next tile which is what's checked by this function so we move until this is false right until it you can no longer move we're going to continue to move otherwise if none of that is
true then we just say continue and what that means is we're Not going to do anything and when we don't do anything no update occurred so now we're going to go down here and we're going to say updated equal true so unless we were in this case or we were on the boundary we're going to reach this variable and we're going to say update equals true and that's going to tell us to initiate another loop here and continue the movement process because something did actually move as soon as this variable never becomes Equal to true
we stop the W Loop and we exit now there's a few other things that we need to do but that's a good start to our function all right so let's continue here as I was discussing while we move these tiles their row and column are going to be adjusted based on their X and Y position so based on where they're actually moving in the grid because as they move uh enough then they're going to be in a different row and a different column so we need to actually adjust That so to adjust that we're going
to use this if we can write here set position function now the set position function or method whatever you'd prefer to call it is simply going to look at the current X and Y position of this um what do you call it tile and then adjust it sorry adjust the row and call based on that X and Y position so we're going to say seal is equal to false and this is a variable that's going to tell us whether or not we should round up or we Should round down which is going to be important
based on the direction in which we're moving so we're going to say if ceiling so simply if we're rounding up then we're going to say self. row is equal to the math do seiling which is always rounds a value up and then we're going to take the self.y and we're going to divide that by the rectangular height so let's say the Y position is 600 right we're going to take six so let's say the Y position is 599 we're going to take 599 divided by the rectangular height which is 200 that's going to give us
like 2.9 something we're then going to round that up to three telling us that we are currently still in the third row okay we're now going to say self. column is equal to math. ceiling self.x divided by the rectangular width and then for the else so if we're not rounding up we're going to round down so We're going to say self. row is equal to math. floor and then the exact same thing here right so this is going to be the Y value and then self. column is equal to floor self.x / the rectangular width
okay so that is just going to adjust the row and column as we move and what we're doing is we're essentially with this determining at what point will we move to the left or to the right that we want to set that row column value so when I go with Ceiling that means as soon as I move fully past the bounding line or I'm right at it then I'm going to adjust this as I'm moving to the left whereas when I'm moving to the right it's actually going to be the opposite um because of the
kind of directions in which we're moving it's it's difficult to explain this but you'll be able to see in the code here how we change this based on if we're moving to the left or to the right so that we know what row And column we're actually in to check for the next tile okay so now what we'll do is we'll go over here to updated and either before after update doesn't actually matter the order in which we do it we're just going to set the tile position so we're going to say tile do set
position and we're going to pass that ceiling value which we defined here so we're moving to the left ceiling is true we're moving to the right it's going to be false okay now this is all Good however you'll notice that we removed some tiles but we only removed them from the sorted tiles list now this is not actually where all of the tiles are stored it's just where they're temporarily stored while we're in this updated Loop so what we actually need to do now is adjust the tiles object itself which was passed in here to
remove any tiles that were then removed from the sorted tiles um and to kind of adjust them so what we're going to do is inside Of the wall Loop here but outside of the for Loop so make sure you have that indentation correct we're going to say update tiles and we're going to take the window the tiles and the sorted tiles now all this is going to do is essentially Loop through our tiles and it's just going to remove any of the sorted tiles that no longer exist from tiles so we're going to say Define
Update uncore tiles and we'll take in the window the tiles and the sorted tiles like that and we will go ahead and write that function so the way we can do this is we can just start by clearing all of the tiles so we're going to say tiles. clear just removes everything from the dictionary and then we'll just say for tile in the sorted tiles and then we're going to say tiles and we'll create an F string again okay and this is going to be Tile. row tile. column is equal to the tile that's it
and then we'll just do a draw operation here so we can actually see what's going on and we're going to draw the window and the tiles so update tiles is going to as I said update this tiles dictionary so it only contains the ones that are actually still there and it's going to draw all of the FES on the screen as they move so we can actually see that movement operation occurring so I think that's okay last thing we'll do Here is we're just going to call something known as end tiles now notice that this
is happening outside of the walloop so as soon as we're no longer updating any tiles we're going to call this function so we're going to say Define end tiles like this this is going to take in the tiles and what this is going to do here is just check whether or not the game is over uh and kind of do that last cleanup operation so what do we want to do here actually let's Call this end move because that makes a bit more sense okay and then inside of here we're going to say if the
Len of tiles is equal to 16 then we're going to return lost so if after we did a move we have 16 tiles uh that means that we can't move anymore because the en entire board is well full of tiles uh and that way we lost so we'll just say we lost and then we can handle that later on if we want and then what we also want to do is we Want to add a new tile to the screen right so every time we make a move a new tile gets added so we're going
to say row column is equal to get random position and this is going to be tiles and then we're just going to say Tiles at the F string of row column is equal to tile and then what we need to do is randomly select whether or not we want the tile to be a two or a four so we're going to say random dot choice and then in an array two four just randomly pick Between two and four then the position is going to be at row column and we'll just return continue so we know
that we can continue the game now from here we're also return and move and then what we'll do is we'll just go to main here and we'll actually start calling these functions that we wrote and then if we get a like end game returned then we'll simply end the game right we can send a message to the user we can do whatever we want in fact I'll actually let you Guys handle that but we'll talk about that in a second Okay so we've now handled moving left the other movements will be fairly straightforward I know
that was kind of complicated let's actually test this though so what we want to do is we want to check for the different key presses right so if you're pressing Left Right Etc so we need to first check okay did we press a key so to do that we're going to say if event. type is equal to py game. key down so Did we press a key down if we did we're going to say if event. key is equal to pame Kore and we'll start with left so if we press the left key then we're
going to say move tiles and we're going to pass window tiles clock and the direction which is left okay so we're checking all right did we press key down if we did let's check the key that we pressed if it's equal to K left which is the left Arrow key you can also do like k a if you wanted to do the a key so Kore a but our case we want the left Arrow key which is denoted by this then we're going to call the move tiles function pass the window pass the tiles past
the clock P the direction of left let's copy this four times and handle the other directions okay so if the key is right then we just change this to be right in lower cases otherwise we'll do up and down and then adjust this so that's up and that's down okay so now we Have all of the directions however only left is going to work right now so let's go here and let's move left and you'll notice that they merge together and then we saw a new four got added to the screen now when I press
left you'll see that even though there's no movements happening a new thing will add onto the screen and you can see that as we move them they will move and they will merge accordingly okay so we can only currently move left and you'll see that Now at this point the game's over because we can no longer move or merge any more tiles although I guess we could go up or down or whatever but in this case that's fine okay so that's it for left now we just need to handle the movement in the other directions
and then we're done so to move in the other directions we pretty much just need to copy all of this and then adjust it for the different directions so let's go with right now so we're going to copy All that and paste this inside of here so to move right is going to be very similar we're going to keep the column key the same we're going to change this to be true because now we want to sort in reverse order the Delta now is going to be positive so moving in the right direction and the
bound check is going to be if the columns is equal to column minus one because that is going to be uh the kind of right boundary right if we're equal to whatever the number of Columns is minus one well then we're in the last column now getting the next tile we're just going to add one not subtract one and now the merge check will look a little bit different so here we're going to change the sign to be less than and we're going to subtract the move velocity cuz now we're moving right and now for
the move check again we're going to need to adjust that as well so this is going to be tile dox plus the rectangular width plus the move Velocity is less than the next tile dox okay so we kind of just flip this around again because we're moving right that should now handle right and then we're going to say ceiling is equal to false because we actually want to round down when we're moving to the right side okay let's run this and let's check left and right so we can now move to the right and we
can merge as well as moving to the left okay looks pretty good obviously we Could you know make the movement more fluid but I think this is actually pretty good so far okay let's see what happens if we go and merge and you see now that game is done all right so let us now do the up and the down okay so how do we do this well for up we're going to copy the exact same thing and actually we'll copy it from left because it's going to be a little bit more similar to that
one and paste that here now for the sort function we're now Moving up and down which means rather than using the column we're going to use the row now for reverse this is going to be false as well and for the Delta we're going to change this now so it's going to be zero and it's going to be negative move velocity because we're moving up in the y direction for the boundary check this now will be row not column so if we're at the zero with row that means we're at the top of the screen
and when we get the next tile we're looking above So it's going to be row minus one and then the call will stay constant for the merge check now it's going to be similar but this time we're moving up right so rather than using X we're going to have to use y so we're going to say tiley is greater than next tile. Y and then this will be plus the move velocity for the move check similarly again we need this to be y so we're just going to adjust this so that rather than uh X
it's Y and we're just going to change From rect width to rect height okay if we sealing that's going to be true as well and now we're going to copy this and we're going to do the same thing for down okay so down this time reverse is going to be true CU we're moving downwards the move velocity is going to be positive the boundar is going to be rows minus one when we look at the next tile we're looking down a row so we're going to add one and for the merge check again slightly more
adjustments here so We're going to say tiley we're going to change the sign and this is going to be less than the next tile. y minus the move velocity and for the move check same thing it's going to be next tile doy we're going to change the sign and we're actually going to take this and we're going to put this on the other side okay so we're going to go like that plus the recti plus the move velocity less than the next tile doy and the ceiling is going to be false okay now if We
run this we should have a finished game so let's go ahead and do this and you can see that we can move move up we can move down we can move to the right and we can merge our tiles and we can play the famous game of 2048 I don't know if I quite know the strategy maybe as well as some of you guys but there you go functioning game now as I kind of play through this I will mention that there are a few like kind of tiny little bugs or things that you could
adjust Here for example it doesn't handle when the game is finished that's actually something I intentionally wanted to leave for you as homework we already kind of set it up so it should be fairly straightforward to add it and there's a few other like kind of small movement things that you might notice if you play this a long time but overall I think it's pretty good and it's not really worth it to fix them right now because it will add a significant amount of time To the video and I think most of you are going
to be pretty happy with this implementation that we currently have now another thing to note is that if you get too high up you're going to run out of colors so if we look at this here I only added uh my quick math is what like 10 colors nine colors so that means we're only going to be able to go up to two to the exponent 9 or actually I think two the exponent yeah two the exponent 9 so you're going to need to Add some more colors if you want to handle larger values than
whatever two the exponent 9 is I don't actually remember what that value is so uh you can add more colors you'll see you'll get an index error if you go above that value but that's a pretty easy thing to fix okay reminder all of the code will be available from the link in the description I hope you guys enjoyed this video if you did make sure to leave a like subscribe to the channel and I will See you in the next one [Music] in this video I'll be sharing with you how to build a platformer
game in Python this game will have Pixel Perfect Collision it will have an animated character as you can see here it will have single and double jumping it will have all kinds of different animations for falling jumping colliding with obstacles for example you can see here when I hit the fire I kind of go into This hit State I will show you how to generate different objects how to scroll the background and really at the end of this video you will have a solid fundamental understanding of how to build a platform or game in Python
and you can go and extend this and build really anything that you can think of I will even include a ton of free assets for you that allow you to change your character change the terrain change the background and do all of that extremely Easily in fact in this tutorial alone I will show you how to use four different characters let me show you those characters before we continue so this is the second character here this is being referred to as mask dude this is the third character I'm calling this guy the ninja Frog as
you can see and finally we have this character here which is called Pinkman now in this tutorial you will learn how to use all of these characters and you can swap them out with a single Line of code with that said I hope you're excited this video has taken a very long time to prepare so please click the like button all right so let's go ahead and get into it now since this is a long video I do want to spend a minute here just talking about who this video is designed for exactly what you're
going to learn and what you can expect just so you don't waste your time if you don't want to go through it so this video is really designed for people That have a bit of experience with python ideally you are an intermediate python programmer you understand the syntax you know for Loops you know functions you know all of that if you don't feel free to follow along but I'm not going to be explaining those basic concepts now this video will teach you how to build exactly what you see here so by the end of the
video you will have exactly this and if you're not interested in waiting until the end of The video then you can download the code from the GitHub repository that I will leave in the description that's also where all of the assets are going to be so regardless you're going to have to download the code from GitHub again I will leave that in the description download that open up the uh folder and kind of we can start working from there now really what I'm going to be showing you here mostly is Sprite sheet animation uh Pixel
Perfect Collision Using what's called masks and then how you can do the scrolling background generating objects all of that kind of stuff that is really the hard part when it comes to generating a platform or game once you have all of that down it's very easy to extend this to add levels to add like you know a finishing flag to add coins to add um you know lives you can turn this game into anything you want and that's how I've designed this so that you have the base and then you Can go and make it
kind of a full-fledged game and work off of that so with that said I will stop talking now I think this game looks really good I'm excited to share this with you guys so let's get into actually building it so right now I have Visual Studio code open obviously we're doing this in Python and I already have py game installed now the first thing we're going to have to do is install py game which is the module we're going to be Using so to do that go to your terminal and type pip install pame if
that doesn't work for you you're going to try pip 3 install py game if that doesn't work try python hyphen M pip install P game if that doesn't work try Python 3 hyam pip install py game if none of those work I will leave two videos on the screen that show you how to install that module now once you have pame installed I'm going to assume that you've downloaded the GitHub repository Go to GitHub there's a little button that says click to download download the folder extract it to your desktop and then open it in
vs code or whatever editor you want so you have something that looks like this you should have an assets directory inside of assets you should have a bunch of different folders then you should have a main python file that contains all of the finished code now obviously we going to write the code from scratch but you can either work off That existing code or you can kind of clear the file and type along with me whatever you want to do I quickly want to run you through the assets folder and then we'll get into the
code so in assets we have a ton of stuff we're not going to use most of this but I wanted to include all of it so that you could kind of continue the game later if you want so we have for example backgrounds these are a bunch of background tiles so you can change uh kind of the theme or Color of the background very easily I'll show you how to do that we have items like boxes checkpoints fruits Etc we're not going to use use any of those then we have main characters for main characters
we have a bunch of sprite sheets inside of here and I'll show you how we can split these Sprite sheets apart and use all of the different kind of animations inside of here right so we have that for Mass dude ninja frog Pinkman and virtual guy all of the file Names are the exact same okay then we have menu we're not going to be using anything from there we have other we have terrain we are actually going to be using terrain specifically we're going to pull out this kind of block here but you could change
the BL again if you want to do that and then we have traps and we are going to be using the fire trap uh wherever that is right here uh that has kind of an animation right where the fire is going but again you Can add all of this stuff later on I will show you kind of the base on how to do it and then you'll be able to extend from there okay now that we understand the assets I apologize for such a long introduction let's get into writing the code I also need to
plug that I do have a course programming expert. if you guys want to get better at python check that out from the link in the description okay so let's start at the top of our program here by importing everything we Need we're going to import OS we're going to import random we're going to import math we're going to import pame we're going to say from OS import list directory and we're going to say from os. paath import is file and join now the reason I'm doing all this OS stuff is because we are going to
be dynamically loading all of the Sprite sheets in the images so that we don't have to manually like type out the file names that we want I'll show you how we Write a function that just loads these folders here kind of splits the Sprite sheets automatically and gives us all of the images that we're interested in okay after we do that we're going to say py game. init we need to initialize the pame module then we're going to go down here we're going to set a caption for a display I'm going to say pame display.
setor caption if you're unfamiliar with what this is doing this is setting the caption at the top of the window I'll Try to explain most of the pame stuff uh as we go through the video I also have a ton of videos on pame on my channel if you want to check out something a little bit more basic okay now what I'm going to do is Define a few Global variables that we're going to be using here the first one is going to be the background color now we'll use this for now until we Implement
our own background and for the background color I'm going to make this white which is going to be 255 255 255 all of our colors in pame are going to be in RGB okay okay so red green blue that's what we have for our background color we're then going to define the width and the height of our screen for some of you you're going to have to make this smaller if you're on a smaller display for me I'm on a 2K monitor so I'm going to go with a th000 by 800 uh but if you're
on again a smaller screen you might want to make this just a bit smaller uh so that it works for you Although it doesn't really matter um make it whatever size you want next I'm going to say my FPS which is my frames per second is going to be equal to 60 and I'm going to Define my player veloc bosty equal to 5 and this is going to be the speed at which my player moves around the screen okay now that we've done that we need to set up a pame window so I'm going to
say py game. display. setor mode and then I'm going to pass the width and the height to this Uh window argument here this mode argument and this is going to kind of create the pame window for us I'm going to store that in the window variable and there we go we have kind of our Global variables created now I'm going to make a main function going to say Define main this main function is going to be what we run uh to kind of start the game so inside of here I'm going to take a window
and at the bottom of my program I'm going to say if uncore uncore name Underscore uncore is equal toore maincore uncore then call the main function and pass the window argument okay so hopefully you can see kind of the structure of our program already the reason I have this line right here is so that we only call the function if we run this file directly if we don't run this file directly say we imported something from it then we won't run the uh game code okay so that's why I have this inside of main is
where we're going to Write kind of our event Loop the event Loop will be what's handling say the Collision moving our character redrawing the window all of that kind of stuff this kind of good practice to have your vent Loop in one place so inside of the main function we need to set up a few things the first thing we need is a clock so we're going to say clock is equal to p High game. time. clock we also need to Define uh what is it a wall Loop that's going to continually Loop And act
as our event Loop so I'm going to say run is equal to true I'm going to say while true or while run sorry and then the first thing I'm going to do is say clock. tick FPS now FPS remembers our variable right here what this line does is ensures that our wall Loop is going to run um 60 frames per second okay so no more than 60 times per second that's what this ensures if you're on a really slow computer chances are you could be running less than 60 frames per Second but in my case
I'm on quite a fast computer and if I didn't put this here then you'd see that my game would be like way faster than yours so we need to do this to regulate the frame rate across different devices okay now that we have that we're going to say for event in py game. event. get and the first event that we're going to check for is if the user quits the game if they quit by quitting I mean they hit the Red X in the top right hand corner Then we need to stop the event Loop
and exit our program so I'm going to say if event. type is equal uh to pame do quit then we're going to say run is equal to false and we can break out of this Loop then we can go down here and we can say pame do quit notice this is outside of the wall Loop and then we can put quit which will actually quit the Python program okay so now we have our basic event Loop and what should happen if I run the code now Is a pame window should pop up nothing should be
on the screen and if I hit the red arrow it should close so let's try this and see what we get okay notice it says platformer and then I hit X and it closes perfect uh we're well on our way to creating the platform or game all right so now that we've done that I actually think that the first thing we can do is generate our background then once we have the background we can create a basic player That we can move around the screen and once we have that we'll start doing all of the
animations and then later in the video once we've got uh kind of the bulk of the stuff done we'll handle the collision and all the movements right okay so I need to make a function here and I'm going to call this getor background now before I dive into this let's have a look at our assets folder again now what I want to do is use these tiles right they're just tiles I believe Their size is 64x 64 or 32x 32 something along those lines anyways we want to use these tiles and tile the whole background
so what I need to do is essentially create a whole grid of these tiles based on the size of my screen so the way I'm going to do that is by using a folder here this folder is going to return to me sorry not this folder my bad this function this function is going to return to me a list that contains all of the background tiles that we need to Draw so that's what we're going to do here with get background now what we want to take is the name sorry as I was saying the
name is going to be the color of our background and that's that's going to allow us to change what background that we're using so the first thing we need to do here is load this background image now it's very important that when you run this file you run it from the directory that the file exists in now the reason I'm saying that right Now is because the way I'm going to load this image relies on the fact that you're running this code from the directory that it exists in so see here that I'm in desktop
python platformer and then notice tutorial is inside of that directory that's why this is going to work if you try to run this code from a different directory say I CD a desktop and then I tried to run this then I'm going to get an issue so just make sure you're in the correct directory I just Want to say that before we even get into this okay so I'm going to load my image I'm going to say image is equal to py game. image. load and then what I'm going to do is join the assets
path which is directly in the directory this files in with the background uh path here if I spell background correctly and then with the name which is going to be the file name that I want to load which is really just the color of the background okay now That I have that I want to get the width and the height of this image so I'm not guessing what it is so I'm going to say underscore uncore with height is equal to image. getor wct now when you do this it will give you the x y
withd height I don't care about the X Y so I've just put two underscores here denoting that I don't care about these values and then I'm able to grab the width and the height so now that I have the width and the height I'm going to say tiles is Equal to an empty list and then I'm going to Loop through um essentially how many tiles I need to create in the X and the Y Direction so I'm going to say 4 I in range and then I'm going to take my width I'm going to integer
divide this by the width of my tile and I'm going to add one and then I'm going to do the same thing for my height here so I'm going to say 4 J in range height over the height of my image plus one okay so notice width here is the width of the Screen height is the height of the screen I'm integer dividing this by the width of my tile and that tells me approximately how many tiles I need kind of in The X direction to fill the whole screen then just to make sure that
I don't have any gaps I add one and I do the exact same thing uh for height in the y direction then what I'm going to do is say actually yeah I'm going to say wct uh is this re no we're going to say pause is equal to I multip by the width And J multiplied by the height and this is going to denote the position of the top left hand corner of the current tile that I'm adding to this tiles list in pi game when you draw something on the screen you draw it from
the top leftand corner so what I'll be doing is continually moving the positions based on how this for Loop is going right so for every I for every J I'm multiplying it by the width and multiplying it by The height and that gives me the accurate positions I need to place every single tile in on the screen hopefully that makes a bit bit of sense but that's how this is working uh and then I'm going to say tiles. append my position and then I'm going to return my tiles I'm also going to return the image
so that I can uh know what image I need to use when I'm drawing all of these tiles okay now that I have my background I'm going to go into Main and I'm going to Say my background is equal to get background and for the name I'm going to reference here in the background folder any of these images so we can use anyone we want uh it doesn't really matter I kind of like the blue one so I'll go with blue feel free to change this though on your end and there we go if I
can type this correctly okay so I'm going to say background comma BG image like that and now I want To set up something that's going to draw my background so I'm going to make a function here and I'm going to say draw this is going to take in a window and for now it's going to take in a background and later it'll take in everything else you want to draw inside of here I'm going to say p game do display. update and before I do that I'm going to draw my background so I'm going to
say four and this is going to be tile in background like that and then I'm Going to say window. blit and actually I need to take my BG image as well so let's take that and I'm going to draw the background image and then what I need to pass here is the position I want to draw it at which is going to be tile so what I can actually do is just convert this to a tle um notice the tile is going to be a list right tile is going to contain kind of my XY
position you can see that here right we're a Pending pause which is a list of XY and now that I think of it to make it easier let's just make this a topple directly and now we don't need to convert it okay so in case anyone's confused what we're doing here is looping through every single tile that we have and then we're going to draw our background image at that position which will fill the entire screen with background images then what we're going to do is update the display the reason we update is so That
every single frame we kind of clear the screen right and we don't have old drawings still on the screen you'll see what I mean in a second but this draw function is where we're going to do all of our drawing for now the only thing we need to draw is the background later it will be the player the blocks the obstacles Etc okay so now I'm going to go inside of my wall Loop and I'm going to call this draw function that we just created now I'm going to pass window and Then of course I'm
going to pass my background and my BG image okay now this reminds me that I no longer need this background color we're not going to use that so I can get rid of that there okay so at this point assuming I've loaded the image correctly we're now going to see this tiling the entire screen so let's save and run and notice that we get it right tiling the entire screen looks pretty good to me and we can quite easily change this if we want by just Going here and saying okay rather then blue I want
yellow and then we say yellow and now we get a yellow background great so that's that's kind of the advantage of how I've done this here you can change the background to any color you want well given that it's in the background directory now that we have our background what should we do next well we probably want to put a player on the screen and start seeing some images for That player now the player itself is the most complicated aspect of this program there's a lot of movement going on with it so we'll start by
just creating like a block for our player kind of move the block around have it jumping around then once we do that we'll do all the Sprites and animations just so that we can get some more progress before we dive into that because it is a bit of work okay so let's go here and let's say class player we're going to use a class for our Player it kind of makes sense here and this class is going to inherit from pame dos sprite. Sprite now I don't typically use Sprites when I'm working in py game
but I'm going to use them in this tutorial and the reason for that is that it makes it very easy to do Pixel Perfect Collision when we have two spr right objects which we're going to have cuz we're inheriting from the pame Sprite class we can use a method that tells us If these Sprites are colliding with each other so just understand that's why I'm doing this inheritance you don't have to understand exactly what the Sprite is uh but it kind of denotes that we have some properties on our class and then it allows these
special py game methods to use those properties to handle the Collision for us so we don't have to write anything too complicated when it comes to the Collision although we still do need to handle it a bit okay so what We're going to do here is Define our initialization and we're going to take in a self an X Y width and height now the width and height will really be determined by the image that we're using for our player but for now since we're going to have like a block for our player until we add
that image we're going to have a width and height now that reminds me that I just need to set a color for my player so I'm going to say color is 255 00 I'm making this a Class variable just so it's the same for all of my players and I have access to it just right on the class okay now what I'm going to do is say self. rect is equal to py game. rect and I'm going to pass my X Y width and height so rather than representing all of these values individually uh we're
just going to put them on the rectangle and this is going to make it a little bit easier for us to kind of move the play around and do collision and all of That so erect really is just a topple that's storing four individual values when I make it P game. rect it means we can use it in some kind of special equations and whatnot okay now for our player we're going to have to have a few values uh the first thing we're going to have I'm getting a bit ahead of myself here but is
going to be the x velocity and the next is going to be the Y velocity now the X and Y velocity is going to denote um what do you call it Here how fast we are moving our player every single frame in both directions right so the way that we'll actually move our player is we'll just apply by a velocity in a direction and then it'll just keep moving in that direction until we remove that velocity now this will be great for example for something like gravity or jumping um and you'll you'll see what I
mean in a minute okay now that we have that we need to add something known as a mask uh for now I'm Going to say the mask is equal to none and then I think that's all we need for right now so now that we have that let's add our first function here which is going to be the move function so move is going to take in a displacement in the X Direction and a displacement in the y direction and it's going to say the self. r.x plus equals the Direction X or displacement X sorry
and self. r.y plus equals the displacement y now if we want to move up or down or left or Right we just change the sign uh of this uh DX or Dy right okay so now we have uh move next what we want to do is create two functions one for moving to the left and this is going to take in the velocity we want to move in the left Direction and the next is going to be moving in the right direction again this is going to take in self and V now to move left
what we're going to do is say our self.x velocity uh is equal to and then this is going to be negative Velocity and then to move to the right we're going to say self.x Vel is equal to V now the reason we use negative velocity here is because of if we want to go left we have to subtract from our X position in pi game remember our coordinate system is that 0 0 is the top leftand corner of the screen so if I want to move down I add to my y-coordinate and if I want
to move to the right I add to my x coordinate so if I want to go up I subtract y if I want To go left I subtract X so that's why I'm putting a negative Val here I know it seems a bit weird how I've just done move and now I'm saying move left we're going to have negative don't worry you'll see how this works in a second next I'm going to say if self. direction does not equal left then self do direction is equal to left and I'm going to say self. animation count
is equal to zero now we're not going to use these right now but I just want to add Them in um for now at least uh and you'll see why in a second now I'm also going to say up here self. direction is equal to left and the reason I'm adding this direction is because I need to keep track of what direction my players facing so later once I have my Sprites I know if I'm showing the animation to the left or I'm showing the animation to the right now the animation count uh we're resetting
that when we change directions and the reason we're doing that is so That the animation doesn't look all wony when we go from going left to right so we need to kind of reset the count that we're using to change the animation frames again you're going to see that later as we go through the tutorial now I've just added up here um self. animation count equals z just to make sure we don't get any weird errors later so now I have my direction and my animation C perfect okay now I'm going to copy this I'm
going to put the same Thing in move right and I'm going to change the direction here to say right and then right so now we know what direction we're facing at all points in time okay perfect next what we need to do is we need to have some kind of draw function and we also need to have what I'm going to call the loop function and in fact let's do the loop function first so I'm going to say Define Loop Loop and inside of here I'm going to take in self and FPS now what Loop
is going to do is Be called once every frame when I say frame that's really one iteration of the wall Loop and this is going to move our character in the correct direction and handle things like updating the animation and all of the stuff that we constantly need to do for our character so for right now I only care about moving in the X Direction we'll handle the jumping later so what I'm going to do is just say self. move and I'm going to say that we're going to move based on Our x velocity and
our y velocity now notice we're updating our x velocity here when we move left or we move to the right so now if we call Loop and we have some velocity in the X direction is going to move our character to the left or to the right okay again all this will start to make sense as we get through the tutorial there is a lot of stuff I need to do kind of up front before I can just show you instantly so hopefully you guys Are following along but I just want to note we eventually
of course will see how all this works I'll walk through the code so no worries if it's a bit confusing right now now what else do we need to do inside of loop well we need to update something known as The Mask which I'm going to get to in a second but before we can do that we need to Define uh what's known as our image so I'm going to say Define and this is going to be draw and this is Going to be the function that handles draw on the screen and for draw we
are going to take in our window which I'll just represent with wi now what we'll do for now is we'll just say pame do draw. rectangle we'll draw the rectangle on the window which is the first argument here it's where we're drawing it the second argument is the color which is going to be self. color then the last is the rectangle so I'm going to say that is self. rect now Notice the rect here right has our X Y width height and when we move we're updating the X and Y of the rectangle which will
then change where we're drawing it if I can find it here on the screen okay so that's what we need for draw now actually for now I think that's okay uh we will add to this obviously in a second but I think we can generate a player draw the player see it moving and then go from there so let's do that so let's go to main here I'm going to Create a player I'm going to say player is equal to player I need to pass an x a y and a width and a height so
I'm going to pass let's say 100 100 and let's make him 50 by 50 and then what we can do now is pass our player to the draw uh function we can then take player inside of here and we can say player do draw and we can pass the window okay so I will move the player in one second but for now let's just see if this is Working if it's going to show up on the screen so let's run the code and notice that now we have a red rectangle in the top leftand Corner
obviously nothing's happening right now because we're not moving it around the screen but you could see it's showing up so we have our player we're drawing the player on the screen now we want to start using some of these methods Right Moving left moving right Etc so I want to separate my movement into a function So I'm going to say Define handle move like this and for this right now we'll just take in the player now inside of handle move what we're going to do is essentially check the keys that are being pressed on the
keyboard if you're pressing left or you're pressing right then we'll move the character to the left or to the right eventually we will check for collision and we will do all of that so I'm going to say key is equal to pame Dokeys actually not keys. key. getor pressed this tells you all of the keys on the keyboard that are currently being pressed and I'm going to say if and actually this is going to be key really we should call this Keys though because this makes a bit more sense so we're going to say if
keys and then this is py game. Kore left this is the left Arrow key key if you wanted to use the a key then you would use a like that uh yeah actually I'll go with left Arrow key cuz That's what I usually do but you can use a or swap it however you want and then I'm going to say if this is the case then player do move uncore left and how much do I want to move the player by because we have to pass the velocity well this is going to be my player
velocity right okay next I'm going to say if keys and this is py game. Kore WR then I'm going to say player do Moore right again same thing I'm going to move this by my player velocity Now it's important that before I do this I set my player velocity to be zero now the reason this is the case is because if I don't do this what will happen is as soon as I move left this is going to set my player velocity right which you can see here my XV it's going to set the x
velocity now once I set that I'm going to continue moving in that direction until it gets set back to zero so if you wanted to make it so when you press a key you just continually move in that Direction until you press a different key then you could omit this but in our case we only want to move while you're holding down the key so I'm going to say play. XL equals z there's a lot of other ways to go about doing this but I just want to stay consistent with our movement because of how
we're going to do the gravity so for now just bear with me we essentially set the velocity to zero and then if we are moving left or right so if we're pressing these Keys Then we change the velocity to be you know the negative player velocity or the positive player velocity based on the direction we're moving in okay that's actually all we need for handling the movement so let's put the handle movement function uh where we going to put this we're going to put this before we draw so we going to say handle move I'm
going to pass my player all right now I need to make sure before I do this that I call my Loop function okay and I Pass my FPS and the reason I need to call Loop is because Loop is what actually moves my player right if you look at loop it's moving my player in the x velocity and Y velocity direction every single frame so if I set the x velocity well then I continue moving again if I set the Y velocity I move in that direction but that only works if we're continually calling this
Loop function okay good so we've made great progress so far let's see now if we can Move our player or if I've made any mistakes which are very likely so let's run the code and let's see okay so I'm going to hit my right arrow key you can see I can move to the right and I can move to the left obviously if I wanted to go up and down I could Implement that but we want to have it jumping which I will show you uh in a second but we kind of need Collision before
we can do jumping very good all is looking great so far now let's Implement gravity so we Kind of fall down then we can do uh kind of the Sprite sheets then we can do the Collision cuz the Collision makes more sense I guess once we have the uh the Sprite sheets done so let's Implement gravity now gravity is a little bit complicated because we want to have um like kind of a realistic gravity right that actually implements some basic physics what I mean by that is rather than just having a constant velocity we want
to actually have an acceleration For our gravity so as many of you know if you're in physics gravity um the acceleration is 9.8 m/s squared I believe that's what the acceleration is anyway in our game we want to emulate something similar to that where it feels like the longer you're falling the faster you fall you're not falling at a constant speed that makes the game just feel like really really unrealistic so the first thing we need to do is pick some value that we want our gravity to Be and this is the acceleration of gravity
so keep that in mind so for this I'm going to make a variable in my player class because this the only place we need it right now I'm going to say this equal to one so gravity is equal to one if you want gravity to be faster obviously you uh increment this value right make it large okay now inside of loop this is where we need to handle gravity so every single frame in our loop we're going to increase the Y Velocity by our gravity however how we know how much to increase the velocity by
varies on how long we've been falling full again I know this seems really weird but we essentially need to keep track of how long we've been falling so that we know how quickly we should be increasing our velocity or how quick we should be accelerating downwards so that means that I need to create a variable here called self. count and given we should really call this something better I'll call it fall count and this will um essentially tell us okay how long have we been in the air for how long have we been falling and
we'll use this value to determine how much we um increment our velocity by so I'm now I'm going to say myself. Yore velocity and I'm going to add to this the minimum of one or and then I'm going to take my self not count and this is my fall count divided by the frames per second multiplied by the self. gravity now this isn't truly what The acceleration would be but this will give us like a kind of somewhat realistic looking gravity in the game so just bear with me so what we're doing we're taking our
fall count we're dividing it by FPS the point of this is that if I want this value to be in seconds then I need to take whatever my count is which I'm going to increment every single Loop in fact we'll do this right now plus equals 1 and I divide it by FPS so if my FPS is 60 as soon as This is 60 then I've been falling for 1 second I take that amount of time I multiply it by my gravity and then that tells me how much I'm going to increment my y velocity
by however this is going to start out being really really small just like fractional decimal decimal amounts so just to make this a bit easier for us when we do our Collision I'm going to increment this by the minimum of one or this value so every frame we're moving at least one pixel Down and it doesn't take us like a full second before we really start feeling any effect of gravity hopefully uh that makes a bit of sense you guys are understanding me here but just be with me I've uh experimented with these numbers quite
a bit so I think this should be fine okay so now that we have this what should happen when I just click run here is I should just start falling immediately on the screen and obviously until we have some platforms Or Collision we can't really stop falling if we have gravity uh but let's have a look and let's see how it works for right now okay so you can see that I fall and notice I'll do this again that I start falling slowly and then it picks up the pace right so this is somewhat realistic
to how gravity would actually work and that's what I was trying to implement when I did this now that we have done that it's Time to move on and have some kind of Sprites or images I was going to do this later but I realized that we can't really do the Collision which is going to be Pixel Perfect Collision until we have some kind of images that's that's really what we need we need our Sprites so what we need to do here first is examine what our Sprites look like for our characters now remember all
these characters are pretty much the exact same they just look different but in Terms of their movements their animations number of images they're identical so whatever I show you for one of these is the same for all of them hence why we can just kind of swap them out so when I go to mask dude here let's zoom in you can see that we have for example double jump I just picked a random Sprite sheet now this sheet has six different animations or six different frames which represent what this guy's going to look like while
he's Kind of jumping or double jumping in the air so what we we need to do is we need to split this one image into the six individual images and then Loop through those images at some frequency or some time so that we can show them on the screen and show an animation right we need to kind of manually do this now some of these are single frames like falling is just single frame that's easy hit okay this is um like you know the guy disappears for a second kind of Expands goes back you get
the point what you want to Loop through these animations idle single frame actually no idle is not a single frame it's a bunch of frames this guy's arms are kind of wagging up and down we have jump a single frame run a bunch of frames and then wall jump now notice here with these uh images that they're in different directions or let's say they're all kind of facing right so another thing we're going to have to do Is rotate this image to face left when our character is facing left so that's another thing we have
to handle that not only do we just have to split these images up we also have to get a rotated version of them so that we can show you moving in a different direction same with jumping same with being idle like whatever Direction you're going we need to show the image flipped in that direction uh so not rotate sorry flip that's what we're going to do okay so Let's do this first thing I will do actually is I'll write the function that will flip our image so I'm going to say flip Sprites this is going
to take in a list of Sprites and I'm going to return pame transform. flip and this is going to be Sprite true false notice as it says here this is indicating what directions you want to flip in when I pass true this means flip in the X Direction when I pass false this means don't flip in the Y direction if you wanted to flip both you'd pass uh true twice but we don't want to do that so I have py game. transform. flip Sprite and then this is going to be four Sprite in Sprites really
I could call this image but you got Point okay so we have flip now we're going to write a function which is load Sprite sheets uh and and should we call it sheet or sheets I think sheets is fine and what this is going to do is load all of the different Sprite sheets For our character so it's going to give us the spreite sheet for double jumping for hitting for falling and then within our character we can pick what sheet we want to be using what animations we want to Loop through so I'm going
to take in directory one and directory 2 and the reason I'm doing this is so that I can load other images that aren't just my characters and this will be very Dynamic I also want to take in the desired width and height of my image and if we need to Load multiple directions so I'm going to say Direction equals false is a default parameter so that we only load like the left and the right side images like we flip the images if you pass this equal to True okay now the first thing we need to
do is determine the path to the images we're going to be loading so I'm going to say join assets dur one dur 2 notice I can use joyin because I imported this from os. paath okay now I'm going to get all of the images in This directory now the way I do that is the following going to say images is equal to and this is going to be F4F in list directory again notice I can use that cuz I imported here we're going to list all of the things that are inside of this path directory
and then we're going to say if is file and then this is going to be join path and F so what this for Loop is going to do here this uh I forget what you actually call this when you're at a For Loop in a list anyways what this line is going to do here is load every single file only file that is inside of this directory so again we're just going to get every single one of these file names and then once we have those file names we can load that image and we can
then split that image up into the individual images that we want okay so we have images now I'm going to say all Sprites is equal to a dictionary and what I'm going to do with this Dictionary is have key value pairs where the key is the let's say animation style and the value is all of the images in that animation okay so I have all Sprites now I'm going to say four image in images and I'm going to say that my Sprite sheet so the individual Sprite sheet I want to load here is going to
be equal to py game. image. load and then this is going to be join path and image and then do convert Alpha Which is essentially going to allow me to load a transparent background image okay so we are loading the image which is just one of the files that we found right from this path and we just need to append the path to it right so whatever the path to the directory is plus the image name okay we're going to load that in we're going to get the transparent background now that we have this we
need to get all of the Sprites in this image so say Sprites is equal to and now this Is going to be a list okay so again the process is load all of the different files okay we have all the files these are sprite sheets now we need to get all the individual images from the Sprite sheet uh and load those okay so I'm going to say 4 I in range and then this is going to be Sprite sheet. getor width integer divided by the width of the image that we're loading now width is going
to be the width of an individual image inside of our animation Or inside of our Sprite sheet so if I know this is say 32 pixels I pass 32 and then it gives me a bunch of images that are 32 pixels wide that's how I'm doing the loading so that's why I took width and height here okay now that we have that we're going to say surface is equal to pame Dos surface and then this is going to be width height we're going to pass py game. SRC Alpha which allows us to load again transparent
images and then I'm going to pass 32 here which is the depth don't worry about that but it's just what we need to load these images and now we need to create a rectangle which is going to tell us where in this image again image being the Sprite sheet that we want to take an individual image from and blit it onto this surface I know this seems really weird but what we're doing is we're going to create a surface That's the size of our desired individual animation frame we're then going to grab that animation frame
from our main main image we're going to draw it onto the surface and then we're going to kind of export that surface that's the way that we have to do this so I'm going to say rectangle is equal to py game. rect and for the rect this is the location on our original image that we want to grab this new frame from so I'm going to say this is I multiplied by my Width and then zero and then the width and the height of my image okay now that I have that I'm going to say
surface. blit blit really means draw and I'm going to draw my Sprite sheet but I'm going to draw this at 0 0 and I'm only going to draw the portion of it which is my rectangle so notice this is my source this is the destination and this is the area of my source that I'm drawing so in position 0 0 which is the top leftand corner of my new Surface I am drawing my Sprite sheet but I'm only drawing the frame from my Sprite sheet that I want okay then I'm going to say spreads. append
and I'm going to append my Surface but I'm going to make my Surface Two Times larger because that's what I want to do I want this to be bigger than the default size so I'm going to say pame dot transform do scale tox and then I'm going to scale tox my Surface okay again I know this seems a Bit complicated but now we have essentially stripped out all the individual frames we've just scaled them up to be double their size so if they're 32x 32 we've made them 64x 64 that's what scale 2x does and
now we need to handle the directions okay so now we need to say if Direction then allore Sprites and this is going to be image do replace it's going to be PNG this is going to be an empty string plus underscore WR is Equal to our Sprites and then we're going to copy the same thing let's copy this and put it here and now this is going to be underscore left is equal to and this is going to be flip Sprites so what we're saying here is if you want a uh multi-directional animation then we
need to add two keys to our dictionary here for every single one of our animations so for falling for hit for idle we need a left and a right side so the right side is the one that We already have so we're going to say say okay all Sprite at and then we're just going to strip off the PNG from whatever the name of our base image was so that's going to give us run jump idle hit whatever the name of our files and then we're going to pend underscore right or underscore left now for
underscore right that's our basic Sprites for underscore left we need to flip all of those Sprites and we already wrote the function that did that now Otherwise then what we'll do is say allore Sprites at image. repace PNG with an empty string this just removes the PNG and then it's going to be equal two Sprites okay then we can return all of our Sprites all right probably one of the most complicated aspects of the code that we need to write so don't worry we are done now with uh loading images at least well we'll have
to load our block But that's going to be a lot easier than loading our Sprite sheets so this now will load a Sprite sheet for us now that we've loaded our Sprite sheet we actually want to start using this so inside of player we are going to grab our images so I'm going to say my Sprites is equal to and this going to be load spreadsheets and now I need to pass what I want to load so now I need to pass the main character directory and actually this is main Characters okay so I have
a look here so inside of assets right uh yes so we're joining assets with dur one and dur 2 so the first directory I pass is main characters and then I pass the second directory which is the name of the character I want to load so mask dude ninja frog Pinkman or virtual guy you can pick whatever one you want I'm going to go with mask dude for now now for width and height uh the width and the height of this is going to be 32 so make Sure you do this 3232 and then you
pass true because we want a multidirectional Sprite so both left and right side animations that's what we want okay now that we have that we are going to change our draw here so that we're drawing our Sprite now for for now we're just going to draw like one simple Sprite just so you see how it looks on the screen then I'll go through animating the Sprite and showing you how that works okay so rather than py game. draw. I'm going to Say self. Sprite is equal to and then this is going to be self. Sprites
at idle now idle is one of the name of our animations right so if we go here we can see we have idle jump Etc so I'm accessing the key from my dictionary and then I'm going to access the first frame of this key which is zero because every single key is a whole like Sprite sheet right so now that I have my Sprite I'm going to say wind. blit and then this is going to be self. Sprite and I'm going To blit this at self. r.x and self. r.y which is the position on the
screen and then if we want we can just turn off the gravity for right now so that we can kind of see it on the screen and it doesn't just disappear okay let's try this out let's just make sure it actually loaded correctly so let me run this and and we got an error okay so let me see what error we got here um run this again it said key key error idle ah okay So the issue here is that since we load a directional Sprite we need to reference either idle right or idle left
so we can actually do this by saying idolor plus self. Direction and then so long as we set the direction which we did here to left uh this should work so now it'll change based on if we're going left or right so actually you'll see that it should swap as we change directions okay let's try this Now all right so now we have this guy facing left and if I go right he turns right left right perfect now we want to see him animated so as I was saying let's get into the animation now this
is actually going to be pretty easy because we've already loaded in all of the frames that we need so I know that we don't have a ton to show right now but a lot of the hard stuff is done for this video so just making you aware that all this time Has not gone to waste what we need to do is we need to come up with something that has uh a way to kind of update our Sprite or update what we're showing on the screen so I'm going to write a function here called update
Sprite and I'm going to take in self and I'm going to say Sprite sheet is equal to idle now this is the default Sprite sheet if we're not moving if we're not jumping if we're not falling if we're not being attacked we Use idem however if we are running or we're doing something else then we use the other Sprite sheet so now I'm going to say if my self.x velocity does not equal zero then my Sprite sheet is going to be equal to run so if I have some velocity in the X Direction then I'm
running right so then I want to change this to the Run Sprite sheet so now I'm going to say my Sprite sheet name is equal to and this is going to be my Sprite sheet plus And then underscore and then plus the self. direction perfect so now we just change the main Sprite sheet name so idle run jump whatever we add the direction to it and this tells us you know what exact Sprite sheeet we want okay now that we have that what we're going to do is say the Sprites that we could be using
for this animation is equal to self. Sprites and this is in all capitals at the Sprite sheet name all right now that We've done that we need to essentially iterate through these Sprites and every few seconds change the Sprite that we're showing so that it looks like we're animating so we need to add a variable here that is going to account for the amount of delay between changing Sprites so I'm going to call this the animation delay I'm going make this equal to five okay now I'm going to come here and I'm going to say
that my Sprite index which essentially the Sprite uh that I want to Be using here is equal to my self. animation count which we're going to increment in a second integer divided by my self. animation delay modulus by the length of the Sprites that I'm using now let's just put some parentheses here for order of operations and let me explain what we're doing so we have an animation delay that's every five frames so every five frames we want to show a different Sprite in whatever animation we're using So if we're running left if we're idle
whatever doesn't matter we want to show a different one so we take the animation count we divide it by five and then we mod whatever the L of our Sprites is so if we have five Sprites then when we're on say animation count 10 we're showing the second Sprite right you get the idea so this is dynamic this will now work for any single Sprite so hopefully you guys understand how this animation count is kind of working but we're just trying To pick a new index every animation frames from our uh Sprites but we want
this to be dynamic so we're using the length of the Sprites and again it's just it's Dynamic it will work for any single Sprite sheet have now we need to select our Sprites we say self. Sprite is equal to the Sprites that we have access to at the Sprite index then we update our animation count by one now what we can do is remove this here from draw and we just need to Now call the Self dot update sprite from our Loop okay so now that we've done that we'll call this we'll update our Sprite
every single frame and then we'll draw that updated Sprite on on the screen okay let's run it and let's see what we get notice we have idle notice I can run to the right and I can run to the left now if you think this is too slow and some of you may argue that it is then you just make this number smaller so make this Three okay and now it looks like we're running a little bit faster so it's completely up to you how you want to animate this um I'll do two for now
and let's see if this looks better so actually I think three was a pretty kind of happy medium here so let's go back to three again you guys can change this it's up to you how you want it to look okay now that we have that we are almost ready to start doing Collision however we need to introduce Something known as a mask so I'm going to make another method here I'm going to say Define update now what we need to do here is essentially update the rectangle that bounds our character based on the Sprite
that we're showing so there's different um like kind of es to the Sprites right some are a little bit taller some are a little push to the left or push to the right and the rectangle that we have we want to be essentially the same as the Sprite that We have again I know this seems a bit weird but we're going to do this we're going to say self. wct is equal to self Dot and then this is going to be sprite. getor wct and we're going to say that the top left of this rectangle
is equal to the self. rect dox and the self. r.y now pretty much what's going to happen here is depending on what Sprite image we have if it's slightly smaller slightly bigger whatever we're going to constantly adjust the rectangle Specifically we're going to adjust the width and the height of it but we're going to use the same X and Y position that we've had for this rectangle if you don't understand that um that's fine it's not a massive deal this line is not crazy important but it's just trying to make sure that the rectangle we're
using to kind of bound our character is constantly adjusted based on the Sprite that we're using now what's more important is this line which is updating The mask we're going to say self. mask is equal to py game. mask. from surface and this is going to be self. Sprite now let me quickly explain this a mask is essentially a mapping of all of the pixels that exist in the Sprite so whenever we draw something on the screen we're really drawing a rectangle right but the rectangle may not have um non-transparent pixels right so only part
of the rectangle is actually filled in hence why we get kind of a circular Image a dynamic image whatever so what this mask tells us is where there's actually images or where's where there's actually pixels sorry and this mask allows us to perform Pixel Perfect Collision because we can overlap it with another mask and make sure that we only say two objects Collide if pixels are colliding not if the rectangular box is colliding if we did rectangular Collision then it constantly looks like we're hitting something even when we're Not because the rectangle for our character
is larger than where all of the pixels for our character are you've probably seen this in a lot of games before but what the mask does is solve that problem for us and allow us to do this kind of Pixel Perfect Collision it's very important though that you call this mask if you don't do that this Collision is not going to work properly uh it needs to be masked because the Sprite that we inherited from here uses This rectangle and uses this mask property when it does the Collision all right so now that we've done
this I just need to call this function so I'm going to go here and say self. update and now we're done with most of what we need for the player so what we want to do now is we want to start adding blocks onto the screen and then letting a player fall collide with those blocks and then be able to jump because obviously we can't Really jump until we have something to jump off of otherwise jumping in thin air doesn't make a ton of sense all right so let's create another class here and this class
class I'm going to call object and this will be a base class that we use for essentially all of our objects just so that the Collision will be uniform across all of them so again we're going to inherit from the Sprite class from pame and we're going to Define our initialization so Define a Nit we're going to take in X Y width and height and name which for now is going to be equal to none but could be equal to something we're then going to say super doore nit which will initialize the super class which
is this one right here now that reminds me we need this as well in our Constructor for player so let's put that in player okay now we need to define a rectangle so we're going to say self. rectangle is equal to pame do Rect and then this is going to be XY with and height we're going to say self. image is equal to Pi game do surface and then this is going to be width height and then we're going to say pame do Source Alpha like that if we spell py game correctly again this just
supports transport transparent images for us by apologies and then we're going to say self. width equals width self. Height is equal to height and self name is equal to name we are then going to say Define draw I'm going to say self and window like this and then we're going to say win. blit and this is going to be self. image and then we're going to blit this at the self. r.x and the self. doy okay I know I went fast uh essentially this is just a base class we're not actually going to instantiate this
but this just defines All the properties that we need for a valid Sprite so we have our rectangle we have our image we are drawing the image and then in a class that we're about to use we're going to inherit from this and it will just save us from rewriting a bunch of functionality that we don't need so the idea here is that all we do is modify this image when we change the image now the draw function will automatically draw it accurately on the screen for us and all these other Properties we're just saving
in case we need them from our child class so I'm going to make a class now called block this is going to inherit from object now we're going to say Define a knit and we're going to take itself x y and the size of our block now since the block is a square we just need one dimension not two right okay we're going to say supercore nit and we're going to pass XY size size so notice this Constructor requires four arguments so we have to Pass four here we just dupc at size because it's the
same for the width and the height then we're going to say block is equal to load block which is going to be a function that we write in a second that will take a size we're then going to say self. image. blit imagine that this is going to give us an image okay which it will in a second when we write it we're going to blit the block at position 00 0 and then we're going to say the self. mask is Equal to pame mask. from surface we're going to take our self. image and there
you go we have our mask which we need for Collision okay again I know this is a little confusing it'll make more sense in a second but we're using this object which now has this draw function built in for us it also defines the wre it defines the width and the height and all of that stuff here what we do is we get the image that we need which we're going To write this in one second then we blit this image to our image which is a pi game surface and then we say self. equal
to p.m mask. from surface self. image we also could just say self. image is equal to the block uh but let's do it this way for now okay so let's now write our get Block function which I'm going to do beneath our get spreadsheet or load spreadsheet so I'm going to say get block and I'm going to take in a size now what I need to do here is Essentially find the block that I want uh in my train folder so I'm going to say path is equal to join assets and then this is going
be terrain like so and then we're going to use the terrain. PNG file so if I go here you can see that we have terrain terrain and then what we want to do is load this block which I'll be showing you how to load in one second okay now that we've done that now that we have our path we're going to say The image is equal to pame do image. load and we're going to say path again do convert Alpha so that we get a transparent backgr ground we don't really need it for this one
but just in case later we load something does have transparency we will and then we're going to say surface is equal to pame do surface and for the surface we're going to pass size size which is the width and the height of our surface we're going to pass py game. Source Alpha with a uh Depth sorry of 32 we're going to say rectangle is equal to py game. rect and then this is going to be 960 size size now let me slow down for one second if we go to terrain we can see that we
want to load this guy right here now I've already done the math this image starts 96 pixels from the top of the screen so that's the reason I'm putting 96 there because I want to start at 96 so 960 is my position and then I want to load the size of this which I Think is going to be either 96 or 64 or something along those lines anyways if I wanted to load say this train image then would still have 96 but my y position would be different in fact the Y position would probably be
a little bit less than 96 it might be 80 it might be 85 I'd have to like experiment with it to see exactly where this image starts but I just want you to understand that what I'm passing here when I say something like 960 I'm passing the Position that I want to load the image from from the image right so I'm picking out a part of this image and this is like 960 that that's why I'm picking it right here hopefully uh you guys understand that but if you want to load a different train image
then you have to adjust these to be the starting position the top left hand corner of whatever image it is you want to load here and yeah I was going to say we could load a different one but I don't want to waste Time guessing which one it is so you guys can mess with that if you want but let's just load this top one which I already know works okay now that we have that we're going to say surface. blit and we're going to blit the image and again we're going to blit it at
0 but we're only going to blit the area of it which is represented by the rectangle then we are going to return pame do transform do scale tox Surface Okay so we've passed what size we want our block to be then we create an image that is of that size okay we then say rectangle is equal to 96 0 size size right and then we blit this image onto our surface which will be the image that we return and we return this scaled up by two times so it just doubles the size that we pass
here you don't have to scale it if you don't want but I want it to be larger so I am scaling now I understand again it's bit confusing this Size is going to be the dimension of this block so you want to pass whatever the size from this spreadsheet is that you want to get in our case I think it's going to be 64 or something along those lines so that's what size will be you guys can mess around with this but really what you're going to be changing is these two values and the size
that's what you're going to change when you want to load a different image for your block okay so now for Block we have get block or load block uh did I call it load block or get Block I called it get Block okay so let's change this to be get block all right so we now have our block let's create a block let's draw a block on the screen and let's do some collision with our blocks okay so let's go here to Main and let's say blocks is equal to and let's just start by creating
a single block so for our block uh let's just put it kind Of randomly on the screen for now uh where do I want to put this let's go with something like actually I'm going to create a variable first I'm going to say block size let's put this at zero height minus the block underscore size block size is going to be equal to 96 okay and then for B size we're going to pass block size okay so the size of our block is actually 96 I lied it is not uh 64 it's going to be
96 so we're going to create A block it's going to be positioned at zero height minus block size which is going to put it at the bottom of the screen and then the size is this now we need to draw our blocks so I'm going to pass blocks to my draw function okay and I'm going to go here and actually let's call this objects and we're going to say form object or for obj in objects if we could type this correctly obj do draw I'm struggling Here with the typing and we will draw this on
the window okay so we have our block now let's quickly look at this again right we load our image okay we get our block we have our size now we create the block down here and then we put it on the screen let's run it and let's see if we get a block and of course we got an error was it say here I need to run this again uh take zero positional arguments but one was given okay so let's go to Our player class here and we can see update I forgot to add the
self parameter so let's add that in and that should fix it okay so now you can see that we have a block so now what we can do is create a whole floor of blocks if we want to do that and then we'll Implement gravity and then collision with the block so that you can see that you like can land on the Block and we can jump off of the block all right so let's make a whole floor So to make a floor we can do this we going say floor is equal to we're going
to say Block it's going to be I times block size it's going to be height minus block size block size for I in range and I'm going to say negative width width time 2 um and we're going to divide this by the block Size and by the block size okay then for my blocks uh let's actually just replace this and instead we'll just pass floor okay what I've done here with this for Loop is I've said I want to create blocks that go kind of to the left and to the right of the screen so
I don't want to just fill the current screen because we're going to have a scrolling background in a second which we'll Implement in a minute anyways I want to Have some kind of going into the left and some going to the right so I'm taking my negative width uh over the block size which is how many blocks I want to the left side of the screen and then I'm taking my width times two and I'm inry dividing that by the block size again that's how many blocks I want to the right of the screen then
I'm taking I I'm multiplying it by my block size which is telling me the x coordinate position that I want my block to be at And then this is always going to be the same because I want it to be at kind of the bottom of the screen and then for my block size well I want that to always be the same okay so let's run this now and see what we get and now we get a bunch of blocks so now that we have these blocks let's make it so we can collide with the
blocks and so we have gravity and we actually fall onto those blocks so the Collision all right Collision is a little complicated but Let's write it and let's see how we can how we can get it going here so inside of handle move is where we're going to handle our Collision which means we need to have a list of objects that we can potentially be colliding with now we are going to write a function here called handle vertical Collision because we need to handle the vertical and horizontal Collision differently for now we'll just start with
uh vertical now we're going to take in player objects And the displacement in y that we just moved now we're going to have collided uncore objects is equal to a list and we're going to say four object in objects these are all the objects we could be colliding with and we're going to say if pame dot sprite. Collide mask and then we're going to pass our player and our object now remember I told you Collision Was going to be simple well there you go this is all you need to do to determine if two objects
are colliding the reason we can do this is because our objects we've inherited from the Sprite class and on them we have a mask so we're going to use this mask property as well as the rectangle property when we collide with the mask so I pass my player I pass my object and this will tell me if I am colliding with my object perfect now if I am I'm going to do some Stuff differently depending on what direction I'm colliding in so if I'm hitting the top of the object it's going to be different than
if I'm hitting the bottom so we need to handle that here so I'm going to say if my displacement Y is greater than zero really this should be velocity but that's fine then what I'm going to do is place my character on top of the object it collided with so I'm no longer colliding with it now what this is saying is if I'm Moving down on the screen so if I'm moving down then that would mean I was colliding with the top of this object so if I am I'm going to take the bottom of
my player rectangle which is my bottom my player's feet essentially and I'm going to make it equal to the top of the object colliding with this another advantage of using rectangles you can use this kind of bottom and top property and avoid having to do you know add the height and all that kind of stuff so That's what I'm going to do now otherwise I'm going to say if my displacement Y is less than zero and I suppose this can be an L if then what I will do is say my player. rec. toop is
equal to the obj do. bottom because if I'm moving up which means I have a negative velocity then I am hitting the bottom of an object so I need to make my top be equal to the bottom okay this just makes it so you don't like say stay inside of the object Excuse me you go outside of it and it looks like you collided but you didn't go through the object now one thing we also need to do here is need to call the method player. landed M player.it head which I've not yet created and
we're going to write these to handle what happens when we land on a block and when we hit our head on a block okay then we're going to say collided objects. append and we're going to append our object and we're going to return our Collided objects just so that we know uh what objects we collided with so that we can check if we collided with like fire or a certain special object or something like that okay so that's handle vertical Collision now we need to write the uh landed and hit head method so let's go
to player and let's do this so I'm going to say let's do it here landed self now what do we do if we landed well if we just landed then we need to reset our gravity or our fall Counter so we're going to say self doall count is equal to zero so that way we stop um like adding gravity right okay what else do we need to do if we land it we need to say that our y velocity is equal to zero if we landed on a block stop moving us down and I'll add
this in now we're going to say our self. jump count is equal to zero we're going to do something with jumping that involves double jumping so we'll have a jump counter I'll just put this here now and Then we'll we'll use it later okay so that's if we landed otherwise I'm going to say Define hit head for self I'm going to say self. count equals z but if we hit our head I want to reverse our velocity so that now we move down because we're moving up right so I'm going to multiply my velocity by
negative 1 so that when I hit my head I kind of bounce off the block and go downwards that's what's going to look most natural okay so that's all we need For right now for hitting the head now we can add our gravity back and when we add our gravity back what's going to happen is we'll fall we'll hit the block it'll move us to the top of the block and then we should just be able to move on top of the block let's see if that's going to work though uh although it's not going
to work if we don't add the function call so let's add the function call here in handle move we're going to say handle vertical Collision we'll pass The player the objects and the player doy velocity and the Y velocity is essentially how much we just moved right okay very good now let's make sure handle move we need to pass our floor so let's do that all right let's run the code let's see what we get and boom look we land on a block and we can now run on top of the block and everything is
looking very good to me okay so that's pretty good now that We're on top of a block we can jump and then we can deal with uh hitting blocks um what do you call this uh horizontally right so that we can't like run into a block and we'll also make the background scroll and then we'll be pretty good we'll have a lot of this tutorial finished I want to make us jump yes let's make it jump okay so let's go to our player and let's create a variable here self. jumore count is equal to zero
now based on the way we've coded this Jumping is actually quite easy I can say Define jump self and when we jump all we're going to do is say self.y uncore velocity is equal to the negative of self doog gravity multiplied by whatever Factor you want in terms of the speed of your jump so I'm going to multiply Gravity by eight the reason I'm doing this negative is so that I jump up in the air right so now that I've done this what happen is as soon as I hit the jump Key I'll jump up
into the air it's pretty straightforward and the reason that's going to happen is cuz my y velocity will change and what will bring me down is the fact that inside of my Loop if I go to where Loop is I'm constantly applying downward gravity so what I'm doing is changing my velocity to go upwards and then I'm letting gravity take me down so that's kind of the benefit of how we've coded this jumping is very easy now I'm also going To reset my animation count to zero I'm going to say my jump count plus equal
1 I'm going to say if the self. jump underscore count is equal to one this means that I'm double jumping so if the jump Count's equal to one when I hit jump that means it's just going to be equal to two now actually let me take this sorry and put this down here then I will say self. count is equal to zero yeah I think does that make Sense no I want to do it this way sorry okay so what I'm trying to do here is make make it so that as soon as I jump
I essentially get rid of any gravity I've already obtained so let's say I was like falling and then I landed and then I jumped there would be some gravity on me keeping me on the ground so I want to remove that gravity so that when I jump up it's not in uh the factor like it's not taken into account and then I'll start applying the gravity after I've Jumped hopefully that makes a bit of sense but this should say fall count so as soon as I jump I'm resetting the fall count to be equal to
zero so that any gravity I've accumulated I'm removing but I'm only doing that if this is the first jump I'm making CU for the second jump I want you to have to time it based on like when you're jumping right so if you jump a second time close to when you jump the first time you will jump higher than if you jumped at like the peak of Your jump when your gravity would be the highest okay I don't know if that makes sense but just just follow along here this I messed with this before this
works trust me all right so we have jumping now I think that's all we really need for jumping um yeah that seems good to me so now if we want to jump let's make it so when we hit space we jump so we can do that inside of handle move actually I'm not going to do an handle move I'm going to do it here in the Event Loop and the reason for this is that if I do it in handle move what's going to happen is if I press the jump key and I hold the
jump key down I'm going to keep jumping a bunch of times I don't want to do that I just want to jump once when I hit the key and then I have to release the key and press it again to jump this tells me if I'm holding down the key what I'm going to do in here tells me if I released the key yeah you'll see um but yeah this is This how I do it so I'm going to say if event. type is equal to pygame do key down then I'm going to say if
event. key is equal to py game. Kore space and my player. jump count is less than two cuz I'm going to allow double jumping right so I'll have two jumps then I'm going to say player do jump okay that should be all we need for jumping so let's try it out and let's See if this works and I can jump and notice I can kind of Run and Jump at the same time now what I'll do now is add uh like falling and jumping animations because obviously it looks kind of weird right now when I'm
jumping but there you go we can jump nice okay so let's add the uh the animations now so if we go to update Sprite all we need to do here is we need to say If self. and actually I need to refer to my cheat sheet here because this is a bit more complicated than I thought okay I'm going to say if. self if self. Yore velocity does not equal zero then what I will do is say if self. jump count equals equals 1 then I'm going to say my Sprite sheeet is equal to jump
I'm going to say l if self. jump count equals equals 2 then my spreadsheet is equal to double jump now This is actually going to be if my velocity is less than zero which means I'm moving up now the next one that I want to add is I want to say if and actually these are all going to be lfs well not that one but this one I'm going to say l if my s. Yore Val is great greater than zero this means I'm moving down then my Sprite sheet should be equal to fall okay
so this is handling regular jump and double jump and this is telling Me if I am falling let's try it now and let's see what happens when I jump okay so it's kind of glitching a little bit uh the reason this is happening I believe is because we are applying gravity even while we're on the ground so my y velocity is always greater than zero and then stops being greater than zero that's greater than zero again so I will show you how to fix this all right so actually the way that I'm going to fix
this is a bit of a hack But it's it's going to be good it'll work here so I'm actually going to say if my self. y velocity is greater than self dot gravity times 2 now the reason I'm going to do this for fall is so that I don't immediately start glitching into this fall State when I have have a really low amount of gravity being applied to me when I've gone off the block and then I've fallen down to the block so let me show you what I mean by Just kind of running the
code here so you can see that what happens is when I hit the block when I collide with it it's going to reset my gravity count and then I'm going to kind of Spawn to the top of the block so when I'm on the top of the block I'm going to be slowly falling down to the block then I'm going to hit the block when I hit the Block it's going to do the same thing it's going to bring me to the top reset my gravity count so what was happening Before is that we would
go to the top of the block and then our gravity would increase a tiny bit right it increase to be one pixel per second or something along those lines which would mean we were falling so then we were falling we hit the block and then it reset it so it kept glitching between the two states so what I've done is just made it so we have to have a significant amount of gravity before it starts showing that fall state so now it doesn't look Glitchy on the screen as I'm jumping around and you can see
that what actually happens is when I jump and I get to the peak of my jump you can see that it starts the falling State because now my velocity has changed directions right now I'm going down okay so now we have jumping now we have running around and colliding with blocks done quite a bit actually the next thing I want to do is make it so that objects move on the screen then we will do our horizontal Collision and then we will pretty much be done uh after I add kind of that like fire uh
state right or that let's call it trap something like that okay so we want to do scrolling background scrolling background is actually fairly easy the way that we do as scrolling background is we simply offset every single thing that we're drawing on the screen by a certain amount so any object that we have we don't change its position at all we just Change how we're drawing it on the screen so it doesn't affect any of our Collision all it affects is what's seen right so what's happening in the background is we may be colliding at
a really far position to the right we're showing the position currently on the screen you see what I mean but what this involves is having some offset X which I'm going to say is equal to zero now the way that I want to have it and I'll just illustrate here is that when I'm on The screen I only start scrolling the background when I get close to the edge so like here right it would start scrolling whereas if I'm in the middle and I'm kind of moving like this I don't want it to scroll the
background until I get to the edge oh also notice you can double jump here I kind of forgot to to mention that part um so I'm going to implement that where essentially once we reach a certain boundary then the screen will start Scrolling all right so how do we do this well we can do it just directly inside of our Loop here and we're going to do it here we're going to say if the player do rect dox minus the offset X plus the player. rect dowith and actually now that I think of this we're
just going to do this we're going to say if the player. re. WR which will account for the width minus the offset X is greater than or equal to the Width minus a variable that I'm going to write in a second which is scroll area width and the player. xor velocity is greater than zero then we are going to say offsetx and this is going to be plus equals the player dox velocity all right let me just write this variable then I'll explain how this works cuz we also have to do the other side so
I'm going to say scroll area width is equal to 200 what that means is That when I get to 200 pixels on the left or 200 pixels on the right of the screen I start scrolling okay so here what I'm doing is I'm checking if I am moving to the right that's what this checks if my x velocity is greater than zero that means I'm moving to the right and this is checking if my character is right on the screen like if it's crossed a specific boundary so I take whatever the right position of my
player is which could be very far off the screen I Subtract whatever offset we currently have so if we're offsetting everything by 100 pixels for example I subtract that so I know where I'm actually showing the character on the screen and I say if that's greater than the width minus the scroll area width which means I'm at say 700 pixels something like that on the right side of the screen then I'm going to offset the screen by whatever the velocity was that my player just moved to the right so that will Make it look like
I'm scrolling now we can say or and do the exact same thing for the left side so I'm going to say if player. re. left and this is actually going to be is going to be plus the offset I got to check if it's Plus or if it's minus no it's going to be minus again minus the offset X is less than or equal to the scroll area width and my player. xor V is less than zero Then I want to do this now let's move this down on the screen a bit and I'm just
going to add some parentheses so that my condition is correct here okay so I think that should be good again I'm checking to the left and the right side if I'm moving to the left I want to check if I'm at that boundary if I'm checking to the right or if I'm moving to the right sorry I want to check if I'm at that boundary and then I Increment my offset X now all I have to do to account for this is add an offset X to my draw function and draw every single object offset
by this x so I'm going to go here let's say offsetx and now just to all of my um draw functions I'm going to pass offset X offset uncore X I'm going to go to all my draw functions and I'm going to add this offset X and what I'm going to do is just subtract the offset X from the EXP position I'm drawing everything at So say minus offset X and we'll take in the offset undor X okay now the reason this works if I move to the left my offset X is going to be
negative which means everything is going to push to the right side because we're adding to the position for it if I move to the left side or sorry if I move to the right side the offset X is going to be positive which means everything is going to move to the left so it has a Scrolling background effect let's just run it though and see if it works then I can fix it if it doesn't Okay so as I start running here you can see that now the flooor is going to start going with me
once I reach this boundary however on this side right like kind of when I'm in the middle is not doing anything I have to get to a certain boundary which is kind of invisible on the screen and then it starts scrolling with me which is what I Wanted to do and then notice if I jump here boom I fall off the platform let's do collision with blocks in the horizontal Direction so to do that I'm just going to add uh a block here so I'm actually going to make a list I'm going to say objects
is equal to asteris floor now if you've ever seen uh like kind of dot dot dot in JavaScript that's what this does in Python it just essentially breaks this floor into all its individual elements And passes them inside of this list so imagine it if me just writing this here that that's what it's doing and then I'm going to pass another block and for this block I'm going to place this at let's do Z and then for the Y this is going to be the height of the screen minus the block size time 2 now
the reason I'm multiplying this by two is so that I get it a bit higher on the Screen uh so that we can kind of run into it horizontally and then I'm going to pass my block size so just see now I want to go and rather than drawing my floor I want to pass objects and same here with handle move I want to pass objects so let me run this so now you can see that I have that block there right now notice that when I hit the block I kind of go to the
top of it and the reason I go to the top of the block Is cuz right now I'm only handling my vertical Collision so when I hit the block I have a little bit of gravity because remember there's always some gravity on me when I'm on the floor and so it thinks that I've hit the top of the block so it spawns me on the top of the block so we need to make it now so that when you hit the Block in the horizontal Direction it kind of Pops you off of it so that
it doesn't think you're hitting the top of the block or The bottom of the block alternatively which you'll see in the second and in fact let me add one more block to show you uh hitting our head on the Block so let's add another block let's make this at say block size multiplied by 3 and then for the height let's do times 4 okay now we have another block let's see where this guy is and now I can show you that I can hit my head on the Block right and I can't kind of go
above it Okay anyways we have that let's do our horizontal Collision so the horizontal Collision is a bit weird to implement the idea behind this is that since we're using our Sprite Collide mask we want to make sure that if we collide with a block horizontally we move ourselves off of that block so that it doesn't think that we're colliding with it in the vertical Direction now you just saw that happen we hit the block it thought that we were hit it like the top of the block So it put us on the top of
the block because that's what this line does right here so in our horizontal Collision we essentially need to check okay by moving in this direction are you going to hit the block if you are going to hit the block we want to prevent you from moving in that direction so that you don't hit it collide with it and then we like spawn to the top of it so let me write it and I'll explain to you how it works but it's just very important that we Check the horizontal Collision first then once we check that
we check the vertical Collision because we only want to check vertical Collision if we are not colliding with a block horizontally or if we haven't already handled or if we have already handled the horizontal Collision again the idea is we don't want to be thinking that we're hitting the block on the top when really we hit it on the left or the right side so we got to check that first so I'm going to Make a function I'm going to say define collide we going to take player objects a displacement X like that now I'm
going to say player. move and I'm going to move my player in the displacement X Direction and zero in the y direction the reason I'm doing this is I want to check if with the current velocity that my player has if now the reason I'm doing this is I want to check if my player were to move to the right or if they were to move to the left would they Hit a block that's that's what I'm checking essentially by moving the player preemptively so now what I need to do is say player. update now
the reason I need to call. update and let's go here to update is because I need to update the rectangle in The Mask before I check for Collision so again what I'm doing is I'm preemptively moving my player to where they would be moving if they were going left or right I'm updating their mask and their rectangle And then I'm going to say for object in objects if pame dos sprite. Collide mask and then I'm passing my player and my object so this is why I needed to update my mask in my rectangle so I
move my player I update it and then using that updated mask I check would I be colliding with an object now I'm going to say collided object is equal to none I've got to spell collided correctly if I am then I'm going to say Collided and this is just going to be object is equal to obj then I'm going to break okay then I'm going to say player. move and I'm going to move them back and then I'm going to say player. update okay and then I'm going to return the collided object okay so what
I'm doing right I'm moving my player I'm updating the mask I'm checking if they would collide with something if they were to move in that Direction then if they did okay I get that coll object it doesn't matter if they do or they don't after I check this Collision I have to move them back to where they originally were so I have to reverse the movement and then update the mask again then I return collided object okay again moving checking if we hit anything either way moving back to where we were before this is preemptively
checking before we allow them to move into a block all right now what we need To do is use this function uh to allow us to move left or right or to disallow us for moving left or right so I'm going to say Collide underscore left is equal to collide player objects and then negative player V then I'm going to say Collide right is equal to collide player objects and then player and then I'm going to say and not Collide left and not Collide right again what we're doing here is we're checking if we Should
be able to move left or if we should be able to move right uh based on on our current position that's why I make that preemptive movement and then here I only let you make the movement if that movement does not cause you moving into a block or colliding with one now that we have that that should actually handle our horizontal Collision that's actually all we need all right so let me run this code and let's see so I'm here okay obviously that's still working and You can see that I can't go through the block
now let's go here and actually I'm getting a bit of a bug on the right side okay so that it worked but it's a little bit glitchy and I have a feeling it has to do with the animation count of me running cuz it's only sometimes when I'm running and I hit the block that it spawns me up here so I'm just going to do another little hack here and I'm just going to multiply this by two both of them here the reason for this being that I'll just make it so there's a little bit
of space between the block and that way me changing the Sprite isn't going to affect if I collide with the object or not cuz remember remember the Sprites kind of shift to the left or to the right a little bit so just by adding this multiplied by two it should make it so that I'm never going to be colliding left or right it will make it there's a bit of space see how there's a bit of space between the block now but that's Okay because now I'm never going to have that Collision bug um where
it's going to spawn me to the top and really you could probably just add one or two pixels but you can see that that kind of fixed it right there okay so now we have collision with blocks we have a scrolling background we have double jumping I think that the last thing that we need to add here is the fire thing right kind of that trap or you hit it and you kind Of Flash and then once we've done that we'll pretty much be done the tutorial all right so let's write our class for representing
our fire so I'm going to say class fire this is going to inherit from object as well and this is going to be animated right we're going to have animated fire so this will take a bit more work but I think it'll be worth it it looks pretty cool on the screen so I'm going to take X Y width and height and then I'm going to call my Super initializer so supercore nit self XY width and height okay and then for the name of this I'm actually going to call it fire remember that we can
pass a name the reason I'm adding a name to the object is so that I can determine when I collide with the object if it's fire and if it's fire then I want to do something right okay so for self. fire I'm going to use our load Sprite sheets function for directory one this is going to be Traps and for directory 2 this is going to be fire now if we go here to traps you can see that fire is one of our traps so we have hit off on okay now there's also a bunch
of other traps right so you can you can pick a different trap if you want like you could pass this blink one or whatever the thing with these ones is that they have uh some more animation so there's a bit more logic you need to handle for them so that's why I'm going with it's a Pretty simple one to do now up here for fire I'm going to have my animation delay so let's just make that equal to three and now let's specify our image so let's say our self. image is going to be self.
fire off we're going to start with it off and then zero okay then I'm going to say self. mask is equal to py game. mask. from surface self. image like that okay then I need to set an animation count so I'm going to say my Animation count is equal to zero just like we did for our player and I need to set myself. animation name which for now is going to be equal to off okay now I'm going to make a few functions my first function is going to be on or my first method and
I'm going to say self. animation name is equal to on if we look at fire we we have hit off on we're not going to use hit we're just going to use off and on okay now we're going to have off self self. animation name is equal To off okay and then we'll have our Loop we'll say toine Loop self and inside of our loop we're going to do a very similar thing to what we did inside of our player Loop in fact so similar that I can copy pretty much all of this right here
so let's copy all that and let's paste that here now for update rather than actually just calling an update method we'll just copy the stuff from the update method here and just paste it Down okay and rather than self. Sprite we're going to change this to image and I actually think that once we remove the direction here this is all that we need for our um all right so now we just need to make a few changes we're going to get rid of this right sheet name and rather than Sprite sheet name we're going to
say self. animation name and now we should actually be good to just use this so let me space this out a bit we get our Sprites okay this is it going to be self-d Sprites no it's not going to be self do Sprites it's going to be self. fire which is this okay really I probably should have called this something else but fire is going to represent all of our fire images okay so I'm using this to get my different animations I'm getting the animation name that I'm currently playing so either on or off and
then I'm saying my Sprite index is Equal to self. animation count divided by the self. animation delay mod the line of Sprites same as what we have before my image is equal to Sprites at Sprite index and then I increment the animation count update my rectangle and update my mask which is important for the collision and I'm good now last thing I want to do here is I want to just check if my self. animation count is greater than actually if this divided by myself. animation delay is greater Than the line of Sprites now the
reason I want to do this is so that my animation count doesn't get too large now you'll notice in my player class actually didn't do this now that was intentional because if you do this then it kind of messes up how the double jump works you can do it if you want but you'll see that it it kind of messes with things and with our player we're constantly resetting the animation count when we jump jump or when we go Left or when we go right so that value doesn't really get too large but here for
our fire since it's just static like it's just sitting forever what will happen is the animation count if we never change it back to zero will get to an extremely large number which can kind of lag our program so what I want to do is just make it smaller right so if it goes beyond what the actual animation um what do you call this is the line of the Sprites are then I want to set this to Zero it's important I divide it by the animation delay though because if I'm dividing it here I need
to divide it here before I set it back to zero okay so now we have fire I think that's actually all we need for fire so now we just need to add it to our objects so let's create it let's say fire is equal to Fire and what do we need to pass for fire we need an X Y width and height so we can pick where we want to put this um where do I want to Put my X and Y okay for now let's go 100 and let's go height minus the block size
and then I don't know how tall my fire is going to be I've got to see how big I want to make this let's make it say 64 and then we'll go 32 64 here okay so if we look at fire let's quickly have a look here and go to off for example or on the size of this is 32x 64 okay that's what the size is and you need to pass that uh correctly to the fin class Otherwise it won't load the image properly so we take our height minus our block size minus 64
which will put us on top of a block now I will put this at yeah 100 is fine for now for the X and yeah 32 width 64 height there we go we have our fire now I'm just going to say fire. on I'm just going to turn it on we'll just leave it on forever uh you can turn it off programmatically if you want and then inside of objects I'll just place my fire now that I've done That it should show up on the screen when I run my code so I got an issue
let's see what the bug is here of course the output is not showing up correctly it says a knit takes from five to six positional arguments which seven were given uh okay I see the issue here let's go back to our fire and we don't want to pass self let's remove self okay let's run this uh list index out of range self. fire off zero Hm okay I'm wondering why that's giving us an issue we have off here so that should have been okay so let's go here and let's print self. fire and let's see
why it's giving us this uh this bug here all right so I have determined the issue and the issue is that I passed the incorrect size here it's actually 16 by 32 so I was passing to large of a size and that's why it wasn't giving us the correct number of images so let's change this now and run and now we should be Okay and there we go now we have fire uh but however it is off now the reason it's off is cuz we didn't call the loop method on fire so let's fix that
I can also get rid of the print statement uh that I put here that I don't need anymore okay so let's go down to Main and where we have player. Loop let's call fire. Loop and is it asking for the FPS I don't know if I took that in my Loop here no I don't need the FPS that so Let's get rid of that okay now let's call it and it should start being on uh fire object has no attribute Sprite okay let's go fix that error my apologies fire we have Sprite somewhere here that
we don't want self. sprite this is going to be self. image and self. image all right sorry with that let's run it now and there we go we now have a moving fire and notice that I can kind of be be on top of the fire right so I can Collide with it and it's like Pixel Perfect Collision pretty much when I'm hitting it so now the last thing we need is to just make it so we go into that kind of hit State when we do hit the fire that's actually pretty easy to do
we just need to add a kind of state to our player to know if we're hit or not so we're going to say self. hit is equal to false we also want to hit count because we're going to uh only be flashing for a Certain amount of time then we're going to have a method here to find hit self self. hit equals true and self. hit count is equal to zero then we're going to go in Loop and before our update Sprite we're going to say if self. hit then self. hit count plus equals 1
and then we're going to say if self. hit count is greater than and we can just pick some value but let's say FPS Multiplied by 2 which is going to be 2 seconds then the self. hit is equal to false then we go here into our update Sprite and we say actually at the top here if self. hit it's important you put this at the top by the way so make sure you put it here then we are going to say the Sprite sheet is equal to hit great then we want to now determine if
we actually got hit so we do that from our Collision functions Which are going to be here all right so we have Collide left we have Collide right and we're going to have vertical Collide now what we're going to do is we're essentially going to Loop through all of these objects and we're going to see if we hit fire now the way we'll know if we hit fire is by looking at all the objects that were returned here and it will tell us well if if we hit fire or not right because we can Look
at the name of the object and if the name of the object is fire then we know we hit fire so I'm going to say to check is equal to collide left Collide right and asterisk vertical Collide now I realized that inside of here I only returned one object whereas inside of here I returned all the objects I was colliding with vertically really we should probably be returning all of them from here as well but I think this is still going to work so We'll just leave it how it is for right now so I'm
going to say 4 obj in 2core Che these are all the objects we collided with remember I'm going to say if 2core check and toore check. name is equal to fire then player. hit is equal to True okay that is all we need and actually I'm going to say player. hit I want to call the method I don't want to set it equal to tr so what we're doing here is looking through all the objects We collided with if any of them are fire then we will put hit on the player the reason I'm doing
this first if to check is because these could be none right we could have no objects we collided with so I need to make sure I handle that case before I try to access name on an object that isn't defined all right let's run the code and let's see and player has no object no attribute hit count Okay so let's go to Player and let's go to hit count and let's make that equal to zero I guess I forgot to assign that all right let's try this now uh list object has no attribute name okay
interesting uh let's see here okay all right so I'm using to check when I need to be checking obj so let's fix that and run the code uh bu object is not callable okay player. hit aha so let's call this make hit it's because I have an attribute With the same name as my method so it's accessing the attribute when it should be accessing the method so I'm just going to say make underscore hit and now that should fix the problem for us run the code and there we go now it looks like I'm always
being hit right now that of course is a bug so hit is equal to false let's check our hit count it's because if self. hit self. hit count plus equals one if self. hit count is greater than Self. hit equals false maybe we need to reset our hit count as well okay and there's probably a bug here let's scroll down keep scrolling with our fire so we have to check if obj and obj name equals equals fire player. make hit okay not sure what the bug is let me run this again and yeah it seems
like we start Out in the hit state so maybe it's an issue in here let's have a look here if self do hit sprad sheet equals hit but we are we hit right away for some reason it's it's making us hit immediately okay let me have a look here guys and I'll be right back all right so I've realized I made a silly mistake here I accidentally had this collided objects appended outside of this if statement and that was causing all kinds of bugs and issues for Me I think I was doing some print debugging
so let me get rid of that here uh anyways I just moved it back now so that it's in the correct location so now if I rerun this now we should see that when I hit the fire it puts me into kind of this hit State last two seconds and then it ends all right so with that said guys I think that's pretty much going to wrap up this video this showed you how to create a platformer how to do animations how to do Sprites how to do a Scrolling background obviously there is a ton
of stuff that could be added to this game but I really want to leave that to you obviously I could spend hours days months working on a game like this uh but I think this is a solid enough base to really give you guys a good foundation to go out there and create something pretty cool obviously there's all kinds of assets that I will leave in the GitHub that you can use I have all kinds of other pame tutorials That you may want to reference uh if you want to learn about menus sound effects um
points scoring all of that kind of stuff you guys go on my channel search pame tutorial you will see a bunch of them those will show you how to do a t a ton of other things that you know you may want to add to this game so I hope you guys enjoyed this this was a ton of work as always the code will be in the description if you did enjoy make sure to leave a like subscribe to the channel Consider supporting me by purchasing something like programming expert and I hope to see you
in another YouTube video