Professional Code Refactor! (Cleaning Python Code & Rewriting it to use Classes)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
he's not answering it do you want to tell it to each other I'll do it finally what's up guys welcome back to another program you do my intro ok cool hey what's up guys and welcome back to another programming tutorial in this video we're gonna build off my last one and we're going to see how we can restructure code to use classes and overall make code a lot cleaner and more professional so start this video off I recommend opening a blank folder that you can write all your new code in and then also opening up the original code for this game and to find the original code you can go to my github page which is linked to in the description it's this game dot py file so you can either just look at it here or if you want actually play around with it locally you can fork or download it by clicking these respective buttons once you've done that I recommend looking at this old code original code for a little bit and just as a reminder the game that it builds looks like this so your the red block and you're trying to dodge these blue blocks the score goes up as you dodge them and if you ever get hit then the game is over there's a little bit of context to this code when I made the original tutorial I wanted to show people how to make a game as quickly as possible and also not using too too complicated of Python skills and so as a result of that you know the game looks good but the code here this is all the code it's not terrible but it could definitely be restructured better and so that's what we're gonna do so the task here is to take all of this code and restructure it in such a way that it's you know cleaner to read the different components of this code are broken up and broken up into classes and it's easier to see the separation between different parts if you want to add additional code it's you we want to restructure this code in such a way that adding additional features is a lot easier right now adding additional features this codes kind of brittle and a simple change might break multiple things so how do we restructure this the first thing I recommend doing is to scroll through this code and identify what parts of the code should be grouped together so kind of immediately we go down I see these colors maybe should be grouped together I see all this player and enemy stuff that probably should be grouped together I see some kind of game control logic so maybe like the width and height the speed game over the screen etc maybe all that should be grouped together some of these functions can kind of hit one of those groups so like you know maybe we separate out something that draws things on the screen and something that actually controls the logic and like drops the the actual enemy on the screen you know we have this probably main loop that we could kind of pull everything out of so there's a lot of different things we can do so the thing I'm going to start with is these players instead of making them just kind of single objects that have an x and y coordinate in a list let's make a player class and we can define our human player as a subclass of that in our enemy player as a subclass of that so over here in our new folder let's create a new file and we'll call that player dot py and to initialize the player class we can do class player and then we need to start it with some parameters so if we look at the player over here it has a size and it also has an x and y coordinate to start off with so we'll put that in our knit method and if any of the things that I'm showing right now are foreign to you definitely check out my classes tutorial because that will get you up to speed on what we're actually doing in this refactor video so in it we're going to pass itself we'll pass an X will pass in Y will pass in size and then we'll set those accordingly so now one thing that is immediately nice when we start using this class is instead of in our methods down here needing to like index by 0 and index by 1 when we want to get X and y accordingly now we'll be able to do player position X player position dot Y and it'll be a little bit more clear what we're doing in our code okay so what else should we add to this player class well looking through this code over here on the right side let's see how players are used okay going through this one thing I immediately see is collision collision check so in the collision check it's just comparing a player position in an enemy position so we definitely can move that over to this player function is there anything else ok I see something here it might be in a couple spots but oh yeah draw enemies and this pygame draw dot rect so this pygame draw a rectangle right here I'll make this a little bit bigger all this stuff in this function right here that is drawing our human player and it's not really clear in the current code over here on the right side that that's what it's actually doing so let's make this a draw method of our player class so we can do def draw then we can pass in self and we also need to pass in as you can see here at a screen so I'm going to pass in a screen to this method and everything else that's the color maybe we have the color as a property of our player so we'll say the default is red self dot color equals color and talking about draw it at rect and then this looks like X this is y and then these last two things are player size and player size so we can use self to get all this information so this is what the new function is going to look like we're gonna have pi game dot draw dot rect whenever you use the screen that we pass into this class method I'm gonna do self dot color and then we're gonna pass in self dot X self dot Y self dot sighs self dot sighs and with this right here we've completely replicated the behavior and this method down here on the right but now it's gonna be a lot simpler when we're drawing our actual player because we can just do dot draw instead of Pi game draw rect etc and one thing I'm gonna do I think it might make things more clear as we go along to figure out what our remaining items are is I'm gonna comment things out that we've kind of addressed in our new refactor alright next let's add I guess the detect collision method that I mentioned earlier into our player method over here on the left so I'm going to draw make another class method so we have def detects collision and it's gonna take itself and then it's going to now take in instead of an enemy position will actually take in an enemy and so because we don't know if it's necessarily gonna be an enemy we want this kind of be generic to any player I'm going to just call this other and so what it's gonna look like now well these initial px player act player y enemy acts enemy y these now are encapsulated in our classes right here so we don't need to actually set these like we did here and then this method down here it can be replicated exactly but we just will need to reference our classes instead of the variables here so what does that look like well we have if so if enemy X in this case is other X is greater than or equal to self dot X so we're just basically replacing enemy acts with other node X and player X with self dot X well I'm gonna run through this kind of quickly and if you don't understand why what this collision method is doing again of a good excellent in the original video so check that out right so if other dot X is greater than equal to self dot X and other dot X is less than self dot X plus self dot size that's the first condition or self dot X now we're just doing the reverse is greater than or equal to other dot X and self dot X is less than so it has to be one or the others for the collision happened other dot X plus other dot size okay that's our first if condition and then we need not one of those conditions to be true so the x's need to overlap now we also need the Y's to overlap other dot y is greater than or equal to self dot y and other dot y is less than self dot y plus self dot size or self dot Y now it's the reverse greater than equal to other dot Y and self dot y is less than other dot y plus self dot size if that's the case we want to return true and otherwise we return false and so just to be clear these if conditions are checking to see if we have both an x overlap and a y overlap if you have both overlaps then we know the objects collide otherwise they don't and we return false and now we can go ahead and comment out this stuff here because I can't fit everything on the screen always here I also have the finished refactored code I'll put that on my github too so check there if you kind of are getting annoyed that things are getting clipped off in this video all right next we're going to extend our player class to include enemies as well so we'll make a subclass of the player class so this is going to take from the player class enemy and we'll initialize this with some parameters so sell X Y size we can say let's define two types of enemies that's defining normal enemy which will have size equal 50 and a color of blue and real quick I just realized that I don't think I listed these colors as like plaintext they're listed in RGB form so let's pass in the RGB forms and even actually taking in another aside let's actually create a class for these colors and we can always add to this class that we need to just going to make another new file real real quick and this is gonna be called color dot py I was going to make this class class color and I'm just basically pasting these values here and I'm not actually going to initialize anything because this is kind of a static class but okay so we have these colors and now in this player class we can read these colors by doing from color import or sorry from lower case color because the file name is color with lower case c import the color class and so now we can do color dot red here and when we want to do the super class or the sub class you new color blue and this just makes sure that we don't accidentally type in the wrong value if we're like moving these colors around in different spots and to finish the initialization we don't have really you know the draw and the detect collision are gonna be the same as the normal player class so we can just do super dot a knit X Y size and color and actually a quick update I want to make is I want you only to be able to specify X&Y here so by passing in these to the init I allow you to also specify the color Anatomy but really what we wanted me to be is a more restricted version of the player class so that all you can set is the x and y parameters so I'm gonna actually set in the super init the required colors of the super class player color dot blue and we can make another one of these let's say we wanted to have in addition to an enemy we wanted to have a large enemy class so maybe all the changes between the enemy and large enemy is that the size is 100 if a large enemy but the color is the same and then finally let's make a human player class and we'll have that be the same size as the normal enemy but we'll have the color be defaulted to red so now we can call these in another file and just specify the x and y and get them to build a player class through the super class all right so now in our refactor code we have our player in enemy classes we have a class for color so I'm going to just comment this out to let me know I have done it what else do we need to add while looking through our code here on the right side we need to add all the visuals for a game so the width height screen etc and we also need to add all the game logic so let's create two new files so I'm gonna do the first file I'm going to call it screen dot py and so that's going to handle all the visuals so we'll create a screen class and also while we're at it let's define another new file and we'll call this up this next new file the game py file and this will encapsulate all the game logic so in things that actually make the game work but not are not visual so we'll call this class game and now basically we're going to go through our code and figure out what should be in screen or what should be in game so let's do that well first off our screen is going to take in these width and height so let's set the anit here and also I just want to say real quick I'm kind of going about this in a way where I'm refactoring everything then testing another way you could do this is kind of make smaller factors so maybe you change player and then you actually update your game to use that newly created player class but what I'm going to do in this video is just go through all the changes at once and then kind of adapt my final game loop to use all those changes and fix any bugs I might have run into along the way at once at the end so class screen and we're going to knit when you start with self and now let's start with width and height what else does our visual have so I also might just define these to start as 800 and 600 does the adult default parameters maybe we give everything in our screen default parameters so that all we have to do is call screen but if we wanted to specify different things we could and that will make sense kind of once we actually start testing what else does this screen need okay so it does some initial so it does some additional initializing here so if I want to incorporate that into our class has a font that probably will want to be incorporated draw enemies will need uh probably make this method part of the screen so maybe I can just do that right now I'm going to just write this down but we'll pass for now and I'm going to start filling in this class self dot with equals with we're just setting the class parameters self dot height equals height okay so what else does our screen need going down to the game loop well it fills in a background color so maybe we should give our game a background color and we'll give that the color you give it this background color color but I'm actually named this black because it's a little bit more clear so in our screen file we'll want to import or from color import color and our now background color so the default will be color dot black and all right that's the game I think the only other thing I might specify in the screen is to specify the font so if you remember when I played the game the followers in the bottom right corner and it was the text that was keeping track of the score so we'll add to the net font type and we'll give that the default that it has here of mono space and we'll have a font size and that will default to the 35 we have on the right side okay I think that's everything we need to have in there now it's just a matter of actually initializing things properly so the screen needs to use the width and height here so do self dot screen equals PI game dot display dot set mode with alma height so we've taken care of this line basically self dot font is going to equal PI game font assist font of this stuff and I guess this is not within heightened words just width that we defined here and height that we defined here and now mono space we can pass in font type so it's whatever you pass into the class creation method across class initialization method and font size right here okay so we're taking care of this line and I think the only other thing I can think of that we might want to handle on the visual side is this clock it's going to just say self dot clock equals PI game time clock and then maybe we also pass in the refresh rate of that clock so I'll just say self dot clock tick equals clock tick and so maybe this is something we you can specify on our screen so I'll say clock tick and the default of that is thirty okay so what class methods will we need to add to this screen well we need to draw the enemy so that's one we need to refresh the background so that's two we'll want to draw this score label so it's three and we'll also want to draw the player so that's a fourth so what did I just say so I said def refresh background that will just need self and so how did we refresh the background over here well we just do screen dot fill background color so now our screen is accessible through self dot screen as we set here so we do self dot screen dot fill dot or fill and then we pass in self dot background color we can duplicate this behavior in this refresh background function okay now I'm gonna move that above draw animes so I think it's a little bit more clear if we keep drawing enemies in draw player next to each other so draw enemies how we're going to do that so we have the drawing of each function here and what does that do it iterates over the enemies and it does the PI game draw command well we can utilize our player class to help us out here so for enemy in enemy list we can instead of doing PI game about draw direkt now if we assume that this is a enemy type that we defined in the player class here we can do enemy dot draw and pass in the screen to easily draw this so we do enemy dot draw and then we just have to pass in self dot screen and that will take care of the draw enemies function that's cool so now let's do draw player that's going to take itself and then the player and for this one it's pretty straightforward it's literally just player draw self dot screen because we only have a single human player this is a human player we're assuming okay and what else did I say we needed to do I said we wanted to draw the font or the score label that we'll need to take in self and a score value and what does that look like over here but we can probably just copy this in and change it as needed to account for the fact that we have our own font I've already set up so my font that's actually now just self dot font the score is passed into this function and we can do score like this or string not score what might be a nicer way is to use f strings and pass it through like this but the functionality is exactly the same the last thing is now with is self dot width and height is self dot height I don't love that these are just kind of magic variable or magic numbers they're called they're just kind of unclear why they're defined as negative 200 and negative 40 but I'm personally okay with leaving them because I don't think there's a great alternative and this yellow should be the color of the score label so maybe we passed this in as a optional parameter so I'm going to say color and we'll say that the default color is color yellow okay so our score label should now be all set and maybe let's make one more function that we just kind of put all these things together so kind of like we do in this loop we'll just lump all these into a update screen method so this is going to take itself an enemy list player and the score and it's going to just call each of these methods in the correct order so to call refresh background we do self to refresh background to call draw enemies we do draw enemies and then we pass in the enemy you list ha player will be next and will pass in the player that we have to find in our function self dot draw scorer label next we'll pass in the score and then the last things we do in our update screen over here is we do clock tick 30 so we have a clock now so we'll do claw self dot clock dot tick and we'll pass in self dot clock tick because that's the 30 value we defined and we'll also call the PI game dot display to update so now we've kind of handled this stuff in our new code I think we've kind of defined handle draw enemies we've handled this in our updated code and I'm just as a reminder I'm commenting stuff out that we've kind of handled in the new refactor code just to kind of remind me of where we're at progress wise all right now that we've finished up our screen the last class we have to implement is our game class so that will take care of all the like speed logic it will take care of these functions that we have left over etc so let's start out by initializing it so the first things I think we should initialize to our game class are probably the speed and the score def NIT the new self speed score we'll start with that and we'll probably have to add additional things as we go so self-taught speed equals speed and self-taught score equals score okay so when we're playing our game the first thing is to actually drop an enemy from the top of the screen so I think the first function that we should fill out is drop enemy's so we'll make this a class method so drop enemy's it's gonna take himself it's gonna need to take in this enemy list and what else will it need to take in with so maybe the screen width so self enemy list and the screen width start with that so this uses the random library to stagger things a bit so we'll use that too so we can import that to our game so import random and we can start filling this out I want to try to do this as quick as possible delay equals random random cool and then I'm going to just copy in this code and tweak it as needed so you can see this we're going to copy in this code okay so if length enemy list is less than 10 and these primaries you can play around with so if you wanted to maybe make the number of enemies a parameter maybe we could also pass that in so max enemies equals 10 by default but that could be changed so self dot Max enemies equals Max enemies so if length enemy list is less than self dot Max enemies and delay is less than zero point line so this is kind of how what percentage we're staggering it so the lower we make this the more staggered they probably will be because this is kind of dependent on this method here so if we wanted to have flexibility with that we can all bring it up into our class initialization self dot delay equals delay okay so what we're doing is we're picking a random exposition that's within the screen size so now instead of doing with minus enemy size we can do and I'm going to simplify this a little bit just because we don't know what the enemy size is going to be in our function based on how we initialize things so I'm just going to say that this is screen width so it might have some stuff a little bit off the screen depending on where it places that top-left corner of the enemy but I think this is okay Y position zero that's fine and now an enemy list instead of appending just an x position in a Y position what we want to do is create a new enemy so I'm going to say enemy equals enemy X y or x position Y position and from our player class we're gonna have to import enemy so from player import enemy the new enemy and we're going to end append that enemy to the enemy list and just because we're going to want to be able to pass this enemy list around throughout our game I'm gonna take out this enemy list and just initialize it to be empty at the start of the game and then you can just directly modify that empty lists throughout the game so now this is going to be self dot append enemy list or self enemy list snot append to enemy and to clean this up a little bit I might just call this random X because it's a random X position so we're creating a new enemy with a random X and we can comment this out now that we've taken care of it next we might want to do update enemy positions so I'm going to just kind of copy this in and we'll tweak it as needed to use our class so enemy list is now not needed but we still probably do need to pass in that score actually what we don't because that's parameter here too so this can just take itself for index enemy position in a new marine enemy list well we don't need to do this anymore we can just simply do for enemy in self dot enemy list any position one that's now replaced by enemy dot y so this is basically if it's off the screen and I mean position Y and this should be kind of Y is less than height well the height is going to be the screen height so we'll have to pass that and because we're you don't have knowledge of the screen height in our game class we have that in the screen class so screen height any position dot y plus equals speed so this is basically changing the enemy position enemy's y-coordinate by the amount of the speed so the speed is high the enemy position will update a lot if it's low then it'll be slower movement it will update the Y position a little bit and one thing to note here someone brought up in my last classes video is how do you do getters and setters with Python well the nature of Python is there's no like distinguish and there's no distinction between like public and private attributes so this Y is accessible by everyone using the enemy class so we can just directly edit this y value we don't have to do like set Y we can just do enemy dot y plus equals speed directly here in the method and that's us setting it it's fine to just directly do that if you need to be a little bit more specific with logic that's happening when you get or set something there's this property attribute which I'm not going to go into now but I'll link a video on that property attribute for more complex getting and setting but this is what we can do to to set the value here and we can always just get things just like this without having to do a specific get Y method I just wanted to mention that quickly okay so if it's on the screen update the speed if it's off the screen that we want to remove the me from the enemy list so instead of popping things off what I'm gonna do instead is just call this new enemy list and anything that stays in the screen I'll add two new enemy list and anything that's off the screen will just update our score by one and this is just a little bit easier because the whole indexing on lists can get a little bit complex so I feel like this might be a better method myself to have score plus equals one and now we need to update the enemy list and that is that method we don't need to return anything now before we return the score we don't need to actually return the score anymore because we've directly set the score to be one higher in this method by this setter method here okay this is done all right collision check we can do that or set level next what makes more sense I'm going to go ahead and do the set level next so let's paste that in as a class method okay and this one is pretty straightforward to change instead of passing in score and speed we just really need to pass in self and self has access to score in speed it's a self dot score is less than twenty self dot speed equals five and this was just kind of an arbitrary increase in speed as you get higher in higher score you could rewrite this set level method to however you please and one thing that's cool too with the use of classes you could do a game subclass that rewrites this set level function to be whatever you want without changing any of this other logic which is also a very nice feature of classes self dot score is less than sixty and we don't need a return the speed anymore because it is directly updated in our game class I said that set level we can comment that out and look at this we're getting very close to having kind of everything good and actually I just these can have default if you don't want to have to set the speed in score you can set these as default values too so I'm just taking what they were defaulted to in this code that I just commented out all right so the last method I think we had was collision check I'll paste that in and this is just basically figuring out for all enemies in our enemy list whether or not there's any collisions with the human player so we can just take itself here and maybe the the player for enemy positions so for enemy in enemy list if detect collision between the well now we can just do how did we write our our collision check method or detect collision method in player that was this so it can just be called with on the player class and passing any other so we can just do if detect collision and we're now going to just do this as if enemy thought detect collision with the player return true else return false I think that's it this is not player position this is player I think that's it for this one cool and we'll test all this in a sec because I'm sure we're gonna have some bugs but for now looks like we just took care of that last class and our final thing we have to do is make our rewrite our main loop so we'll do that next let's create a new file and we'll call this one main dot py and we can copy in all this over here and now we'll just have to adapt it to user class okay so starting from the top while not game over well we need some sort of game over equals false first okay that takes care of this right here next we need to probably initialize the player here so let's see for event pi game to get it that's all good but right here we should have a player initialized so I'm going to do that player equals human player and we need to get this from our player file so oh I didn't name this human player I need a bit large enemy this was supposed to be human player and we'll have to now import from player import human player okay now we have a human player we should initialize its position somewhere on the screen but we don't know what the screen is yet so probably above this will actually have to initialize a screen so screen equals screen from screen import screen and then we can use this screen to initialize our human players location so we can do screen dot width divided by 2 for the exposition of the human and then for the Y position we should do screen dot height and then we do minus 2 times player size over here but we don't know what the player size is without like you know mainly checking the value of human player so I'm going to just kind of hard code in a 100 here so it's a little bit it's not at the very bottom of the screen it's a little bit above and you can play around with this 100 value okay so that's the player cool let's start factoring that in x and y are no longer needed we can just use X minus equals player dot size player dot size and we're now directly editing the players exposition we're setting it here player dot X and as I mentioned before we're fine and Python to directly set just directly accessing this attribute other languages you probably made a setter method player position that's now already taken care of cool one thing to note if you're on Mac you might have to do import OS instead I've imports this and I should probably import that import sis so I think on Mac you do OS exit but for Windows and Linux I think it's fine to do assist on exit okay now we need to start updating the dropping the enemies and whatnot so we need a game as well okay and so now we can do we look down over here we can drop the enemies so game dot drop enemies and then we had to pass into our drop enemies let's remind ourselves drop enemies the screen width so we could do screen dot width then we updated the enemy positions I believe and that's now called by game update enemy positions just need to pass in this or an idle actually path pass it anything here other than the let's check one more time the screen height set level that's called by game not set level and I think this one you don't need to pass anything in cool so we've accounted for all this logic kind of in here now we need to start updating the screen so we can just simply call the screen dot update screen method that takes in the enemy list so self dot game dot or actually sorry not self psyche game enemy list then it takes in the player so that's just called player here and then it takes in the score game dot score right okay update screen that looks good if collision check collision check is written differently now it's game dot collision check and then you pass in the player game where equals true yep that looks good is everything good here I think it might be one way to test it and that's just to run the code my game is not defined in screen ok so my game dot display doesn't know how to deal with that so we need to import my game here so we're now we're trying to run into some errors but we'll just work our way through that ah we got a little farther it looked like fought not initialized so what did we not do in this code that we did over here one thing I immediately see is a PI game down it so maybe we should add that to the top of our code here just like we had it in the top of our original code PI game is not defined huh ok now we need PI game here as well okay we got all the way to this file what do we need here game is not defined we just defined it game is not define oh it's because we didn't import it here from game import game oh wow we got the drop enemy's enemy list is not defined and drop enemies that's in the game okay so this is now self dot analysts did I think that's good run our main again screen dot uh page screen PI game is not defined in screen ok we defined it name play game to draw okay it's in the player dot draw so it looks like it's actually coming from the player class that we need it import by game run main come on we're so close screen is not defined here screened lit screened off UI so this is self dot screen we're working our way through them uh we saw a red thing that's good enemy list is not defined in game dot collision check ok self dot enemy list Hey is their score increasing yes yes yes I think we've successfully refactor our game this is also alright yeah that looks good to me a couple small tweaks I might make is let's pull out this stuff right in here into its own function showing on I'm gonna call this def play game and so I need to just indent this properly okay so let's play game it now needs to take in a player a game and a screen and two kind of I guess organize it logically to how we initialize these things I can say screen player game okay so now we have the play game method and now one thing I recommend you do whenever you're running code or have code that's executable is actually surround it in the if name equals equals main cuts and so basically what this line does you'll see this all over the place when you're looking at Python code is it only allows this code to be executed if you're actually running main py and why that's useful is that we can now write other files that use play game and not have this code execute and so one reason we might want to use this in other files is let's say we want to write a couple other levels of this game so maybe a more difficult level or maybe two or three more difficult levels we can still use the same play game and I'm going to show that to end this video but does it still wrong looks good to me all right let's create a new folder called levels and in that we can define a new file and I'll just call this level 2 py and we'll utilize our existing code to make this happen okay so from main dot py will want to copy in this main code and then we'll want to basically import all the same stuff and we'll also need to now from main import play game so we can access this function down here so as is level 2 should run let's see if it does know module named player and the issue here is that it's looking at the levels folder for player but now that's one directory above so what we can do is sip a thought insert this is basically telling our machine to look one directory higher to find these files so I'm going to do that real quick and now run it ok like that so our game works so how do we want to define this level to be more difficult so one way we could do this is by making a like subclass of game we could either just directly pass in some parameters of the game that makes it more difficult so or maybe like to the screen that makes it more difficult so we could like you know make max enemies 20 that'd be a that would be an easy way to do it so let's try that real quick it's already you'll see that there's gonna be more enemies than there ever was before so that's one way to make the game more difficult and this will definitely get harder as the speed ramps up so that's one thing we could even like change up the enemy that we're dropping so if we go to game I'm going to define a new class of game called class hard game and that's going to be a subclass of game and what we're going to do here is just change up this enemy that we're using here so I'm going to bring out the enemy I want to say enemy I'm gonna make this a class variable as opposed to like an instance variable that all these are defined us so we're just say enemy equals enemy and basically what this is doing is setting self dot enemy so even though I'm not in this in it if I define this class variable we'll be able to access it by doing self dot enemy and now what this allows us to do is the code will still rod maybe not oh oops I didn't pass anything in here so what I'm going to do is say enemy here is equal to large enemy and we defined large enemy in our player class over here so now I'll need to import that into game enemy and large enemy okay so all I change was enemy equals large enemy here an enemy equals enemy here and we're taking enemy and large and me from this and setting it here so in level two right now it's the same game we've got that enemy that is you know size 50 right now what happens is now if I use that subclass hard game it breaks hard game is not to find harder game here so right now we already have level two which is these oh my gosh I just screwed myself over maybe we don't make max enemies 20 here but we just created a new version of the game using our class very very easily and we could easily extend that hard game even further by maybe rewriting the cell set level function in the hard games I could say def set level here it takes himself and then maybe instead of having these kind of different levels based on the score like kind of hard-coded levels we just make it a always increasing self dot score or self dot speed equals that say self dot score divided by five and because the score is initialized to zero let's make this self dot score divided by five plus one so this also is changing up how we set the level it's going to always be increasing and that will be factored into hard game without having to make any other changes so that's like one of the beauties of classes we can make a change in one place and it doesn't break the code everywhere else so look it it's starting really slow all these are lumped together and you know maybe I change this up a little bit but once I get by this first set of blocks here you'll see it rapidly start increasing come on get off the screen get off the screen okay and now we've already gotten oh my gosh however I have a secret here I can get off the screen and block this temporarily I got really unlucky there but everything kind of is increasing there so that looks pretty cool and to block this the little cheat I just did this is something that everyone asked me on the original video in your event I keep I game dot left you could add the statement it only go left if you are greater than if your player dot X is greater than zero so you can't go left off the screen basically it won't work and only go right if you're play they're dot X is less than or equal to the screen width minus the player size no quick I'll just show that now oh I guess I can still get off the screen I screwed something up elsif player can only go right oh is sorry is greater than or equal I maybe I screwed it up because this should be in parentheses can I go left off the screen I can't go left off the screen now and I just might need to fix this right along a little bit okay yeah I can't go once I added that parenthesis it works okay so now I can't go off the screen so I can't cheat like I did all right let's finish this game off with one more level we'll say that this is the boss level so I'm gonna just call this boss level we basically copy all the code from level 2 here into boss level but now let's make it obviously be called boss level of UI so we can copy all the code from level 2 into boss level but now let's have a little bit of fun with this and instead of the hard game being defined let's define kind of the boss game so in game we're going to find class boss game and the enemy here is where we're gonna get fun I'm gonna say that this is called the Keith's enemy so we're going to find the Keith's enemy so in player we're gonna find one more enemy and it's gonna be called class Keith's enemy you can initialize the same stuff the color and stuff won't actually really matter here but you'll see in a sec what I'm gonna do okay so what we're gonna do here and the Keith's enemy is I'm going to rewrite the draw method and instead of drawing a square I'm gonna have it pass in an image of my face so it's initialize the same way but this time it's going to you know draw an image of my face and I'm not going to go through the details of how this code works but I'll show you that it does work and you can copy it into your own files but basically we define a rectangle we have an image so we need to find an image I'll define an image on the outside as in class variable maybe pygame dot image dot load and I need to have an image so I'm gonna create a little folder here called assets this is a good place if you want to have multiple pictures to store them and then I'm gonna take a selfie that I just took I'm gonna move that into assets I don't know if I can do it like this oh my god okay I'm gonna just do it okay here's the selfie copy this and I'm gonna find my assets folder and I'll paste it in here cool now I have selfie JPEG so that's gonna be the path to that is dot slash or actually might be up Wondrich already know yeah its dot slash assets slash selfie dot jpg cool cool and so now we can define our hard game with the Keith's enemy and we'll give you a we have a size 100 that sounds good to me now we can define our hard gate or boss level with the boss game class and let's see what happens alright will it no oh human Claire what's the air here couldn't open assets that selfie so the issue here is that it's getting all confused because our levels directory is not the same directory as assets so the dot slash is saying current directory - assets isn't there's no assets in the levels folder so as a quick easy fix to this what we can do in player is actually paste in the full path so I can get the full path on my windows by clicking the folder icon when I'm here so if I paste in this this is the absolute path so it is and I might have to make these other slash it direction so no matter it doesn't look at relative paths it just absolutely knows that this is the file location on my computer and its assets slash selfie JPEG okay so I can rerun boss level now maybe not Keith's enemy is not defined in boss game so I need a import key that I'm here okay look at that now it's just selfie Leone selfies with me and so you can have fun with this and make this more difficult as you please maybe to make it a little bit less daunting it's already daunting enough just having my image there so I'll have to change up the difficulty too much but maybe I say that the Keith's enemy has a size of like 75 to make it a little more manageable to pass all of them and if you wanted to you could also like play around with the screen size so width equals 1,000 let's say maybe height equals 1400 so this would make it a bigger screen so I don't know just have fun with these setting these different parameters because we made it all different classes it's a lot easier to to change different things now and I still can't go off the screen which is nice cool I think we're gonna end this video here so in this video we refactored code to be more professional more like it would be written at a software company there's still more changes we could make but I think this is a pretty dang good base for the sake of this video if you have additional thoughts on ways we could make this code even better leave them down in the comments I would love to hear your suggestions and kind of get a discussion going on all this if you enjoyed this video I mean a lot of you throw it a thumbs up and also if you haven't already subscribed I'll be making some new videos very soon so look out for a neural networks tutorial in the next couple weeks and soon after that I'll start working on a another data analysis real-world data analysis video and probably use a cattle challenge for that also if you're interested check me out on the other socials Instagram and Twitter thank you everyone for watching peace out [Music]
Info
Channel: Keith Galli
Views: 21,388
Rating: 4.9007092 out of 5
Keywords: python 3, python programming, cleaning code, using classes in python, objects python, object oriented programming, oop, python classes tutorial, code refactor, improving code quality, code quality, pygame tutorial, inheritance python, subclassing, self python, what is self, getters & setters, get and set python, class variables, python fundamentals, initializing class python, how to write classes in python, how to write good code, clean code, refactor, professional code
Id: 731LoaZCUjo
Channel Id: undefined
Length: 62min 29sec (3749 seconds)
Published: Sun Mar 22 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.