TubeSum ← Transcribe a video

I Had to Start Over... But It Became Better! | Building a Game with Pygame

0h 26m video Published Jan 7, 2026 Transcribed Jul 31, 2026 D Dani Krossing
Beginner 13 min read For: Beginner Python developers interested in game development with Pygame and learning good project structure.
AI Trust Score 58/100
⚠️ Average / Some Fluff

"The title is a fair hook — the creator does restart and improve the code structure, though the 'better' payoff is modest."

AI Summary

The creator lost all their previous Pygame project files and is rebuilding from scratch. They set up a new environment, established a clean project structure with separate scripts for rendering and player control, and built a basic medieval tavern simulator prototype with a movable blue square. The video emphasizes the value of restarting to improve code organization.

[00:02]
Starting Over from Scratch

The creator lost all previous project files, so everything has to be rebuilt from the beginning, including directories and code.

[00:57]
Game Idea: Tavern Simulator

The goal is to build a medieval tavern simulator where the player can place decor and move around, starting with basic shapes as a prototype.

[02:52]
Environment Setup

A virtual environment is created and Pygame is installed inside it to keep dependencies isolated.

[03:21]
Why Import sys

The sys module gives access to Python system functions, and sys.exit() ensures the entire program closes when the game ends.

[04:22]
Pygame Window and Game Loop

The window is created with set_mode, caption is set to 'Tavern Simulator', and the main loop handles events, fills the screen, flips display, and caps the frame rate at 60 FPS.

[10:29]
Separating Renderer from Controller

Code is organized into renderer_start.py for loading assets and drawing, and player_controller.py for input and movement, following clean separation of concerns.

[11:57]
Creating Assets with Surfaces

A simple blue square is made using pygame.Surface and filled with a color, then drawn with blit onto the screen at a player_rect position.

[15:46]
Python Auto-Properties

Python automatically creates instance attributes when you assign them inside __init__, so no need to define properties at class level upfront.

[21:47]
Instantiating Classes

main.py creates objects from the RendererStart and PlayerController classes, passing the player_rect and using object attributes to center the player.

[24:08]
Structure and Future Plans

The project mirrors Unity's Start/Update pattern; future work includes save/load functionality for dynamic game states like customer positions.

Rebuilding the Pygame project from scratch turned out to be a positive experience, as it allowed the creator to implement a cleaner architecture with separate scripts for rendering and player control. The prototype works, and the foundation is set for adding more complex features like save/load and richer game assets.

Mentioned in this Video

Tutorial Checklist

1 02:08 Create a new project directory and main.py file as the entry point for the game.
2 02:22 Create a scripts folder and add player_controller.py for player logic.
3 02:52 Activate a virtual environment and install Pygame with pip.
4 03:21 In main.py, import sys and pygame, then call pygame.init().
5 04:22 Set window width, height and screen with pygame.display.set_mode((WIDTH, HEIGHT)), and set caption to 'Tavern Simulator'.
6 05:31 Define the main game loop: handle events (QUIT to exit), fill the screen, update display with pygame.display.flip(), and limit FPS with clock.tick(60).
7 10:29 Create renderer_start.py with a RendererStart class that stores the screen reference and loads initial assets.
8 11:57 In renderer_start, create a player_surface as a blue square using pygame.Surface and fill, then draw it to the screen with blit.
9 14:36 In player_controller.py, create a PlayerController class with a player_rect and speed=5, and implement input handling with pygame.key.get_pressed() for movement.
10 17:12 In main.py, import the classes from scripts, instantiate the renderer and player controller, center the player using renderer.player_size, and run the loop.

Study Flashcards (9)

What does pygame.key.get_pressed() do?

easy Click to reveal answer

It returns the state of all keyboard keys so you can check if a specific key is currently held down.

16:44

Why is sys.exit() important after pygame.quit()?

medium Click to reveal answer

pygame.quit() only closes the Pygame modules; sys.exit() ensures the entire Python program terminates cleanly.

03:53

What does blit do in Pygame?

easy Click to reveal answer

blit draws a surface (like the player) onto another surface (like the screen) at a given position.

14:11

How do you limit the game loop to 60 FPS?

easy Click to reveal answer

Call clock.tick(60) at the end of each loop iteration.

07:25

What is the purpose of player_rect in the player_controller?

medium Click to reveal answer

It represents the player's position and dimensions; it is used for drawing and movement logic.

15:17

What is the main responsibility of the RendererStart class?

medium Click to reveal answer

It loads initial assets (like the player surface) and draws game objects onto the screen at startup.

10:43

How does Python handle instance attributes when you assign them inside __init__?

medium Click to reveal answer

Python automatically creates those attributes on the instance; you don't need to define them at the class level first.

15:46

What game project is the creator building?

easy Click to reveal answer

A medieval tavern simulator where players can place decor and move a character around.

00:57

What is the function of pygame.display.set_caption()?

easy Click to reveal answer

It sets the title of the game window.

05:04

💡 Key Takeaways

💡

Tavern Simulator Concept

Shows the importance of defining a clear game concept before jumping into code, which guides all subsequent decisions.

00:57
📊

sys Module for Clean Exit

Explains a practical reason to use sys.exit() with Pygame, preventing hidden background processes.

03:21
⚖️

Separation of Concerns

The creator refactors code into separate scripts for rendering and input, a core principle for maintainable game projects.

10:29
📊

Python Attribute Creation

Demonstrates that Python dynamically creates instance attributes in __init__, simplifying class definitions.

15:46
💬

Building Like LEGO

The LEGO analogy highlights that there are many valid approaches to building software, and the joy is in finding your own path.

25:36

[00:02] where everything is. I don't know where I put my files on my computer. I don't know where the chat is. That did we like I'm starting to think that maybe I didn't even make the last two videos cuz it's just gone. Honestly,

[00:16] if you have to ask me, we didn't really do anything in the last video. We basically just set up a basic chat tpt sort of demo for how to set up Pygame. But we haven't actually thought about like what should we actually make inside

[00:30] going to code. You don't do step two then do step one. And just like with all members will have access to these files. You can just go ahead and find that inside the description at the very bottom of this video. Uh if you want to

[00:44] code along with me or if you get any sort of error messages and oh no, how do I fix this? Then you can just kind of see where I'm at and copy paste my code if you want to have help fixing that error. Basically, I think we're going to

[00:57] come up with an idea for a game. And I do actually have something in mind that I've been wanting to make for quite a long time, which is a tavern emulator simulator sort of game. Basically, we're inside a medieval tavern and we have to,

[01:14] you know, you can place decor and you can go around. There's like, you know, care of them. I'm starting to like really expand the scope here, but basically some idea about what we're going to do. I do have underwear this

[01:28] Did I just say I do have underwear on? I do have pants on. Okay, already off to a good start. So, I think to begin with, uh, we might just have to make some shapes inside the game and just kind of

[01:40] like go from there cuz, you know, typically you want to prototype something before you start creating assets for a game. waste a lot of time wait, I didn't need that staircase anyways that I just spent five hours

[01:54] creating inside some sort of drawing program. I think to start with here, we're just kind of going to go inside and um let's just go ahead and make a directory for this game cuz like I said, I just everything is gone. So I guess

[02:08] we're going to be making a new file that is called main.py cuz this is going to be the main file that just has all the stuff in it. I should probably start thinking about making scripts that has certain purposes. For example,

[02:22] player controls. That could be a really good thing so I can just import it into a new folder and we're going to call this one scripts. Inside that folder, player_controller. Right? So, we have a player controller

[02:36] and we could also actually I think we're going to start start small. You can import I believe we can import something called SIS. Uh we do also need to actually now that I think about it build a environment that

[02:52] my understanding setting up an environment just basically means that you have this encapsulated environment where if you start installing stuff like pygame or other sort of libraries or frameworks they just exist within that

[03:06] to do here is we're just going to go and activate this environment I just installed. There we go. And we now need to install Pygame again cuz like I said, to install Pygame again cuz like I said, I lost everything. Okay, it's working

[03:21] different way, but it's working. What I'm going to do next is I'm going to go ahead and start setting up this program here. I did actually kind of ask chat GPT what exactly this did. So basically import cis allow us to access the Python

[03:39] functions. So things like exiting, reading command line arguments, interacting with the standard input, output, print/ errors, knowing what OS Python is running on, etc. So basic uh the system module for Python cuz one of

[03:53] the issues is that if I run this game and I just say exit pygame and then I close that down it might not necessarily have closed down my Python program but have closed down my Python program but it closed down my py pygame part of this

[04:08] that we close down the entire system. Uh we do also need to make sure that when we set this up that we do actually import Pygame because that is actually one of the things that we're using here. So the first thing we need to do anytime

[04:22] we set up a Pygame program is that we need to initialize our Pygame. So we're going to refer to Pygame which we just imported up here. I'm guessing that's a library or a module. So just like before, we want to

[04:37] module. So just like before, we want to make sure we also create a window height the game window just like we did before. So this is one of the modules inside Pygame that takes control over the Pygame display. So basically we can set

[04:51] different parameters in here. Right now we just have two which is the size. So we have how wide and tall do we want it to be. We can also insert something to be. We can also insert something called flags depth display VSYNC. That

[05:04] is kind of cool. And just like before, we can also go ahead and give it a you have the window, you have like a little name at the top there. So, we could call this one tavern simulator. Then we do also want to control the

[05:16] frame rate. Again, it's just kind of like it it's just feeding me all the next thing. What what now? Define main. Okay. Um, but basically, we're saying is equal to pygame and then another module called time. But the next thing

[05:31] we're going to do is we're going to create the main game loop. So I'm just going to go and copy paste it from here and we'll just take it step by step. Um need to have the comment there. Uh in pygameevent.get.

[05:48] events. This allow to fully create fully feature games. Blah blah blah. Okay. So basically it's just an event handler go in and you uh, you know, listen for keyboard input or if the player clicks

[06:03] something, then we want to do something and that's basically what this is, just [music] in this case it could be a keyboard press like it says mouse closing window so forth. Uh, so this is basically needed for us to interact with

[06:17] the game. If like if this is not here, we can't do anything. [music] If the player clicks the X in the corner of the window, we quit Pygame and close the entire program safely. Next, we want to go down and fill the screen with a

[06:30] color. So, this is basically the background of our application. So, dark everything we see on screen. Without this, nothing visually changes. So, this, nothing visually changes. So, pygame.d display.flip.

[06:43] So, update the full display surface of the screen. This will update the content of the entire display. Okay. So basically at the very end of

[06:55] this loop here after we listen for events and we do stuff we you know might change the background color after running this it's only going to change it after this has been actually run. Like this basically is what says okay

[07:10] all these changes here apply them to the game. Okay then all these changes apply them to the game. So if I click move, it does not move my character until this particular line of code actually runs. Okay, so that's very important, too.

[07:25] flip. Then we want to limit the game to run at 60 frames per second. This prevents the game from running too fast. Okay, so clock tick is set to 60. And and go back up here. I think we might actually do that. Let's just go ahead

[07:40] and say we want to add a FPS. Going to set it equal to 60. We'll just use that it stored up there and we can have all our properties and just kind of like run changes up here, it make changes to the program. So that that's just kind of

[07:56] neat. So with this, we can open up the have anything other than a black black screen or like a dark gray screen. So if screen or like a dark gray screen. So if I were to say uh let's just say python

[08:09] I were to say uh let's just say python main. py try and run it. That's basically it. And you can see it says tavern simulator. So this X up here is the button that basically goes in and grabs our If we go down to this uh

[08:23] pygame.quit like that basically just grabs that and closes it down. So it runs it. So that's kind of neat. So so far so good. Now we just need to have a the last video. And I just realized we've done everything we did in the last

[08:37] video just again today. [laughter] This is basically just copy pasting. I just realized I did not name this correctly. This has to be uh how to rename py. So

[08:50] inside player_controller, we're going to import pygame again. Now from here, we're going to create a class that is going to be for the player character. So basically what the player is going to do and it's only going to be

[09:04] related to the controller part. So if the player behaves in a certain way, let's say when an enemy hits him or maybe has to like has some physics that makes him bounce back a little bit, like that sort of thing, we do not want to

[09:17] for controlling the player unless there's something interacting with the to have it in here. We're going to class called player controller. Let's just go ahead and copy paste this in

[09:31] because I want to I want to just go through this step by step. Okay. The way that chat, again, this is a very good example because the way that chat tpt gave this to us basically just says, "Oh, you want to have everything related

[09:44] here." But right now, it's trying to create my player inside the controller as well. And the main py is just like the main script that runs the game, like controls, frame rate, the window, that kind of thing. But all the objects

[10:00] inside my game should probably go inside a separate script that initiates all the different like renders all the game objects inside the game. Um, so having that inside main py or player_controller is probably not the best idea. Okay, so

[10:16] we're doing things slightly different now. We're going to go inside player controller and let's just go ahead and delete everything cuz we're going to we're going to try and do things in a more logical way, I'm guessing. Uh, so

[10:29] instead I'm going to go inside and create a new script. And this one is going to be renderer start start strat start py. So my goal here is to

[10:43] what what needs to be loaded in when you start the game up for the first time. So it it loads in assets that just needs to be there like the player, maybe some UI elements. Um, it it's basically going to take care of that. Okay. So this

[10:59] says that this function is called when we create a new renderer object we create a new renderer object which is interesting cuz what is that? The main game window surface created in main. py and we use this to draw

[11:14] everything the player sees. Okay, so this is going to basically initiate whatever is inside this particular uh that Python writes functions or in this case it's going to be a method because

[11:29] store a reference to the screen so we can draw on it later. So basically we're just grabbing the screen from inside main. py cuz that's when we initiate the screen and then we just reference to it. Then we want to create a directory to

[11:44] store all our game assets, images, etc. So basically we're creating an an array here that just goes in and and stores all this information. So we're going to store things. Then we're going to go in and we're going to load those assets. So

[11:57] we have a function here that loads in all the assets. So this function loads the game. Example one, we're going to create a simple blue square for the player. So pygame.urface width and height creates a blank image

[12:09] of the given size. So using this particular one here, we're just going to create a player surface. And I guess we can just fill that in like it says with a color, one image. So if we have an asset at some point, we can just fill

[12:25] basically going to, you know, fill it in. I I guess one thing to do here would probably to create some properties at the very start here. So we want to create a player size. How do we how do how how does

[12:40] go ahead and go down and we're going to say player size X and we're going to set this one instead. We're just going to

[12:52] copy this and we're going to paste it in. I guess we can just do this. If not, in. I guess we can just do this. If not, then we're going to have to say this and then we're going to have to say this and dot oh in this case because it's Python,

[13:05] dot oh in this case because it's Python, it's self dot then we say self dot player. So referencing to the properties instead otherwise it's just gonna we're gonna have to go down and look through the code and gonna do all that stuff. So

[13:18] we take player surface fill or in another case we could have used a image. here? Does it say we can fill in with an image? I guess fill is going to be like

[13:30] another method instead if it's going to be an image. But in this case this [music] looks nice. Draw the player at a certain location. And we did actually define that. So first we get the player surface door from earlier, right? So we

[13:44] surface door from earlier, right? So we grab the asset itself. Then we draw it grab the asset itself. Then we draw it and we position it somewhere inside the game. So we say self.screen. So that's the window that we are using right now.

[13:57] And then we have something called blit that I've never heard about before. Okay. So blit means that we draw the player surface onto the screen at the player surface onto the screen at the player_rect position. Now player_rect.

[14:11] player_rect position. Now player_rect. Where is that one? Where is it? Where is the thing? So this is a parameter, but where is the uh parameter? We don't have player_rect [music] anywhere. So the next thing

[14:24] we're going to do is we're going to go inside our player_controller and we're going to create that script. And we're just going to go through this one by one cuz we want to make sure we understand and don't just create and just copy

[14:36] importing Pygame again because we need to make sure that we actually have access to Pygame. Then we want to create a class called player controller and a class called player controller and this one only reads input and moves the

[14:49] player does not draw anything and does not create the player. Good. That's exactly what we want is. So we're going to define our initialation which we found out is when it draws everything or like initializes it on startup. So it's

[15:02] going to initialize itself. It's going to initialize player_rect which I for some reason still do not know what exactly is. Then we have a speed set equal to five and then player_rect a pygame.rect that

[15:17] represents the player. Right? But [laughter] where do we import this from? Is it inside my main py? Okay. So let let me just see if there's anything else going on here. Oh, okay. So we'll get to that.

[15:31] Okay. It it comes later inside main.p a py that's that's why we don't know what this particular thing is. Okay. So, we're going to take these parameters them inside this class here cuz right now we have our self.player_rect

[15:46] which I think is kind of interesting cuz when I do this does it automatically create a property for that particular thing? Because typically I would say that you had to go up here and say well we have this property here and then you

[16:01] you know you fill it in but in this case it does not which is interesting. So basically instead of creating properties up here inside the class in Python it automatically creates the properties when we initiate them inside this

[16:16] particular method here. Good to know. So, we also want to create a speed property. And then we assign the speed to be pass in, which in this case is going to be five, which I think is kind of interesting cuz we'll just going to

[16:31] have to check that later. Um, because I would love to just have this be like changed in here. I don't want to define it up here if that makes sense. If we go down, we can also see that we have a method for handling input.

[16:44] Pygame.key.get pressed. Basically, we're listening for a key to be pressed. So, work with the keyboard and we want to get the state of this says that we're running something on the keyboard and this is going to get

[16:57] we want to do here, which has left me with a lot of questions, is inside main. with a lot of questions, is inside main. py I'm just basically going to just copy paste everything in and then we're going to take this from the top again. So

[17:12] again we import pygame we import system which we already talked about why we need to do that import the player controller class from our script called uh so from scripts. So we're going inside the scripts folder dot

[17:25] player_controller import this particular class here from that file import the renderer class from our scripts folder. So again we have another file which is scripts. renderer start and we import renderer start. Um

[17:39] but we have the initial game set up. So basically we initialize the pi game which we need to do. We set the window width, window height, we set the screen. We talked about this. We set a caption. Again this is my tavern game. So tavern

[17:55] simulator. Then we create game objects. So now we create a rectangle to represent the player character. Here we center it by starting in the middle of center it by starting in the middle of the screen. Good. So the way to position

[18:08] things horizontally and vertically is by taking the window width divide it by two and minus it by half of the height of my player. Now in this case it could actually be kind of interesting to just kind of say that you want to import half

[18:24] of my property from inside the player controller or the the renderer cuz that if I changes that then it's going to be offcentered. Um, so that is something we'll have to do. And how do we do that? I'm guessing

[18:39] I'm guessing uh we're going to have to refer to render start just like we did down here. Uh, so we're going to say render start at dot player size and then

[18:52] we want to Oh, now it's starting to throw errors. This is not good. So why is it giving us errors now? Argument of type int can't be accessed to parameter. So, if I go back inside, we do have the renderer here. Like, this is what we're

[19:06] trying to grab. Does that mean that I will have to actually go in and define of weird that we're going to have to parentheses to initialize these. So, instead, we have to say player size Y,

[19:21] super long if we have a lot of these different properties, and then we initialize them down here. But that that's kind of weird. what chatbt wants me to do is take these and put them inside of uh this particular initiation

[19:38] uh method instead. And so, you know, after we import the screen, then we paste them in here, which is apparently better cuz now we actually load them in. Why is it not There we go. Okay. self.player and self.right. So, this is

[19:55] what it wants me to do. Otherwise, it's not going to initiate these. And this is kind of like throwing me back to PHP cuz we have something similar inside PHP in order to do this. But from here, we basically just go back inside main. py

[20:08] basically just go back inside main. py and refer to these. Now, it is throwing me a error message, which is kind of interesting. So, we might want to try because there's no comma. So, if I do this, will it actually give me some sort

[20:23] of error message? because it still says cannot access attribute for class type renderer start. Okay, so apparently it's saying I need to use renderer instead

[20:35] saying I need to use renderer instead which where do we have that? [laughter] Oh wait, there's something up here. No, that's not it. Renderer is just like a a keyword we use in order to render things. Oh, it's up here. Okay,

[20:49] initiating a new object here. So we're initializing a new object. So basically we're taking the render start and we create an object from that particular inside. So we don't just grab the data directly which just like in PHP doesn't

[21:05] make any sort of sense. So instead we want to grab the object that we created based on that class and then use the data. That makes a lot more sense. So and we're just going to go ahead and paste that in. And instead we're going

[21:20] paste that in. And instead we're going to say y like so. I want to divide by to say y like so. I want to divide by two like so. And for some reason, this is now causing errors. There we go. All right. Yeah. So, we're

[21:34] also changing the the height and the width. So, we just dynamically grab it why uh it it was trying to tell me something there. So, that's uh that's kind of neat. Um so, from here, we now create the player control and give it to

[21:47] the players wctck, which is the the player that we created, right? So, we basically means we're creating a new object here based on this one. Uh, we're pasting in the player_rect and the speed, which I do not like that we have

[22:04] in here as a variable. Um, so we should probably just define that in here instead. So instead of doing this, I actually would much rather prefer to go inside of here and just say we want to create a

[22:18] here and just say we want to create a self dot speed and set this one equal to five. I think this is much better. Okay, so we're just going to delete that. Th this is much better. Trust me, this is much better. [laughter]

[22:33] [gasps] Okay, so we go back in here and now we just remove this cuz we we don't need to define it from outside. We just we just do it there. Okay, so we know that, okay, I need to change something about the player's controls. I should

[22:45] probably go inside the player_controller script to do that. Okay, instead of like trying to find it inside main. py. That's just weird unless you want to have all those sort of like things just kind of like registered inside the same

[22:58] file. But I guess it depends on how you want to do things. Um, I do not think it makes sense. So now that we have the player controller, we can create a can draw on it. Oh, well, we did that already. We did that up there. Let's

[23:12] just go ahead and do that. Okay, cuz we just initiated the object early. That's all we did. So, now we want to run run while true. So, basically, we're running this game repeatedly in a loop and we're updating things. I don't see any sort of

[23:28] errors that might be causing or happening now that I press play. Oo, and we can use both WD. If I press left and right at the same time, it just stands still. That's

[23:42] time, it just stands still. That's awesome. Okay, this is cool. And we can no boundary. [laughter] But that that's something has to be changed. What happens? Oh, we can't resize the window,

[23:56] which is that's interesting cuz what if I want to have full screen or do something else? Um, let's go ahead and just um stop here. Basically, [laughter]

[24:08] I think this is a good start stopping point for like we have something better the last episode. So, this isn't just a repeat. Okay. Uh, we actually separated

[24:20] things. What is this pie? I don't Let's not question that. Um, so basically we now have a player controller. We have a renderer at start. This is basically when you go into Unity and you have the uh the start method and you have an

[24:34] update method and you have uh awake you have different methods that do different things. Um this is just our start method. So this is when we start the game what needs to be loaded in. Now

[24:47] this of course will have to be a little bit more dynamic at some point if we want to have a save file and we want to load in that save file at a certain point. And it then starts getting complex cuz if you have certain

[24:59] customers inside the tavern and you save the game and you close out of the game, then you need to store where those customers are so then when you start up the game again, they continue from where they left off. Um, so like stuff like

[25:11] that starts to get complex at some point. Um, but I do think this is fun and that's like the main point of making an application like this. Uh, it's trying to learn how to do things from scratch because there's literally like

[25:23] dozens of ways. I was going to say hundreds and thousands of ways, but I guess, you know, depending on there's only so many ways you can do things, right? Um, but it's just kind of fun to see how to build things. If you received

[25:36] a bunch of Lego pieces and you were told, "Oh, you have to build the Star Wars battle uh station, you know, like the big round thing." There's no "There you go. you got to start building it. Okay, that sounds fun. I'll get

[25:51] right on that. And then, you know, 10 different people will build it 10 fun to see how uh people build stuff like this. Uh so, with that said, I hope you enjoyed this video and I'll see you guys next time.

More from Dani Krossing

View all

⚡ Saved you 0h 26m reading this? Transcribe any YouTube video for free — no signup needed.