Main

Awesome Intermediate Python Project: Building an Aim Trainer…

In this video, I'll share with you how to create a custom aim trainer in Python that you can make as easy or challenging as you'd like! Beginner and intermediate programmers, this a great project for those looking for a fun project to practice your skills!! 💻 Master Blockchain and Web 3.0 development today by using BlockchainExpert: 🔗 https://algoexpert.io/blockchain (Use code "tim" for a discount!) 💻 Accelerate your software engineering career with ProgrammingExpert: 🔗 https://programmingexpert.io/tim (Use code "tim" for a discount!) 🎬 Timestamps ⏱️ 00:00 | Demo/Introduction 00:35 | Programming Expert 01:03 | Installing Pygame 02:30 | Pygame Setup 06:38 | Target Class 13:10 | Creating Random Targets 24:47 | Target Collision 31:55 | Game Analytics 43:45 | End Screen ◼️◼️◼️◼️◼️◼️◼️◼️◼️◼️◼️ 👕 Merchandise: 🔗 https://teespring.com/stores/tech-with-tim-merch-shop 📸 Instagram: 🔗 https://www.instagram.com/tech_with_tim 📱 Twitter: 🔗 https://twitter.com/TechWithTimm 🔊 Discord: 🔗 https://discord.gg/twt 📝 LinkedIn: 🔗 https://www.linkedin.com/in/tim-ruscica-82631b179/ 🌎 Website: 🔗 https://techwithtim.net 📂 GitHub: 🔗 https://github.com/techwithtim One-Time Donations: 💲 https://www.paypal.com/donate?hosted_button_id=CU9FV329ADNT8 Patreon: 💲 https://www.patreon.com/techwithtim ◼️◼️◼️◼️◼️◼️◼️◼️◼️◼️◼️ ⭐️ Tags ⭐️ - Tech with Tim -Programming -Aim Trainers ⭐️ Hashtags ⭐️ #techwithtim #programming #python

Tech With Tim

8 months ago

in this video I'll share with you how to build a custom aim trainer in Python that you can make as easy or challenging as you want now this is a great project for anyone who's a beginner or intermediate python programmer just looking to work on something fun that will help you practice your skills I don't assume any advanced python knowledge in this video but I am assuming that you've worked with python before you've maybe done a project or two in the past and you have some idea about basic synt
ax like for Loops functions classes Etc regardless this is a great project I want to lay the intro anymore let's go ahead and get into it and I'll show you how we can build this aim trainer so we'll dive into building that project in one second but I just want to share with you that I do have a course known as programming expert which is for anyone looking to get better at programming and become a software engineer this course covers all kinds of different content but specifically focuses on pyt
hon go and all of the necessary skills like software engineering tools that you need to land a job you can check that out from the link in the description and if you're interested in blockchain or web3 development I have another course called blockchain expert I'll leave that link down below as well okay so now that I've gone through that let's go into a new file here and let's start working on this aim trainer but actually I'll just quickly demo it so we can talk about kind of what we need to d
o here so you can see that what I'm doing is tracking some different stats so I've set a number of lives that's essentially how many targets you have to miss before the aim trainer is going to finish and tell you what your stats are I've set it really high for the demo but typically we'd have this at something like three or five we then have stats that are keeping track of the number of hits you have the number of targets you press per second and the total time elapsed obviously we have targets
that are appearing randomly on the screen you can press on them and you'll see that they are shrinking and kind of growing as they appear so they grow up to a certain size pause for a second and then shrink back down that's exactly what we're attempting to do okay so now that we've looked at that quick demo we have some kind of idea of what we need to build here let's go into a new python file which I'm in right now and let's start working on this project now for this project I'm going to use a
module called Pi game now Pi game is something we need to install so what we're going to do here is go to our command line or terminal and type pip install and then Pi game now I already have this installed so I'm not going to run that command for you you may need to do pip 3 install Pi game if you're on Mac or Linux you can also try python hyphen M pip install Pi game or Python 3 hyphen M pip install Pi game if none of those work I'll leave two videos on the screen that show you how to install
piking okay so now that we have Pi game installed we can start working it so we're just going to do a few Imports here Define our PI game window don't worry if you've never used Pi game before it's super straightforward and it's actually a really great thing to build some basic user interfaces in Python so I'll walk you through all the steps let's start by importing pygame we are then going to type pygame dot init which is going to initialize Pi game and initialize the fonts and some other thing
s that we need I'm then going to go up here and before Pi game I'm going to import math because we're going to use that I'm going to import random we're going to need that as well and then I'm going to import time I think that's all we need now that we've done that we're going to define the width and the height of our window we're going to create a window object and then we're going to create what's known as the main Loop for our pygame project so we're going to say width comma height is equal t
o and then I'm going to go with 800 and 600. now keep in mind if you're on a smaller display you need you may need to make this a little bit smaller I'm on quite a large display so you'll see that this is kind of a good size but for some of you you may want to do 600 by 400 this is the number of pixels you're going to be using for the window okay so now that we have the width and the height I'm going to define a window object so I'm going to say win is equal to Pi game dot display dot set unders
core mode and inside a set of parentheses I'm going to pass my width and my height now what this will do is initialize a pi game window and display that on the screen so this is going to pop up kind of a black window that will have an 800 width and a 600 height because we've passed that inside of the parentheses once we have this window we can then draw things onto it which we'll do in a minute so next we're going to say pygame dot display dot set underscore caption and the caption for this is s
imply going to be aim trainer now the caption is just the name of the window you don't need to set this but I like to do this for my projects okay so now that we've done that let's create what's known as the main Loop of our program which is essentially an infinite Loop that will check for different events so pressing on the screen quitting the window if a Target appeared or disappeared that's what we're going to be doing inside of the main Loop so we're going to say Define main which is our mai
n function now inside of here we're essentially going to create a while loop that will run forever until we quit the window so we're going to say well run and we'll Define a variable here called run we'll make that equal to true and inside of the while loop what we're going to do is Loop through all the different Pi game events and see if the user quit the window now you'd think that it's already built in that when you press the x button it's going to close the window that's actually not the cas
e here in pi game what happens when you press the x button is an event will be triggered and we then need to respond to that event and close the window for the user so to do that we're going to say four events in pygame.events.get now what this is going to do is Loop through all of the different events that are occurring so that will be kind of equal to the event here and then we will check if this event is equal to the quit event if it is then quits we'll say if event DOT type is equal to pygam
e dot quit like that then we're simply going to say run is equal to false and we're going to break out of this for Loop here okay so now what we have is a while loop that's going to run while this variable is true we then Loop through all of the different events that are occurring as we go through this while loop so at pretty much every millisecond or however fast this while loop is running we're looking at all the events if one of the events is quit then we're going to break the loop and get ou
tside of it so now for outside of the loop we're going to save highgame.quit and that's going to quit the pi game window and close it and then we're going to come down here and we're going to say if underscore underscore name is equal to underscore unscore Main then run the main function now what this will do is just ensure that we're only running the main function if we're executing this file directly don't worry too much about this if you haven't seen it before just a nice line to add in to ma
ke sure if we import one of these functions from another file it doesn't cause this game to run so now let's quickly test this out you can see when I run this a window appears that says aim trainer which is 800 by 600 and then if I click on X it closes the window and all is good perfect that's all we needed for right now okay so now that we have our main Loop implemented what we need to do is start putting some Targets on the screen viewing those targets then seeing them kind of shrink and grow
so what we're going to do is create a class which is going to represent our targets so we're going to say class Target like that and inside of the class we're going to define a few variables that we need for the Target remember it's kind of growing and shrinking so we're going to set a maximum size for the Target which is essentially the size at which we want to start shrinking so we'll grow up to the maximum size as soon as we hit that we'll start shrinking so the max size will be 30. you can c
hange all these values by the way I'm then going to say the growth rate is equal to 0.2 now this is how many pixels we want to grow the target per frame now we'll talk about frames in one second but both of these values you can adjust and as you adjust it will make the aim trainer more difficult or easier depending on the direction you go in then I'm going to set the color for my target equal to Red you'll see why we want that in a second just so that we can kind of change the color Target quite
easily okay next we are going to Define an initialization this is what's known as The Constructor for our Target inside of here I'm going to take in self X and Y self will refer to the Target itself that we are calling this Constructor on and X and Y will be the position where we want to place this Target on the screen so we'll kind of randomly generate those positions and then we'll store them inside of the target object so we'll say self.x is equal to X and self.y is equal to Y we're then goi
ng to Define two variables here one is self.size is equal to zero now the size will be the radius of the target it's going to start at zero and then we're going to increase it by this growth factor until it hits the maximum size once it hits the maximum size we'll start shrinking it down so then it gets to zero and then once that zero will make the target disappear from the screen we're also going to have an attribute here called grow we're going to start this equal to true but then we need to m
ake this false as soon as we hit the maximum size so we start shrinking rather than growing great so now let's write a method that we can call to update the target size which we'll need to do so we're going to say Define update and we're going to take in self now what we'll do in here is we'll essentially check if we should be growing or shrinking and then adjust the target based on that so we know that we need to start shrinking the target as soon as the current size of the target is going to b
e greater than the maximum size so I say if the self.size Plus the self dot growth rate is going to be greater than or equal to the self.maximum size then I need to say self.grow is equal to false so as soon as I add this growth rate and it causes the size of my target to be greater than or equal to the maximum size I need to set grow equal to false okay then I'm going to come down here I'm going to say if self.grow so if we are growing then self.size plus equals the self.growth rate otherwise i
f we're not growing we must be shrinking so we'll say self.size minus equals the self dot growth rate okay so now we have a function that will handle sizing our Target and making it larger or smaller based on if we're growing or not okay now we need a function that actually draws the target onto the screen so we're going to say Define draw we're going to take in self and we're going to take in a window object that we want to draw this target onto Now The Way We Draw Something in pi game is diffe
rent depending on the thing that we're drawing but in our case we want to draw a circle so we're going to say Pi game dot draw dot Circle okay now what we pass here when we're drawing a circle is the window we want to draw the circle onto the color of the circle and then the center position of the circle as well as the radius okay having all of those different pieces of information allows Pi game to put this on the surface so in pi game we're constantly dealing with surfaces this window here is
going to be our window object that we've created and we're saying yes we want to draw this circle onto the window where do we want to draw it what color is it how big should it be that's what it's asking us so we're going to put win because that's where we want to draw it we're going to put self.color because that's the color we want the target to be and then we're going to pass a tuple that contains the X Y position of the center of the target so we're going to say self.x self.y that's the cent
er of the target then we're going to pass the radius or the size of our Target so we're going to say self.size and when we pass self.size whatever the current size is well that's the size we'll be drawing for the radius of the target meaning as the size increases we'll be drawing a larger and larger circles now for now this is just go going to draw a red circle however if we want to draw kind of that Target style Circle where we have you know red white red white Etc we actually need to draw four
circles the first one will be the largest Circle then we'll draw smaller and smaller circles that will overlap each other's story and cause this kind of ring pattern to appear so what I'm going to do is draw four circles here so I'll just kind of copy this down four times and what we'll do is we'll adjust the size so we'll say self.size times 0.8 now it's important that we do this by some kind of multiplication Factor so that as the size of our Target changes so does the size of all the Rings i
nside side of the target sorry I can't just say draw this size 20 draw the next one size 30. I need to do it dynamically based on what the current size of our Target is because it's going to grow and it's going to shrink right okay so we do times 0.8 then we're going to do times 0.6 and then times 0.4 and if you want the Rings to be spaced out differently then you can adjust these values but I think this will give us a nice ring shape for our Target now what we need to do is just adjust the size
or set up the size the color of our targets so we have self.color here and in fact let's go and say we have a second color which is equal to White okay so we'll use the color variable for the red rings and the second color variable for the white rings so now I'm going to go here and change each uh kind of second target drawing here to be the second color so we have color second color color Second Color you can see that we're constantly going smaller in size so what happens is we draw this very
large Circle then on top of that Circle we draw one that is a little bit smaller then on top of that a little bit smaller on top of that a little bit smaller and what that does is overlap these different circles causing us to have this kind of ring shape in pi game the order in which you draw things is important when you draw something after something else it's going to go on top of that object or overlap it so that's why we're able to accomplish this here with these four draws okay that's fanta
stic so now we have our Target we've created that and what we need to do is start making these targets appear on the screen so how are we going to do that well we need to go into main here and we need to create a variable called targets now this is where we're going to store all of the different targets then what we'll do is we'll Loop through all the targets we have we'll update their size and we'll draw them on the screen but every X seconds we need to kind of place a new Target onto the scree
n so to do this we're going to create what's known as a custom event now this event will essentially be triggered every 500 milliseconds or 600 milliseconds or whatever we want we can then check for that event when that event occurs we can then make a new Target at a random position and add it inside of this array so let me show you how that works we're going to go to the top of our program and we're going to Define two variables here the first variable we're going to Define is the targets under
score increment now this is going to be equal to 400 milliseconds now you can change this if you make it uh slower or sorry if you make it less so like 300 200 it's going to be much harder if you make it larger it's going to be much easier because the targets appear later so I've gone with 400 milliseconds you can adjust that as you want next I'm going to say Target underscore event is equal to pygame dot user event and then I'm just going to Define another variable here which is the target unde
rscore padding which is essentially how many pixels I want this to be off the edge of the screen we'll just put this here for now and then we'll kind of look at that in a second but I'll set that to be 30. okay so we have a custom event which is the target event which is a pygame.user event we then have the increment which is the number of milliseconds so we want to delay until we create another Target now that we've defined those variables we're going to start using them down here sorry I didn'
t mean to kind of scroll through that crazy so what I'm going to do is essentially create a timer so I'm going to say pygame dot time dot set underscore timer and the timer that I want to trigger is the target event then I'm going to put the target increment now what this says is trigger this event every Target increment milliseconds so we're going to trigger the target event every 400 milliseconds that's what we're doing okay so now that we have that timer what we'll do is we'll go inside of ou
r event Loop here and we'll listen for that event and when that event occurs we'll make the target appear on the screen so I'm going to say if event.type is equal to and now we're going to use our custom event which is the target event so as soon as I see this occurring I want to create a new Target to create a new Target I need to randomly generate an X and Y position for it then create the Target and add that to my target array or my target list so I'm going to say x is equal to random dot ran
dom integer and we're going to generate a random integer for X in the range of our Target padding and our width minus our Target padding now the reason I'm doing this is to ensure that my targets don't appear off the screen since we're drawing from the center position of our Target that means the radius of our Target will go to the right and it will go to the left so if I had a position like 10 10 so I'm drawing at X position 10 x position y but my target has a radius of 30 that means my target
will really appear from kind of negative 20 here all the way to 30 right uh or sorry not 30 all the way to 40 because the radius is 30 so it's going to take up 30 pixels on each side of the X and Y coordinate hopefully that makes sense but if this is the center position then the radius kind of expands outwards so I need to make sure my Center position is such that when the radius is applied to my target it doesn't appear off the screen so that's why I have this target padding here I'm generating
a random integer between the target padding and between the width minus the target padding to ensure the center position causes the target to not be off the screen now I'm going to do a similar thing for my y I'm going to say Y is equal to the random dot Rand int and this will be again the target padding and then the height minus the target pad okay I'm then going to say Target is equal to Target and I'm going to pass my X and Y so I'm initializing a new instance of the target class then I'm go
ing to say targets.append Target and what this will do is now push this new Target object into this list so then we can use it and loop through it great so now every X seconds every 400 milliseconds whatever we Define in the variable we will create a new Target what we need to do next is update all of our targets and draw them on the screen now what I like to do is put all of my drawing inside of a separate function so I'm going to write a new function here called Draw I'm going to take in a win
dow object and I'm going to take in my targets now in pi game remember I told you that the order in which we draw things is important if we draw something over top of something else what that's going to do is overlap it so essentially what we need to do inside of this draw function is we need to clear the screen every single time we draw so we're going to wipe the entire screen clear by drawing swing over top of it then we're going to draw all of our objects and then we're going to update the di
splay and we're going to do this every single frame so every frame we wipe what was on the screen previously then we draw onto it what we want to see next so it's kind of frame by frame rendering that's what we're doing here that's not how it works in every single system anyways what we do is we type win dot blit uh sorry not Blitz dot fill and then we can fill the window with a specific color now you can just write in a string the color you want so if you want it to be yellow you can write yell
ow if you want it blue write blue but if you want a more specific color coding like what we have then you can use an RGB value so what I'm going to do is go to the top of my program and I'm going to say my BG underscore color is equal to and then I'm going to specify the red green blue value that I want to draw so in this case it's going to be 0 25 and 40. now if you're not familiar with how RGB works this is essentially three values in the range of 0 to 255. now all three of these values tell y
ou the number of red green and blues the first value 0 means I want to have no red 25 means I want 25 green and then 40 means I want 40 blue and the maximum is 255. so as you kind of change these values you get different colors that's kind of how RGB Works in Python you define three values in a tuple and then you can use them inside of a function like this so I can pass my background color and now I'm going to fill the entire window with the background color next I'm going to Loop through all of
my targets so I'm going to say four Target in targets then what I'm going to do is say Target dot draw I'm going to pass this window object so if we go and we look at the draw function here you can see that it accepts the window so we just pass the window here Loop through all of the targets draw them all on the screen lastly we type highgame dot display dot update now the display is only going to draw all of the things that we've kind of rendered up until this point when the update function is
called so once we've drawn all of the targets and we've filled the screen in then we will call update and we'll draw them onto the screen perfect that's the draw function so now we need to make sure we call the draw function so I'm going to go inside of my while loop and I'm going to call draw and then I need to pass my window and my targets so I'm going to pass win and targets like that now we're almost done at least with this step what we need to do next is we need to make sure that we update
all of our targets before we draw them so I'm going to say for Target in targets and I'll simply call Target dot update okay so now what this will do is update all the targets by updating them we're going to change their size right we're going to make them grow or Shrink depending on where they currently are in the animation now there's a few more things we need to do but for now let's run this and see what happens okay so actually I just need to fix something there let's run and you see that t
he targets kind of appear very quickly on the screen now the reason they're going so quickly here is we haven't set what's known as the frame rate for our window so let's fix that then you should see that things get a little bit better okay so how do we fix the frame rate well inside of this while loop here essentially what's going to happen right now is all of this stuff is just going to run as quickly as our computer can execute this while loop because it's kind of an infinite Loop right but w
hat we can do is regulate the speed at which this runs by introducing a frame rate so to introduce a frame rate we're going to create a clock object we're going to say clock is equal to Pi game dot time dot clock we're then going to go inside of here and we're going to say clock.tick and we'll just put a 60 inside of here now 60 means I want you to run this while loop at 60 frames per second meaning that no matter what computer we're on as long as it can run minimum 60 frames per second then we'
re going to run at 60 frames here so this tick just regulates the speed at which this while loop runs which means this code should run at the same speed on your computer as it does on mine if we didn't have this we're running based on the processor speed which can vary drastically even just based on what you're doing on the computer okay so let's go ahead and run this now and we should see that now our targets are kind of appearing a little bit better right so they're growing they're shrinking y
es some of them are overlapping that's fine we haven't introduced Logic for that and they're appearing on the screen now what you'll notice is if we let this code run for a while it will start to get slower and slower now the reason it's going to get slower and slower is because we're not disposing of our targets once we put them or sorry once we shrink them down to a zero size right now what happens is this targets list just keeps getting larger and larger and larger and larger every time this
event happens what we actually need to do now is we need to make sure we remove these targets as soon as they have a zero size so we start growing them and then as soon as they shrink all the way down to zero we'll want to get rid of them so our computer doesn't have to handle them anymore so how do we do that well the way we do that is the following we're going to say if the target dot size is less than or equal to zero then we want to remove this target from the targets list so we're going to
say targets dot remove and then Target now that's just going to get rid of it and take it out of this list meaning the next time we run this code we're not going to be iterating over it which means we won't kind of be doing all of these unnecessary operations on a Target that's currently invisible hopefully that makes a bit of sense why we're doing that but we just need to remove it as soon as it has a zero size now the reason we put this if statement here and not before the update is because we
want to update it first which means if it currently had a size of zero because it starts out on zero size and it's growing then what will happen is it will get a size of 0.2 or 0.4 whatever the size ends up being meaning we don't remove it if we just added it inside of this array if I had put this if statement before then we would never see a Target appearing on the screen because as soon as it was added it would have a zero size and then we would remove it so since we're updating first that me
ans if we just added the target it will be growing so it will have a larger size than zero so we won't we won't remove its story until its size shrinks back down to zero after it has already been displayed okay so let's run this now and you'll see that the code works the exact same now what happens though is as soon as the target reaches zero we remove it and we don't get any errors okay there we go so now our targets are appearing on the screen the next thing we should probably do is make it so
we can press on the targets so what we need to do is essentially get our Mouse position whenever we click down see if that's colliding with the Target and if it is and we need to remove that Target and then increment some kind of variable indicating that we pressed on the target so how do we do that well the first thing that we're going to do here is just to find some variables related to kind of our analytics as we play this game so we're going to have a variable called Target pressed which is
equal to zero we're then going to have the number of clicks that we've made in total which will be zero we then want to track our time so we're going to say the start time is equal to time dot time you can find the time imported all the way up here okay so the reason I'm doing this I just want to say okay when did we start running this code and then what I can do is track how much time has elapsed since we started and that will give us the total duration of the round that we're currently in now
I also want to have misses now Mrs essentially means that we missed a Target so it popped up on the screen and then it disappeared as soon as we have a certain number of Misses then we're going to end the game so that's kind of what we're tracking here and I think those are the only variables we need right now okay so now we have those let's go here and where we have if Target size is less than or equal to zero what we need to do is increment our misses by one so Mrs plus equals one because as
soon as the target is removed because the size is equal to zero that means we didn't press on the Target and it appeared and disappeared and we didn't see it so we need to increment misses whereas if we collide with the target when we're pressing our Mouse on it then that means it was a successful click okay so now what I'm going to do is I'm going to write a variable called click I'm going to make this equal to false what I'll now do is I'll look inside of my events I'll see if the user pressed
the mouse down if they did then I want to set click equal to true so then we check if the current Mouse position has collided with the target so I'm going to say if event.type is equal to and this is going to be pygame dot event dot actually no it's gonna be pygame.mouse button down sorry that's the event there then we're going to say click equals true and we're going to say clicks plus equals one because we've pressed so we're going to increment the number of clicks that we have in total okay
great so we've Now set click equal to True clicks plus equals one now we need to handle colliding with our targets now the way that I like to do this is just by writing a simple method on each of my targets or on my target class so I'm going to go here and say Define Collide and we're going to take in an X and Y position which will represent the mouse position that we want to see if we've collided with this circle all right so performing Collision for our circle is fairly straightforward because
we're just looking at the center coordinate of our Mouse position versus the center coordinate of our Circle position so what we can do is we can simply take the straight line distance from the two points and see if that distance is less than or equal to the radius of our Circle if that's the case then we've pressed on the circle I don't really know how to explain it much more than that but essentially if you have some kind of distance between your mouse position and the circle and it's less th
an or equal to the radius then you're within the circle if it's greater than the radius then you are outside of the circle there's other ways to perform this Collision but this is probably the easiest so how do we get this well what we need to do is use the distance to a point formula and that is going to be the following it's going to be self.x minus X and then all of this is going to be raised to the exponent two we're then going to add that to the self.y minus the Y and we're going to raise t
hat to the exponent too and we're going to take the square root of all of this we're going to say math Dot sqrt of all of that that's going to be the distance between the two points I'm going to double check this because it's been a long time since I've written this formula and then we are simply going to return if the distance is less than or equal to the size and this is going to be the self.size okay now the only thing you need to kind of follow when you're writing this formula is that whatev
er order you put the coordinates in you need to maintain that so in this case I'm using the coordinates of my circle first and then the coordinates of my mouse since I'm raising this to the exponent 2 it essentially gives me the absolute value of this first component then the same thing will happen here all I'm trying to say is I can't Swap this and do like y minus self.y if I wanted to do that I would have to swap the other coordinate as well and say x minus self.x either order works you just h
ave to maintain the same order when you do this we'll go in this order and you'll see this is fine okay so now we have this Collide function now that we have that we can start using it so notice we've kind of tracked if we clicked here so if we did click then we want to check if we're colliding with our different targets so I'm going to say if click and then we'll say Target dot Collide and then we need to get our Mouse's position so up here I'm going to say the mouse underscore position is equa
l to Pi game dot mouse dot get underscore pause and then what I'll do is pass that position so I'm actually going to pass an asterisk and then the mouse pause now when you use an asterisk inside of a function argument what this will do is break down the Tuple into its individual component so that might be confusing but Mouse position gives us the x y coordinate of the mouse in pi game so since this is a tuple this is considered one object right like pause is equal to X1 but you can see that insi
de of our function right we're taking X and Y we're not taking an a tuple that contains X and Y so what we need to do is break this Tuple into its individual Elements by using the asterisk so when I do this it essentially takes the first element passes that as one positional argument takes the second element passes that as another positional argument so it's equal or equivalent to me passing Mouse position zero and mouse position one it's just a shorthand for doing that okay so we're just going
to use the asterisks this is known as the Splat operator okay so if we have clicked and we are colliding with this target then make it disappear so to make it disappear we'll simply remove the Target and we will increment the targets pressed by one okay so Target pressed plus equals one there you go that's all we need to do for handling our Collision so let's run this now and let's see if this works and we get an error what is the error here it says some issue let me just run this again with the
terminal open for some reason my terminal keeps cutting off the errors uh it says int object has no attribute self ah y dot self okay so I can see why we got that error so let's go back and fix this I'm sure you guys probably caught that yourself it's not y.self it's self dot y okay so now let's run this and see what happens when we press the targets and notice that they disappear meanwhile if I click outside the target it doesn't disappear because well we weren't within the bounds so now we've
already kind of got the core logic working here for pressing the targets what we need to do next is really just display some of our statistics and then end the game and we'll be finished with this tutorial all right so what we're going to do now is we're going to draw kind of a top bar that will contain some of the statistics uh for our app or for our round or game or whatever you want to call it so the way we'll do that is we'll write a new function here called Define draw top bar now to draw
this top bar we're going to take in the window and we need to take in some stats right some information that we want to display so what we'll take is the elapsed underscore time we'll take the targets pressed and we'll take the number of Misses that you currently have because what we'll do is we'll kind of track the number of lives remaining until we need to end the game right so that's the next thing we need to do as well if you've missed more than three targets well we need to end the game or
however many lives we Define so let's actually Define that up here let's go ahead and say lives is equal to and let's set our lives equal to three we can then just quickly write some code down here we can say if the misses is greater than or equal to the lives then what we will do is we'll just say pass but really this is where we need to end the game okay so if the number of Misses we have the number of targets we have impressed is greater than or equal to the number of lives we have then we en
d the game we also could just subtract from the lives but I think this is fine as well okay then while we're at it we'll just call draw top bar and we'll pass in the information we need so we need the window we need the elapsed time well to get the elapsed time we'll create a variable so we'll say lapse time is equal to time.time minus start time so remember I was telling you if we have access to the start time then we can get the amount of time that's been elapsed by taking the current time and
subtracting that from the start time that's all it's doing gives us current time minus the time we started this will give us the number of seconds that have elapsed so now we'll pass the elapsed time variable we then will pass the targets pressed and then we'll pass the number of Misses that we had uh why is that kind of highlighting here all right not sure why that's giving us that weird error but regardless let's go here okay so now inside of this function we want to draw this top bar now thi
s top bar is really just going to be a rectangle that has some text on it so let's draw a rectangle and then we'll draw the rest of the stuff we need so let's say pygame dot draw dot rect now this is how you draw a rectangle use rect not rectangle then we're going to draw this on the window we need to choose the color we want so I'll just go with gray and then we need to pass a rectangle object now a rectangle object is going to be the X and Y of the top left hand corner where we want to draw th
e rectangle and then the width and the height for that corresponding rectangle so we're going to draw this at 0 0 because we wanted to take up the entire screen 0 0 by the way is going to be the top left hand corner of our PI game window okay so we always start at 0 0 from the top left then we need to pass the width and the height well the width of our rectangle is going to be the width of the window so I'll just pass width and then the height is going to be some defined height that we're actual
ly going to put in a variable so we'll go here and we'll say top bar height is equal to and we'll just go with a height of 50. we can use whatever height we want but I think 50 is fine then I'm just going to pass my top bar height here and draw it there okay so now this will draw a rectangle onto the screen next what we need to do is draw a bunch of different kind of text objects on the screen that represent our different statistics so this is where it gets actually a little complicated but when
ever we want to draw text in pi game we need to create a font object and then render an instance of that font so what we'll do is go to the top of our program and we'll set our label underscore font is equal to pygame.font.sys font and then we need to pass a font so in this case I'll go with Comic Sans you can pick any font you want that's supported by pi game but I just recommend going with this and then you choose the font size in this case I want to go with 24. now you can see there's some ot
her kind of things you can do here too like you can pass if it is bold italic Etc in our case we'll just go with the standard Comic Sans of size 24. okay so now we need to render this font so the processes create the font object then you render an instance of the font then you draw that onto the screen so the first thing we'll draw is our time so we're going to say the time underscore label is equal to and this will be our label font dot render now what you do in the render is you pass a string
of the text you want to render you pass one for anti-aliasing don't worry about that just pass one and then for the color you pass the color that you want it to be in this case we can draw it in Black now for the text that we want to draw here essentially we want to take our time which is in seconds and we want to convert it into minutes seconds and then milliseconds so the way I'm going to do that is I'm just going to write a function called format underscore time now format time is going to ta
ke in the number of seconds that we have and it's going to return to us a string that contains the number of milliseconds seconds and minutes in a nicely formatted kind of thing okay so we're going to say Milli four milliseconds is equal to math.floor which will round something down inside of here we're going to take the int of our seconds multiplied by 1000 modulus 1000 divided by 100. now what this will do is just give us the number of milliseconds um that we want to be displaying okay I know
this seems a little bit weird not really going to explain it too much you can try to kind of break it down yourself it just gives us the number of milliseconds from this seconds which will contain a bunch of decimal places then we're going to have seconds now seconds is going to be equal to the ins of the rounded seconds mod 60 and we're going to round this to the first decimal place okay what we're doing is we're taking the number of seconds we're modding it by 60 that'll give us the number of
seconds that we have and then we will handle the number of minutes here by doing an integer division so I'm going to say minutes is equal to int and then this is seconds integer divided by 60. we need the mod here to make sure we don't get something like 70 seconds or 90 seconds because that's going to be handled by our minutes okay so now actually sorry that shouldn't be seconds this should be sex like this because we need to use the same value all right now that we have that we're going to ret
urn a string I'm going to return an F string which is new in Python 3. I believe seven and above or maybe 3.6 and above anyways inside of the F string you can use these curly braces to embed variables so I'm going to say minutes colon 0 to D now the 0 to d means I want to pad this number such that it always has two digits and if it doesn't have two digits start it with a zero so this will format it such that you get like 0 1 0 2 0 3 or 0 0 if we have no minutes which is kind of what we want then
we're going to do seconds we're going to do the same thing 0 to D and this is also why I need to convert these into ins because this only works when you have an INT type as opposed to a float type okay so we have our zero two D zero two D for the formatting and then we will just put our milliseconds here like that which I actually already formatted for us and we can put that with a DOT we can do a DOT or we do a colon up to you I'm going to go with a done okay so format time will give us a nice
ly formatted time string so now inside of our label font we're going to put an F string we're going to put time colon then we're going to call format time with the elapsed time so that will give us the string that we want to display inside of here after we have time okay now that we have this time label we want to display this on the screen to do that I'm going to say wind.lit blit is how you display another surface in this case I want to display the time label surface which we've just created I
'm going to put what I want to display which is time label then I'm going to put the x y coordinate of the top left hand corner of the object I want to display so I'm going to go with 5 5 which means the top left hand corner of this time label will be at 5 5 and we'll draw downwards and to the right from there to draw our text okay so I think that's all we need now uh what I'm just going to do is I'm going to take this pygame.display.update out of my draw function and I'm going to put that insid
e of here all right so I'm going to kind of put that down here and what's the issue here it says targets pressed is not defined did I not have that to find Targets pressed okay and then let's go here to The Click targets pressed plus equals one okay so I just need to fix that variable name apologize but that I have my display now outside of these two functions so we're displaying afterwards and now if we run the code we should see we get our time displaying up here nicely so notice since I drew
that five five it's five pixels down five from the left that's kind of what we're seeing okay so now that we have the time we want to display some other information like the number of Misses number of lives Etc that we have remaining so let's go here and do the rest so the next one I want to do is the speed now your speed is simply equal to the number of targets you've pressed based on the current time so like the targets per second so the way we do that is we take the targets that you've presse
d and we divide that by the elapsed time so I'm going to use my round function I'm going to take targets pressed and divide that by elapsed time and I'm going to round this to the first decimal place so we get something like 2.1 or 1.1 or something along those lines now that we have the speed we'll create our speed label right which can be equal to the label font dot render and then we can go here with an F string we could say speed colon speed and then I'll put a t slash S standing for targets
per second I need to put my one for the anti-alising to be true and then black and then we can draw this on the screen so we'll take this paste this down here change this to our speed label and then we're just going to set the x coordinate we want to draw this out so I want the y coordinate to be the same but the X I need to space this out for my time label so I'll just set this to be 200 so it goes a bit further to the right now let's do the rest of our labels so let's copy this so next we'll h
ave the hits label this is the number of targets that we've currently pressed so we'll say hits and this will be targets pressed get rid of the T slash S and then we'll blit that one so copy this and then draw the hits label rather than 200 this time we can go with something like 450 and then lastly we need to display the number of lives we have remaining so we'll say lives label is equal to and then I really should just copied this so let's copy that there and we'll say lives is equal to the to
tal number of lives minus the number of Misses that we currently have okay then we'll draw this one with the lives label and we'll draw this at 650. okay so I think that's going to be good for the top bar let's run this now and you should see that as we press targets we start updating our different stats however you'll notice that some of our targets are appearing at the top bar I'm going to show you how we fix that in one second and you can see our lives are subtracting kind of as we miss the t
argets okay so why are they appearing in the top bar well the reason they're appearing in the top bar is because we haven't padded where we want to render the targets based on the position of the top bar so what we'll need to do now is go to where we have the randomly generated positions and for our x coordinate we'll just say our Target padding plus the top bar height just to make sure the minimum y coordinate is always going to be beneath that top bar so now that we've done that if we run this
we should see that none of our targets will be rendered in that top bar anymore they can be close to it but they're always going to be bordering it they'll never be kind of beneath it meaning we're not going to miss them now obviously I'm performing quite poorly here because well I'm under pressure and I'm on the video I'm sure you guys will be doing better than me okay almost done here last thing we need to do is simply end the game once the user has no more lives so how do we do that well to
end the game we are simply going to call a function that will display the user's stats so very similar to drawing the top bar we're going to draw a bunch of stats onto the screen so I'm going to write another function called end screen now this is the last function we need and inside of end screen we're going to take when the elapsed time the targets underscore pressed and the number of clicks that you had so that we can calculate what the accuracy is now what we'll do in here is we'll essential
ly kind of pause the execution of our code and we will render something onto the screen that displays the stats and then as soon as the user presses a button we'll just end the game okay so what I'm going to do is say when sorry win dot blit and then we're going to blit the background color so that we clear whatever was currently on the screen because what I want to do is just have some text that appears in the middle of the screen so what we'll Now do is we'll copy kind of all of the text we ha
d from here and we'll paste this in but now I only want to display a few things so I don't need to display the lives anymore I can display the hits but I also want to display the accuracy okay so ack you receive I don't know if I spelled that correctly and then I'm going to define the accuracy here so for the accuracy this is simply going to be equal to the number of targets we've pressed divided by the number of clicks that we had so I'm going to say round the targets pressed divided by the cli
cks multiplied by 100 we'll round that uh actually do we even need to round this yeah we'll round that to one decimal place okay so this is going to be the accuracy that we have so now we'll just change this text to be accuracy and then we'll display the accuracy and then percent now what I'll do is I'll take these different labels and I'll just render them in a slightly different position on the screen so that it is in the center right because here we're displaying them on the top bar now we wa
nt to display them in the middle of the screen so to display them in the middle screen I'll actually copy this rather than the lives label now have the accuracy label and we just need to change these here so we're rendering in the middle of the screen now the way we render in the middle of the screen when we're using a label is we need to take the middle coordinate of the screen okay so it's a bit difficult to explain this visually or without having a visual so let's actually go into paint quick
ly here let's imagine we have a screen okay if we want to display something in the middle of the screen like this the natural thing to do would be okay well let me just find kind of this middle X position and then start drawing here well that works if you have something like a circle where you're drawing in the middle of the circle but in our case we're drawing from the top left hand corner which means if we draw something from the middle coordinate we end up drawing it to the right and down so
what we actually need to do is draw from the middle so let's say this is X over 2 minus the width of the object we're drawing minus 2. or sorry now minus 2 over 2. so if you take the width of the object over 2 which is this right here and you now move back by that to here then you start drawing the object in the middle of the screen hopefully that makes a bit of sense what I just explained but we're going to take the kind of width of the entire screen divide that by two then subtract that by the
width of the object that we're drawing over to that will then give us the X position where we need to draw the top left hand corner such that the object will be in the middle so let's get rid of that and let's make a function that calculates that for us so we'll say Define get middle this is going to take in a surface okay and what this is going to return is that middle position so we're going to say width over 2 minus the surface.get underscore width over 2. so now we can use this function on
our different labels to determine what x coordinate we should draw them at so we're going to say for the time label well we want to draw this at get middle of the time label then for the speed this is going to be get middle of the speed label and then for the hits this is going to be get middle of the hits label and then for the accuracy get middle of the accuracy label okay so that should be good and that should draw everything on the screen however what I want to do is have it so it kind of pa
uses until the user presses something so what I'm going to do here is I'm going to manually update the screen so pygame.display.update I'm then going to run a while loop in here that will wait for the user to press something once they press something it will then close the screen so I'm going to say run equals true I'm going to say while run I'm going to say four events in highgame Dot event dot get I'm going to say if event DOT type is equal to Pi game Dot and all capitals quit then I am simply
going to say quit like that otherwise I'm going to say if event DOT type is equal to Pi game and this will be dots and we'll go with key down so this just means if we press any key down then I'm going to say run equals false and I will break out of this Loop now what this quit function will do is just completely quit the Python program for us and then what this will do is kind of just exit the loop which will then cause us to get out now what I could actually do is just put quit here as well or
I can make this even a little bit more elegant and I could copy this all and say or it equals this and now we just have that in one line so we really just have this one while loop this is kind of running forever and just waiting for us to press any key or to click quit as soon as we do that we just close the window okay so now all we need to do is call this end screen function as soon as we kind of lose the game so we'll go here and rather than pass we'll call end screen and we'll pass this the
information we need so we need the window what else do we need the elapsed time the targets pressed so targets pressed and the number of clicks okay so now we should be fully finished our program let's run this and make sure it works and let's just see what happens now if we kind of click a few of the things here and then we kind of let some of our Lives run out okay two one and we got an error let's see what that error is uh was it an error or did it just quit immediately let's see here give t
his a second okay argument one must be Pi game surface not Tuple uh window blit ah okay start with that guys let's go fix this now go in end screen and rather than wind.blit this is going to be win Dot fill so we need to fill with the background color not blit with it that's my bad let's give this another shot here click a few targets okay and now let's lose so two lives one live and it shows our information however it's showing it all on one single line that's because we didn't change the Y pos
itions so let's make these like a hundred 200 300 and 400 and while we're at it let's change the color here to be white because black is a little bit of an eyesore there on the blue background so let's change these all to be white and white and let's run this and now let's just run a few targets or click a few targets and kind of let this lose and see if it displays correctly for us all right so there you go we got our time our speed our hits and our accuracy and we have finished this project wi
th that said I'm going to wrap up the video here I hope you guys found this helpful and that this was a cool project uh that you're able to kind of work on you could show to people and that could kind of improve your python knowledge what I will be doing is including all of the code in the link in the description in case you want to download any of it or in case you get lost so feel free to check that out anyways if you enjoyed make sure to leave a like subscribe the channel and I will see you i
n another one thank you

Comments

@TechWithTim

Code in this video: https://github.com/techwithtim/Python-Aim-Trainer

@1hoodpharm

i see tim , i click… simple

@blackestbill7454

amazing, thanks so much!

@cr370

Thanks for what you do. I'd like to get the feel of the jobs offered out there. Can you go through what is requested in a job that you've done, from the beginning, what you have to interface with, to the end. This may be a good series for your channel. Thanks

@paulthomas1052

Great code and useful logic. Thanks.

@python703

Thnx Tim. Good job

@Beardedmane901

Tim content be 🔥🔥🔥🔥

@manosmakris8308

There is an error in this code. If the user doesn't click at all and let its lives go to zero there is a ZeroDivisionError at the end_screen() when we try to calculate the user's accuracy. If someone wants to make the end_screen() more bulletproof try this: def end_screen(win, analytics): win.fill(BG_COLOR) time_label = LABEL_FONT.render(f"Time: {format_time(analytics.elapsed_time)}", 1, "white") speed = round(analytics.targets_pressed/analytics.elapsed_time, 1) speed_label = LABEL_FONT.render(f"Speed: {speed} t/sec", 1, "white") hits_label = LABEL_FONT.render(f"Hits: {analytics.targets_pressed}", 1, "white") # This is the changed part # ------------------------------------------------------------------------------------------------------------------------ # try: accuracy = round(analytics.targets_pressed / analytics.clicks * 100, 1) except ZeroDivisionError as e: accuracy = 0.0 # ------------------------------------------------------------------------------------------------------------------------ # accuracy_label = LABEL_FONT.render(f"Accuracy: {accuracy}%", 1, "white") exit_label = LABEL_FONT.render("Press any key to exit...", 1, "white") win.blit(time_label, (center_label(time_label), 50)) win.blit(speed_label, (center_label(speed_label), 150)) win.blit(hits_label, (center_label(hits_label), 250)) win.blit(accuracy_label, (center_label(accuracy_label), 350)) win.blit(exit_label, (center_label(exit_label), 450)) pygame.display.update() while True: for event in pygame.event.get(): if (event.type == pygame.QUIT or event.type == pygame.KEYDOWN): quit()

@takisbezaitis7741

Great content! I would like to ask you if pygame is still popular or arcade library (or another library) will take its place. Thanks!

@ezzaimran

amazing

@Andrew-Tsegaye

Please please 🙏 Tim, can you add an AI feature or pinch industry grade algorithms to go a little bit deeper?

@averagegamer9513

At 29:13, I don’t see why you couldn’t swap the values inside the squaring operation. At least mathematically, it wouldn’t change anything. Does this have to do with implementation of math in Python, or was it simply to ensure readability/clarity?

@andrewanastasiades6819

Hey Tim! Love the PyGame tutorials. Do you have advice for building web-deployable game applications? Is there a solution that’s optimal for those of us who are stronger backend OOP programmers? Maybe a video creating the same game in a different language/framework would be cool

@teodora382

Can you post the code on github , 'cause I have an error and I can't find out what the problem is ?

@sungod595

Hey Tim, Can you please point me yo the video where you listed all python topics graded as Begineer ,Intermediate etc. I checked the playlist several times but i could not find the List , Your content is awesome. Thanks

@buzzprime93

Can you do some Deep learning projects ? Plz

@Vilnius_Chillinus

I literally made this a few weeks ago haha