Learn Godot by creating Pong

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello in this tutorial we are going to be creating this pong game and since pong is a fairly simple game this isn't going to be too difficult so if this is your first game in godot or your first game in general this tutorial should be quite easy to follow but if you're looking for specific things here are all the steps i will be going through and if you already know some godot it's probably safe to start in this stage and if you happen to like this tutorial check out my python game development course in there you'll be learning much more sophisticated games in python and good dough including a first-person shooter but with all of that covered let's talk about godot so what is godot well godot is a game engine and all that really means is that godot is a program that helps you make video games so when you make your game in godot you see immediately how your game would look like and you can drag and drop elements on the screen and see changes instantly which is a much better way to create video games than just looking at hundreds of lines of code and godot is by no means the only video game engine there are loads of alternatives but the one thing special about godot is that it uses gdscript which is essentially python so if you know python and you want to make video games then godot is the best option by far but to use it we first have to install it which is actually super easy all you have to do is to go to godotengine.org then go to download and then download the version of godot that is appropriate for your operating system in my case that's windows and once you finish the download and unzip the file you should see a folder like this and in there all you have to do is click on godot and then you can see the project manager and in here you could either open an existing project or create a new project in this case it's empty because we haven't created any projects yet but to do that we have to click on new project and then godot was asking us for a name and a project path in my case i'm going to call this file pong i already have a file path that i can paste in right now and godot needs to have an empty folder so this is what i'm going to create here and then we have a few more options for the renderer but this one is not going to matter for this tutorial so i leave it to the default option but that is all we needed so now we can click on create an edit and then we are getting into our game so with that let's talk about how godot works all right now that we have our basic project here's what we can see and there are quite a few elements on the screen right now and i am going to explain them when we get to them but for now don't worry too much about them and before we are getting into anything in godot i would really like to start explaining how godot works on a more fundamental level because that is really going to help us understand later on what we are doing so the door relies on two fundamental concepts to function the first one is called nodes and nodes are the really basic building blocks that actually create your game so for example a node could be a picture a note could be a timer a note could also be a 3d object it could be lots of different things godot has a few hundred of them and they effectively create your game so when you see for example a player character this one would be created out of different notes coming together for example one note would be the picture another note would be the physics calculation another note might be a skeleton animation but what you essentially do in godot is that you put different notes together and move them around on the screen and that creates your game and that's really it you have a couple of notes on the screen and you can influence the attributes and via that you can move them around and that's really all you need to create a game they can do quite a few more things like communicate with each other or have specific code but what you really have to understand is that nodes create your game they are the most fundamental concept in godot and what we are going to work with the most by far but here's one problem by default nodes are not visible which is kind of a problem for a video game so we need a second concept and that second concept is called a scene and scenes in godot serve two purposes number one is that they are canvas for your notes so what you effectively do with your notes is that you put them on a canvas and what the player later on perceives as a game is the scene with all the notes in it so a scene basically displays your game and besides that scenes are also really powerful to organize your game and the reason for that is that we really easily end up with quite a few different notes to organize our game so if you have any even slightly more complex game you will end up with hundreds of different notes which by itself would get really unreally and complex to work with so instead what we can do is have different parts of our game as individual scenes so for example a player could be its own scene and then you put this player scene into the level scene and via that you can work on each of these elements independently and focus on one specific thing and with that your game remains much more modular and much easier to work with and that's basically it if you understand these two concepts you already have a really good starting point for godot so let's actually have a look at how this works in practice so here we are back in our godot editor and what we can see right in the middle of the screen is called the viewport and this viewport shows our open scene right now and what we have at the moment is a 3d scene and if you hold the middle mouse button in here and move the mouse around you can move around in space and if you look at the top of this window you can see a tab right now it says empty and you could save it and give it a name and you could save all the notes you want in there but we don't want a 3d scene right now because our game is 2d and to change between a 2d and the 3d scene you have to look all the way at the top and there you can see 3d and 2d and if you just click on 2d now we can see a 2d workspace and in here you can see this blue rectangle and this is the actual size of our game so if you want to put anything on the screen it has to be inside of this blue rectangle for the player to see it so this is really important so this would be a very basic thing to look at the different scenes in your game and if you want to create a new scene you just click on the plus icon and then you would have a new scene and you can create more it's really up to you but right now i only want to keep this one scene and i want to keep it in 2d so now we have a scene but obviously you can't really see anything on the scene right now and to actually display something we need a node and to get notes you have to look at the top left of the screen and there you can see what's called a scene tree and right now we can choose different nodes we can choose a 2d scene a 3d scene a user interface or another node and if you click on other node you can see a fairly long list let me open up all the different subfolders these are all the different notes that you can have in godot and here you see lots of different things for example you have a skeleton you have a visibility notifier you have a touch screen button you have a polygon 2d you have particles and you have something called a sprite and a sprite is what i'm going to start with for now and this is really just a picture and you might be asking right now there are so many different notes in here how do you find anything and for that you use the search function and in here you can just type sprite and then get the sprite node that you want and it will take you some time to learn about all the different notes but once you get even a little bit of practice this will come very natural to you but okay so with the sprite selected i click on create and now we can see in our same tree that we have a sprite node but in the viewport we can only see this red cross here so how do we add a picture to this node and for that you have to look all the way to the right and there we have the inspector and in the inspector you can set the attributes of this node and right at the top we have what's called a texture attribute and if you hover over it godot gives you a description of this property and it says texture object to draw and what this one effectively does is it takes a file of a picture and it displays it so now what we need is a picture and we do have that if you look in the bottom left there we have a file system and by default every good old project always has one default file that's called eigen.png which is the godot logo and all you really have to do is to drag and drop this icon into the texture slot and you can already see when you drag the file there's this blue line around the file so let me drop it in and now we can see our picture so this one works quite well and if i zoom out a bit we can also move this picture around and place this wherever you want to have it on the screen and let me put it roughly in the middle so this would be one attribute of the sprite node you could also look under transform here you can see position rotation and scale so in here you could for example rotate this image or you could scale it up in different axes which i don't want to do right now but this is really what you have to understand for godot that what you effectively do is you take different notes and you affect their properties and this can be done either by using the inspector or it could be done in code which is what we are going to see in just a little bit but for now let me save this scene and to save a scene you can either press ctrl or command s or go to scene and save scene and if i click on it we can see the folder again we created earlier and in here i want to create a new folder that i call player let me just spell it correctly and now in this folder i want to save the scene also with the name player and gudu's scenes are always saved with the file ending tscn which i guess is short for scene no idea but it doesn't really matter so click on save and now at the top of our scene we can see player and what we can do now is actually run the scene and see how our game would look like and to do that you have to look all the way at the top right and there we can see play we can see play scene and we can see play custom scene what really matters for now is play scene or f6 and let me click on it then go to loads for a bit and here we can see our game or well not really a game but the picture and you can't do anything right now but you can see your game and if we add a bit more code this could be interactive so we could have user input here we could have enemies in here we could have a moving ball in here this works just like a game but for now let me close it so this is really the most fundamental concept in godot that you work with seeds and with notes there's one more concept i do want to cover before we are getting into the actual player character and that is that in the century the notes are always in relation to each other and let me illustrate what this means so with the sprite selected i want to add another node to this that is also going to be a picture and to add another node you have to go either click on this plus icon or press ctrl a and let me add another sprite node so we have another picture and what we can see right now is that we have one sprite at the root of our same tree and another sprite connected to it and what this means is that this bright is a child of this node and they're usually called parent node and child nodes and this has direct implications for your game and let me actually add an image to this second sprite node so again i just drag and drop this icon and then there and we can't see any change right now because the images are on top of each other so let me move this image a bit to the side so we can see our sprite node selected here the one to the bottom right and our parent node the one right in the middle now here's the really important thing if we make any changes to the parent node we are also going to affect the child node however when we move the child node we are not going to affect the parent node and let me demonstrate what this specifically means so if the parent node selected i just move it around and while we're doing that we also move the child node and this would also apply if i go back to transform if i rotated it it would also rotate the child node and if i scaled it same thing whatever we do to the parent node we are also going to do to the child node and this is going to become really important to create our player character in a little bit because we want to have one note that controls the entire player character and all the other notes on the player character always move in the same direction as this note that actually controls the player but i'm getting ahead of myself i think we have made some good progress for now so let's actually start talking about our player character so let's talk about creating a player character which in our case is going to be a paddle that has a couple of functionalities and let me go through what we want our player pedal to be able to do the first and most important thing is that we have to be able to see it so there has to be some kind of picture on our pedal and this one should be straightforward if you can't see your player character you don't really have a player character number two is that we have to be able to control this player character so if you're pressing a button on our keyboard this thing is actually moving so this is another really important thing and besides that our player character also needs to have the ability to react to physics and this is actually a really important part that we want a ball to bounce off this player character later on and this is a physics calculation and this is going to require a specific node in godot that can actually work with physics and in total the dough has four different nodes that can work directly with physics at least in 2d space and these are called kinematic body2d rigidbody2d static body2d and area2d and they all work with physics in slightly different ways and i'm going to go through all of them bar 1 in this tutorial so i will explain every single one of them when we get to it but for now the one we are going to work with is called the kinematic body 2d which is the most powerful kind of physics body in godot and this one is usually the note used for a player character because this one can influence other physics bodies and it can also be influenced itself by other physical bodies and we can move it in code so this one is really powerful and really useful for us and this node is actually going to be the foundation of our player character but there's one problem that's going to sound a bit weird that the kinematic body by itself doesn't have a physical body and this is going to need another note that's called a collision shape and think of it like this a kinematic body 2d by itself is essentially an atom in space it can be influenced by physics but it's so small you can't see it and it's also so small that it can't really collide with anything so we have to give it a physical shape which is an entirely new note but this is basically all we're going to use for our player so let's actually implement all of this so here i'm back in my player scene and what i want to start with is to get rid of some notes so this child sprite note i don't need so i'm going to delete it so deleting it you can either go to right click and delete node or press on delete and then godot is going to double check and i do want to delete it now our sprite node i don't want to get rid of i want to change it which you can also do and all you need to do is to right click on the node and change type and then godot brings us back to the menu and here we can choose a different note and what i want to start with is called a kinematic body 2d and do be aware it has to be a 2d one there's also a kinematic body this one is three-dimensional so make sure to not use that one we want a kinematic body 2d and really easy way to tell between 2d and 3d notes is that 2d notes are always blue 3d notes are always red so that makes it kind of easy but ok we want a kinematic body 2d and if you double click on this you can also rename it so i want to rename mine to player and here already godot was giving us a warning that this note has no shape so it can't collide or interact with other objects consider adding a collision shape to d or collision polygon 2d as a child to define its shape and let's do that so i click on the plus icon again and let me get rid of this and i want to add a collision shape 2d and you could also use a collision polygon we're going to see this one later it works in very similar ways but for now i'm going to use a collision shape 2d so click on create and now we have our player parent node and a collision shape 2d as its child node and here we get another warning that a shape must be provided for the collision shape 2d to function and to give it a shape you have to look back into the inspector and there we can see shape and there we have a drop down menu and here we can select a couple of different shapes and this is going to be the physical body of your player character so you want to select a shape that resembles the player's shape as closely as possible which in my case i think is going to be a rectangle shape 2d which is well a rectangle and once you have clicked on that you can see this bluish icon with a couple of red dots and these red dots you can use to change the scaling of this rectangle and let me zoom out again so what we want is to resemble our player shape which is going to be a paddle somewhat reasonably well which is going to look something like this and this would be the shape that the ball is actually colliding with later on and what i also want to do is that right now our player pedal is in the middle of the screen because i moved the sprite there earlier and i want to change this back to 0 and 0. and for that i went to the inspector to transform and here we have the position you can either type in 0 0 in here or we could just use this icon and then we go back to position 0 and 0. and ok i can close this again and now we have to collision shape for our player but let me save this scene now if i were to run this game now by pressing f6 again or the icon we can't see anything because a collision shape is invisible to the player which makes sense you don't want to see the actual collision box that the player has around itself so we have to give an actual image to our player and the problem for that right now is that in our file system we only have the default godot icon which well doesn't really work for us so we have to import a couple of images and that is super easy to do in godot and all you have to do let me open my file so this pong folder is the point folder we used earlier to create our game and above that i have an assets folder and all i have to do is to drag this assets folder into the profile and then go back to godot and then it loads for a bit and now we have an assets folder and in the assets folder we have a ball a pedal a couple of sounds and a font so how our text would look like so these are all the things we need for our game it's actually very simple so let me close this folder again and i'm not going to use the icon psg anymore so i'm going to delete it and to delete it i right click on it and click on delete and then godot is going to remove the file from the project and can't be restored and i'm fine with that so okay now our game looks a bit cleaner and with that let's actually add the image to our player and if you want to challenge yourself for this tutorial now try to add the picture yourself to this player note so you could just pause the video now and try to do it yourself and continue after you're done and i would really recommend this it helps you to learn so much [Music] but let's do it together so with the player selected i'm going to click on the icon again and i'm going to add a sprite and you can also see our sprite note in the recent tab so i click on create and now we have a sprite and i just need to drag and drop the image of the pedal into it so i drag and drop the pedal into it and now we can see our pedal or the image of our pedal but there's one obvious problem right now that the shape of the pedal and the image of the pedal have different sizes so we have to resize the pedal a little bit to properly be above the pedal image and there's one thing you also have to realize that in the note 3 the order really matters so right now the collision shape 2d is below the sprite and this you can also see in the viewport and let me reverse the order by just dragging it below now our sprite or the image is below the collision shape and this kind of thing is becoming important later on quite a bit where you want to control what elements are on top of each other so always be aware if something is further down in the century it's usually above the other nodes in the actual viewport but in here i want to make sure i drag all of the white part of the paddle inside of our collision shape and if you click on the blue part you can also move the entire shape around and if you hold shift then you move it only in one axis which can make things a lot easier and i want to make sure i only cover the whitish part and let me yeah okay i think this looks good if you want to be more precise with this you can also click on the rectangle in the inspector and in here you can give it very specific coordinates so you could for example let me go with 14 and 60 so we have cleaner numbers although that doesn't really matter but okay now we have our player character this is really all our player character is ever going to be it consists of a kinematic body an image and a collision shape this is literally all you need to create a player so let me save the scene by pressing ctrl s and run the scene and now we can see our player in the top left which isn't too good so let me drag the entire thing a bit more to the middle and i can do that either by having player selected and going to transform and moving it here so i could press something like 100 and 500. let's say more like 300 or you could just drag and drop it but there's one more problem before i finish this part if you were to just select this thing and try to drag it you would only select the node furthest down in the scene tree so the collision shape in this case which would be a problem because our play would collide in this shape but we would see the player here so this is no good so what we have to make sure is that when we have this player selected that we can't move the sprite or the collision shape and for that you have at the top here an icon that looks like this it's very hard to explain all it does is make sure that you cannot select children nodes and if you click on it you can see this icon here and if that's the case you can only select the parent node not the children nodes and this makes sure that all of these nodes always stay in the same place so now i can move it roughly let's say to left side of the screen and this is a really important part i do want to talk about that to create our game we are basically creating an allusion to the player that what the player is actually going to control later on is the kinematic body 2d so one specific point in space it just happens to be that attached to this note we have an image of a pedal and a shape with the size of this pedal so the player assumes all of this is one object but in reality it really isn't but uh but okay i think this part is getting quite long so let's get to the next stage and that is to actually give our player the ability to move which is what we are going to do with code so let's have a look at that so let's talk about how our player can move and for that we have to talk about programming in godot and there are different languages you can use to code in godot the language we are going to use is called gdscript which is insanely similar to python i talked about this earlier in this video but it's also a really simple language so even if you never code it before this should still work for you or at least i hope it will but before we're getting into specific code there's one important concept that in goodu code is always connected to a node and what you effectively do is you take a node and take all its attributes and you create additional capabilities and each node can be expanded in different ways so for example a kinematic body 2d can get different functionalities compared to a sprite note for example but you don't have to worry about this too much for now let's actually start creating some code so here we're back in our player scene and i have our player notes selected and to create a script you have to use this icon here which says attach a new or existing script to the selected note so i click on it and now we have a couple of options the first one is the language we want to use and we want to use gdscript then we have inherit and this is the node we are starting from that we are going to use to expand its capabilities so kinematic body2d node is fine then we have a template as default empty and no comments i will leave it now at default but later on you definitely want to start with empty then we have built-in script which is just asking you if you want to save the script as its own file or as part of the note it's usually left off but it really doesn't matter and then we have the name of the file so player in my case and what we want to store it also in the player folder so all of this is fine by default usually so i click on create and now at the top we can see script and we can see our script and if you want to go back to your viewport you can just click on 2d at the top or go back to script and you can also use the f keys to switch between them where f1 is 2d f2 is 3d and f3 is the script view and this does make it quite a bit easier to switch between the different views and i'm going to use that quite a bit but alright in here we can see a couple of examples godot provides and let me actually get rid of this part down here but we are going to come to that later on so what you see here right now is that you can declare a member variable and a variable in essentially any programming language is a box that you can store information in and this can be either a number like the number two or it could be text and text is usually called a string and a number without a decimal is called an integer so these are different data types although that really isn't too much at this stage if you're new to programming but okay let me get rid of all of this because we don't need it so just to get it started i want to create one variable so i use the keyboard var and now i have to give the variable a name and i want to go with speed because i want to use this variable to determine how fast our player can go and i need to assign it a value and this is done with the equal sign and now i have to type a number how fast i want my player to be and i want to go with 400 and i've chosen this number by just trial and error so if you play around with this later on there are lots of different options there's no universal one just choose whichever one looks best but all of this is still just a number it doesn't actually do anything in our game and to actually do stuff in our game we need a function and a function is really just a collection of different lines of code that you all execute as one block and usually for a function you have two steps you first have to create a function and then you have to call the function and this basically means that you first have to create your code of block and then you have to use the code of block in specific spots where you want to use it in godot this is slightly different that you have two different kinds of functions you still have the normal functions that you have to create and call yourself but you also have inbuilt functions and these functions you only have to create you don't have to call them yourself because godot is going to call them at specific points in your game so for example we have a ready function and this function is always going to be executed when our scene is ready or there would be an input function that is always executed when we get player input so for these functions godot determines when they are being executed which is really useful for your game and for our player we actually do want to start with an inbuilt function and really what we want is to have a function that is being executed on every single frame of our game so essentially a function that runs constantly and godot has two of them they are called process and physics process and those two functions are incredibly similar and you don't have to worry about the differences in too much detail yet at least for this stage just keep it at process is usually used when you don't care about physics and physics process is being used when you really want to calculate physics calculations which in our case we do want to do so we are going to use that function but again lots of theory let's actually get back into our code editor and let's implement this so here i'm back in my code editor and let me go to a new line and to create a function we need to func keyword and now we need the name of our function and in my case this is physics process and into this function you can pass what is called an argument and godot by default passes in an argument in here that's called delta and all an argument really does is when you're executing a function is that you can tweak the parameters so this one can be useful to find tweak what the function is doing and what delta does in godot is that it makes sure that the game always runs at a consistent speed which isn't something you have to worry at this stage in too much detail so i would recommend to just ignore it at least for now all right if you press enter now godot is going to go to the next line and it's going to indent the next line and this indentation is really important it means that whatever code is below and indented in this function belongs to the function so further down the line if you created more code below this function that is not indented it would mean it doesn't belong to the function but now in this function we have to give our player the ability to move around and to move around we are going to need three different steps number one is that we actually need player input so that we check if the player is pressing up or down in my case but could be any kind of input number two is that we are storing this input and number three is that we're actually applying this input to our player and let's go through this step by step and before getting to the input i do want to start with some kind of variable that can store the user input and i'm going to use a vector and if you paid attention in high school you might remember a vector but vectors are generally useful in game development and really important and fortunately they're also quite easy a vector is essentially an arrow that can point in different directions and what we want is that by default we have a vector that doesn't point in any direction but if we're pressing the up key we want it to point upwards and if we're pressing the down key we want to point downwards and that's really all we need so let's actually create this so here i'm back in my code and i want to create a new variable so again i need the var keyword and now i have to give this variable a name and usually this one is called velocity which i am remarkably bad at spelling for some reason my brain just can't get around it all right now we want to create a vector and for that we just need the vector keyword and godot now asks us do we want a 2d vector or a 3d vector and since we have a 2d game we want a 2d vector and now when you press a dot you can access its attributes so what the arrow is pointing at by default and what i want to go with is 0 all in uppercase letters and this means that by default this vector is 0 0 so it doesn't point in any direction it's just the point in space although we can influence this and that actually comes now because now we're getting keyboard input and for keyboard input we need a specific keyword that is called input and here again we need a dot sign to use a specific part of this input so the input is essentially a large object it has lots of different functions that you can all access with a dodge and the one we want to access is called is action pressed and all this does is it checks for specific keys and here you have a list that i predefined but you could create your own and what i want to look for is ui up which is the up key on your keyboard so if i click on this we have it as an argument inside of this function and this is actually bringing us to a new data type and that is a boolean and booleans can either be true or false so in our case if we were to run this game and we press the up key this entire line would signal that something is true and if we don't press the up key it would be false and to actually use this in code we need an if statement so that if all of this is true we want to do something and else we don't want to do that and then to finish this line we need a double colon and now when i press enter again we again start on an indented line so this means that anything that comes below is only being executed if this line is true so if we are pressing the up key and if that is the case we want to target our velocity again so here be aware in here we are creating velocity and here we are using velocity so you only have to create a variable once once you have done that you can just use the keyword and work with it and a velocity has an x and a y attribute that you can influence with x being the horizontal one and y being the vertical one so we want y because we want to go up and down and all we have to do in here is to change this number to a different number so it's pointing in a certain direction so i want to take this value and subtract one from it which happens with minus equal and one so this kind of operation is really common in programming languages it basically means we're taking this value and subtracting one from it so this would be the same as velocity dot y equals velocity dot y minus one these two lines do exactly the same thing except this one is quite a bit faster to write okay and this is all we need for this one line to move the player upwards but obviously we also want to go downwards and here again if you want to challenge yourself pause the video now and try to implement the code for the down movement but to do it all you have to do is to copy this line or really type it yourself it doesn't matter and now instead of looking for ui up we want to go for ui down and in here instead of subtracting 1 we want to add one and this is something that might be weird to you right now that if you want to go up we have to subtract from y and if you want to go down we have to increase y which is going to be really strange if you paid attention in high school so let me explain in high school when you saw a coordinate system it always started in the bottom left so if you went to the right you have to increase x if you want to go up you have to increase y which tends to make sense in most video game developments this is slightly different because the origin point is in the top left meaning that if you want to go to the right you still have to increase x this one stays the same however if you want to go down you have to increase y and if you want to go up you have to decrease y which is honestly really counter-intuitive and is going to take you some time to get used to but it just became the standard in quite a lot of engines i have no idea why but you will get used to it eventually so don't worry about it too much but with all of that covered we have the two first steps to get input we have code to get input from the player and we can store the input now we just have to apply this input to our player and this happens with the move and slide function so i type move and slide and in here godot already gives us some hints in terms of what it needs and the first argument it wants in here is a linear velocity which we have it's our velocity and well that's all we needed so let me save this entire thing now and let me run this scene by clicking again on this icon at the top or pressing f6 and now we can see our player and let me move up and we can see that our player is moving up just very very slowly and that's for a good reason let me close this again because we are only moving it by one unit but we want to move it by this 400 and so all we really need to do is to multiply this one by 400 so when we call this move and slide function we just multiply velocity by our speed and now if i run this again by pressing f6 now we can move up and down this feels so much better okay and there was a ton of theory in this part of the video so i think it's good for this section so let's talk about creating our level for now our entire game consists of a single scene and that's the player scene but obviously this is quite limited because we want to have other elements in our game as well we want to have a ball and the opponent at the very least and each of them is going to be their own scene but we have to bring all of them together into one big scene and this is going to be the level scene where we actually going to create our game logic and our level doesn't actually have to do all that much it's quite a simple thing it really only has to carry all the other scenes and have a bit of extra code to reset the ball for example or to limit the movement of the player so let's actually go right in and let's create this so here i'm back in my game and what i want to do is to click on this plus icon and create a new scene and we are still in the code view so i go back to 2d and here we can again see our 2d space and now we have to determine what kind of node do we want and in this case you could go with a 2d scene but you don't really need it so i'm going to go on other node and i'm going to just click on node which is the base class for all scene objects which is a fancy way of saying this node is a really basic node that can't really do anything by itself and let's click on create so now we have a node and let me rename it to level right away and if you look into the inspector you can't really see anything so we have pause and script but they don't do much so this note is so basic it doesn't really have any attributes so it can't do all that much but it is really useful to organize your code so you can put other nodes connected to it and this is what i want to do i want to connect our player scene to this level node and for that we have to instance our player into this new scene and let me actually save it before we do anything so right now when you look at the tab it says unsaved so i press on control or command s and here again we can see our folder and i want to create a new folder that i'm going to call level and in here i want to save this scene as level scene because our root node is called level so click on save and now we have our level scene and now with this level selected click on this chain icon and this is the instancing icon and if you click on this you can see all of our scenes we have a level scene and we have a player scene and we want to play a scene so i click on open and now we can see our player scene inside of our level and it is still going to have the same capabilities so if we were to run this scene now our player character would still work in exactly the same way and let's actually try this so again i press on f6 and now we have the very same thing even though we have a different scene so now we're running the level scene not the player scene but the player scene is part of the level scene okay cool so this works quite well and now we can actually add more useful stuff to this and the very first thing i want to add is that let me run the game again if i go up and down we can move outside of the screen which well is unintentional so we want to add something that the player can't go outside of the screen and there are different ways to achieve this but before work on this i do want to work on how large our game is supposed to be so let me close this so right now here our game has the size of this blue rectangle and we can influence how large this is going to be and to influence this you have to go all the way to the top to project and project settings and in here you have all the settings for the project and if i go down a little bit there we have display and window and in here we can change the width and the height of our window and by default this is always 1024 by 600 and you can't leave it at that it's perfectly fine but i feel like 1280 by 720 tends to feel a bit better but it's really up to you you can also change if it's resizable or borderless or full screen it's really up to you play around with this but for now i'm not going to worry about screen scaling in any meaningful way so i'm just going to close it and now we can see that our blue box has increased in size by quite a bit and if we were to run this game we'd also see it is quite a bit larger now so we know this is working good start but now the actual important part we want to limit our player from moving outside of the screen and we can approach this in two different ways one is that we can give our players some code that it can't move outside of the screen or number two we could use another physics body to limit the movement so so far we have seen a kinematic body we can use another physics body at the border of our screen that the player would collide with and those would basically be walls and since for our ball we also want to use walls i am going to go with the second approach so we have walls that limit our player our opponent and also make our ball bounce so we have lots of functionality and one object which is really nice and for that we have to talk about another physics object in godot which is called the static body 2d and i think the name already explains it quite well it's well a static body that can't move by itself so it is essentially a wall and that is really it it's just a physics body that can't move by itself but if other objects move against it they will be influenced by its physics and static body 2ds also work like a kinematic body 2d that you start with a single note that has the physics and then you have to give this note a shape so let's actually create all of this so here i'm back in my level scene and with the level note selected i want to add another node that is going to be a static body and here again you have a static body in 3d and a static body in 2d and i want to go with 2d so i click on create and here again we have a static body 2d and we are getting an error message that this note has no shape so let's give it one so with this note selected and not the text i'm going to click on the plus icon and i want to give it a collision shape this one down here so click on create and still we can't see anything we get another error message again that we have to provide a shape and this happens again in the inspector and here i just click on whatever shape i want and i think again we want to go with a rectangle shape 2d because well the wall doesn't need any fancy shape a rectangle is fine so i click on this and now we have a wall that the player couldn't collide with and let me actually demonstrate this so i'm going to drag this out a bit and move it let's say here so when we run our game we should not be able to move past this point so i save the game and press f6 again to launch it and let's move up and indeed i can't move further up than this point so this is working but obviously we want to be limited by the top of the screen so we have to change all of this and move this entire shape to the top of this blue line and let me zoom in quite a bit if we want to be right on this blue or red line and to be more fine-grained you can also use the arrow keys and move it up or down or you could use transform and use it here let's actually go with that so i have transform open and i also click on rectangle again so now we can see the dimension and the position and all we need to do is to change this to -10 and this is going to bring us exactly 10 units from the top of the screen and now we want to have this static body cover the entire top part of the screen so i'm just dragging it out and this would be fine or if you want to be a bit better looking for the game you can also move it to the middle and have the size a bit more appropriate for it so it doesn't move massively outside of it and yeah i think this looks about right and here if you look at our scene tree now we have a bit more of a complex structure we have a root note the level we have one child that's the player and we have a static body that's also child of the level node but now this static body 2d has its own child which is the collision shape 2d so if we were to move this static body we would move the collision shape 2d but if we move the level we would move both the static body 2d and the collision shape because they are both children of the level node ok let me rename this one to wall top and then you can minimize it which makes it easier to work within your game and this is giving us our turbo so let's try this by running our game and i can move all the way to the top of the screen but not further so this is working quite well cool so now we have to create a wall at the bottom of our screen and here again if you want to challenge yourself pause the video now and try to do this yourself but effectively all you have to do is to copy this entire wall top by pressing ctrl d and let me rename it right away toward the bottom and then you can just drag the entire thing down and here again you can see that i'm moving the collision shape not the static body although in this case it wouldn't matter too much because this collision shape is what actually matters but it doesn't feel good so with the wall bottom selected i'm going to click on this icon again that we cannot select the children and now i can move the static body down and let me zoom in again and i want to roughly move it at the bottom of the screen or if you want to be really precise about this you could also move it to 740 and okay this is all we needed and let me change the same thing so it's all consistent and let's run the game now and i can't move to the top and i can't leave the screen from the bottom so this is working quite well cool and we are making some decent progress and with that one done let's start by creating our opponent and the opponent is actually done in a really similar way compared to our player as a matter of fact it is going to have the same notes it is just going to have some slightly different code so instead of using keyboard import to move this one we are going to make this one move to wherever the ball happens to be but this part will come later when we actually have a ball for now let's just create a basic opponent so here again we are in our level scene and i want to create a new scene for the opponent so i click on the plus icon at the top to add a new scene and here we have the scene and what we want to do is to basically copy this player scene and do the same thing except for the code and this again could be a challenge if you want to code along pause the video now and try to recreate our player but let me go through it i want to start with another note that is going to be a kinematic body 2d and this time i guess that's one difference i want to name this opponent and again we're getting the warning but i'm going to ignore it for now because i want to start by adding the picture so i click on this plus icon and i type in sprite and i'm going to add the sprite and here again we're going to use our assets and the pedal it is the same as the player has and here now we have an opponent that is a kinematic body and a sprite now i want to add our collision shape so here you could add a collision shape 2d and this works just like for the player you can add a rectangle shape 2d and move it roughly in place to where this needs to be [Music] something like this so yeah i think this looks good and just for completion's sake what he could also do so let me just hide this one for now you could also use a collision polygon 2d this one works in basically the same way except now you cannot select a pre-built shape instead at the top of the screen you can see these three icons that says create points edit points and delete points or erase points and what you basically do with a collision polygon is you are creating your own shape so when i click on create points i can literally just put points on the screen so if you have a more complex shape this one would be quite easy and then if you're at the last point just click on enter and then it finishes the shape so now we also have a square shape but this shape could be any point so if you added points you could create something much more complex but in my case i well don't need to so i'm happy by just using a collision shape because this one is much easier and we don't have any fancy shapes and yeah that's literally all we needed so now i'm going to save this entire scene in its own folder that i'm going to call opponent and again it's already named appropriately so i click on save and this is our opponent so now this i can also put into our level scene and here again i have the level note selected i click on the chain icon to instance it and put an opponent and now move opponent roughly in place okay this looks good so now let me save this level scene and run the entire thing we can see that we have two pedals and we can only move our player our opponent is not moving and we don't have a ball but that comes later but i think we're making decent progress there's two more things i would like to add though number 1 is to make this level scene our default scene so right now we have always only played a single scene and this happened with f6 but what we can also do is run the entire game as a whole and our game consists of different scenes but by default godot does not know which is the default scene it needs to start for the game and this we have to define ourselves and all this really means is when you click on f5 udo is going to ask you that no main scene has been defined do you want to select one and we do so click on select and here we would have all of our folders and i want the level scene to be the main scene so i click on level scene and now we can see our level again and now even if we were in our player scene i could press f5 and i could start the actual game how it's supposed to be looking when it's actually being played so this one makes it easier to launch games but okay let me close the player and the opponent scene closing them doesn't mean you delete them you can still open them from the file system so down here so down here you can just double click on the player scene and reopen it all right the last thing for the level is that this gray background looks absolutely hideous so i want to change it and to change it we have to add another note so with level selected i'm going to click on the plus icon again and i want to add a color rect which is well it's a colored rectangle kind of like the name implies so i click on create so now we have this colored rectangle in the top of our screen and let me zoom in a little bit so here you can see the color and you can influence the color here and i will talk about this in just a second but for now what you do have to be aware is that when you look at the color of this note it's green and this means that it's a ui note so godot essentially has four different kinds of notes we have the blue ones those are 2d notes then we have the red ones those are 3d nodes then we have the green ones those are ui nodes and then we have all the other nodes like the plane node for example is just another node it doesn't really have a specific group and ui nodes have a couple of specific parts that are really powerful and effectively what they can do is be really responsive to the size of the window so you can always make sure they're for example in the middle of the screen always cover the entirety of the screen which in our case isn't going to matter too much because the game isn't designed to be resizable although we could add that later on but we could for example make it cover the entire screen really easily let's actually do this so here we are back in our editor and with the color rect selected at the top you can see these two green icons that say layout and then you have this anchor kind of icon and if you click on layout you have lots of different options and what you can click is full rect and then this rectangle is immediately covering the entire screen and right now it's covering everything even our players which we don't want so i'm going to move this color direct above all the other elements so it's below them so now we can see our player and our opponent again and here you would have a couple more elements that we are going to see in a bit more detail later on but for now just be aware that ui elements have lots of options to arrange elements on the screen but okay now the white color doesn't look too good so we have to give it a different color and here we have quite a few different options in terms of how we are going to work with color we have rgba numbers we have hsv we have raw and we have hexadecimal numbers and every single one of them are a different way to create a color what we are going to use is the hexadecimal number which is the one down here and the number i want is 14 21 and 26 and now if i press enter we get a dark color and let me explain how this works hexadecimal number always consists of six different numbers that follow a hashtag and the first two ditches define the amount of red the third and the fourth digit determine the amount of green and the last two digits determine the amount of blue so the higher the number gets the more amount of this color we have and the way we are counting a hexadecimal number is going to look a little bit weird because we're counting from zero to one and then from a to f so basically goes one two three four five six seven eight nine ten a b c d e and f so there are 16 different stages that you can have and then you have three different colors and you essentially mix them and i hope that makes sense okay with that we have our background color so now when i press f5 this does start to come together and look quite decently so with all of these parts covered let's actually start talking about how to create our ball so our ball is going to be the most complex object in the entire game which basically means it's going to be the object with the most amount of code but in terms of notes our ball is actually going to be remarkably similar compared to the player and the opponent we will still start with a kinematic body2d add an image and add a collision shape and i think you really start to notice that there is a pattern that most objects in godot work in really similar ways that you always have some kind of physics node then you add a picture and then you add a collision shape and this can be more complex for example the image could be an animation or the collision shape could be more complex but really at the most basic level most objects in godot work really similarly so it's really easy to create them so let's start to create our ball so here we're back in our editor and i want to create a new scene and again i'm going to pick another note and here again i'm going to pick kinematic body 2d and i'm going to rename this one to ball and i'm going to add the sprite and i am going to add a collision shape 2d and for the sprite this time i'm going to go to my assets and add the ball and then for the collision shape let me zoom in a bit i am going to pick a circle shape 2d this time because now we have a circle we don't have a rectangle anymore and in here now we only have one red dot because a circle is a bit of an easier shape and i'm just going to drag out this red dot to make sure this circle roughly matches our ball and that's all we needed so now let me save this in a new folder that i call ball and save this as ball dot scene cool and now i go back to my level scene and instance the ball into it now we can see the ball on the top of the screen and let me move it roughly in the middle of the screen at least for now and that's all we need for the basic ball so if we run the game now by pressing f5 we can see all the very basic elements of our game so that's a pretty decent start so now we can close this game for now and now we actually have to make our ball move and that's going to be the more complex part so let's go through it step by step with the ball selected i'm going to create a new script and here again we have all the same options except this time i want to start with an empty template but the folder is still fine so i click on create and here now we're starting with completely empty code except that our code extends a kinematic body to d so this one is fine and here again i want to create a couple of basic variables that are going to be important for our ball and the first one is going to be the speed of the ball so speed equal to let's say 600. again you can play around with this value it just determines how fast the ball is going to be and another important thing let me open my player script again so on the left you can see all the open scripts and if you go to the file system and click on player.gd for example you could open the old script and right now what we have is that our player has a speed variable and our ball has a speed variable and that's fine each of these nodes has its own scope meaning that you can have a variable name speed for the ball and the variable name speed for the player and even the variable name speed for the opponent that's perfectly fine it doesn't matter if they have the same name so this was a good start and then this time i want to create a velocity vector again and this one again is going to be a vector 2 dot zero so an arrow that doesn't point in any particular direction and here do know the difference that for our player we created this velocity inside of the physics process whereas for the ball we are creating it outside of it and there's a specific reason that you are going to see in just a second actually right now so the reason we have to define velocity outside of a function is because we want to use it in lots of different functions so what i effectively want to do is when our ball is ready i want to change this vector 2.0 to a specific direction and then i want to use this direction in the actual game in the physics process so we couldn't define this velocity inside of a function because we want to use it across multiple functions oh yeah and this is something i haven't mentioned before so let's say open the player again if you create a variable inside of a function this variable is only available inside of this function so this velocity here is only going to be available inside of this physics process function so we couldn't use it outside of it but in this case it's fine because we don't need it outside of it and helps to keep our code clean but in case of this ball velocity we do need to use it in different functions so it's important to define it outside of a function okay cool so now when our ball is ready we want to give it a random direction so we first have to run a function that only runs when our ball is ready and i talked about this a tiny bit earlier it's called the ready function and remember the underscore that one is quite important and use the double colon again and now we are indented in the line so any code we put in here is only going to run once when the ball scene is ready and what i want to do is to target velocity and now target the x attribute of it and now i want to give it a random number and this is a topic we haven't covered yet in godot how to create random numbers and there are a couple of different ways and to get to a random number we actually have to cover a couple of different concepts so i think the best way to go on about this is to first write the line and then explain how the line works so let me write the entire thing [Music] okay so this line is probably going to look really confusing so let me go through it step by step and there's actually going to be a new kind of data type we have to talk about so we are starting the entire thing with square brackets where we have minus one and one and this is called an array and an array is basically just a list so in this array we have two numbers that are minus one and one you store different numbers inside of a list so it's kind of comparable to a shopping list and this allows us to store different values inside of a single data type so this can be quite useful so basically what we have right now is a box with two values inside minus one and one and essentially what we are doing with the other square brackets is to pick one of these numbers at random and this process is called indexing that after you're putting square brackets after an array and put an integer inside of it you are picking a specific value from this array with a number zero picking the first element and number one picking the second element and so on and be aware here that the first element in an array is always the number zero but we want to pick a random integer and for that we have the function rand i and rand i generates a random integer but by default it generates a random integer across an infinite range so that's not good so we have to add the modifier 2 after it and this is what this entire part does it generates a random number that's either 0 or 1. and then this random number 001 is being used to pick either the minus one or the one and i hope that makes sense it's a tiny bit more complex i will put a link into the description of this video to explain this in more detail if you are interested but okay this covers our x speed so our horizontal speed now we need to talk about the vertical speed and this happens in exactly the same way so instead of x i change this to y and we are almost good to go the one thing i do want to change is that -1 and 1 feels a bit too steep so if we were to leave it at this our ball would start moving in a 45 degree line which i think would look quite slow so instead i want to lower the degree so this one could be 0.8 and or minus 0.8 and 0.8 so what this effectively means is that our ball is going to move to left and to the right by the unit of 1 but it's only going to move up and down by unit of 0.8 or negative 0.8 so it is moving faster in the horizontal direction than it is moving in the vertical direction and for now that's all we needed for the direction of the ball now just like for the player we can go with funk physics process and all we have to do now is to use the move and slide function and add in our velocity and let me actually try this and see if this is working so i press f5 and we can see that our ball is moving very very very slowly and again the reason for that is that we have to multiply it by our speed so now let's try this again and there we go there is you can see at the top the ball doesn't bounce but that's okay we can work on that in just a bit for now i think this seems okay but there's one more thing i do want to add before finishing this part that let me run the game again our ball is again moving to the top right and if i press it again our ball is again going to move to the top right and the reason for that is that these random numbers are not perfectly random and let me explain what godot does whenever you use a random number in godot what godot effectively does is it creates what's called a seed and the seed is really just a long list of numbers that godot picks from but godot always uses the same seed which always gives us the same number so these numbers are not actually random but we can change that by using the random mice function so now whenever our scene is ready godot is going to pick a random c to pick numbers from meaning that now when we run our game the ball doesn't start to the top right every time it can move in random directions and i hope at some point it moves to the left there we go okay so this is also working as well cool obviously the ball needs to bounce so let's talk about that so bouncing something off in godot with a kinematic body is actually really easy because there's a specific function for it and it's called move and collide and move and collide works kind of similar compared to move and slide they are both moving a specific kinematic body in a certain direction given the vector you put into it but when they are colliding with something they are doing different things when move in slide collides with an object it slides along the surface of this object whereas move and collide by default doesn't do anything but it returns what's called the collision object and you can use this collision object to make the object bounce off whatever we have hit so this is what we're going to do instead of using move and slide we're going to use move and collide and use that to calculate the angle we have to bounce off and i think it is best to just write in code so here we are back in godot and we have the code for our ball open right now and i don't want to use move and slide so i'm going to delete it and i want to use move and collide and again moving collide needs a vector so we need velocity so far this is exactly the same and again i also want to multiply it by speed but now there's one difference already that we have to multiply move and collide by delta and now with that let me explain what delta does delta is the amount of time that has passed since the last frame of the game was called so let's say if our game runs at 60 frames per second then the difference between each frame is about 17 milliseconds and godot is using that number to calculate how fast the game is going to run and let me illustrate why this matters imagine you have a game on two different computers one computer being really fast the other computer being really slow now the fast computer is going to be able to run a computer really fast so you might have frame rates like 200 whereas the slow computer might only get something like 20 frames per second now if we didn't account for the faster frame rate the game on the fast computer would run about 10 times as fast as compared to the slow computer which should make it really weird to play the game on different computers also within the same game if you come to the scene that is more complex the game might slow down and feel inconsistent so we have to account for different frame rates and that is what delta is for and really delta is just a very very small number that measures the time since the last frame and really what happens if you have a fast computer delta is going to be really small but applied very often whereas if you have a slow computer delta is going to be comparatively larger but it is going to be applied less often but both of these are going to equal out so the game is going to run at the same speed so the movements and side of the game are at the same speed and move and slide applies delta automatically whereas move in collide does not and the reason for that is that movement collide does more with physics so we need more control over it now the important thing is that moving collide whenever it hits something it is going to return what's called the collision object and this we can store in a variable so let me create a new variable that i call collision object and this will just assign with the equal sign so whenever we come to this line here udo is going to run this function and move our ball but then when this function is colliding with an object like our wall it is going to return a value this collision object and this collision object we can use to change the velocity of our player so the direction it is moving in and this we do we first check if this collision object exists in the first place which we can just do by typing if collision object and that's all we need so if this kind of object exists then this line is going to evaluate to true and then this if statement is going to trigger so we can use it like that and if that is the case we want to change our velocity because that is the direction we are moving in so we have to assign it a new value so use the equal sign and here we have to use velocity again and then use the bounce keyword and this one bounces a vector and into response vector we have to pass in the collision object and not just that but we also need a normal of this collision object so this line is going to look quite weird so let me explain what's happening here and let me illustrate this actually so here you can see a ball colliding with a wall and we want to bounce this spot off this wall and to do that we are going to need what's called a normal and the normal is just the direction a specific surface is facing so our wall right now is facing upwards for example and this normal we then can use to bounce the wall off in the right direction so the correct one for the bounce direction and all of this is done with the bounce method but well that's all we needed so let's actually try to run this game and see what happens so yeah there we go so the ball goes right outside of the screen let me run it again and we can even bounce off the pedal and oh it's actually working nice so here we have a bouncing ball so this works quite well actually and with that we almost have a working game there's one more thing we need and that is to have an opponent that can actually move along with the ball and that's going to come in the next section so what this means is that we have to talk about artificial intelligence at least on a very very very basic level but effectively this is what we are doing we are giving our opponent some kind of basic intelligence so they can follow the ball and we have an actual game but obviously we are not going to create anything sophisticated so all i really want to do is if the ball is above the opponent i want to move the opponent up if the ball is below the opponent i want to move the opponent down and then the strength of the opponent is going to be determined by the speed of the opponent and i think this is best explained while i'm actually doing it so let's jump right into our game and let's do this so here i'm back in my game and right now i only have the level scene open and if you look to the right you can see our opponent and if you want to open a scene really fast you can just click on this editor icon i guess and now we have opened our opponent scene and i want to give my opponent a script so i click on the script like again and here all the usual stuff i want an empty script let's say let's go with no comments so you can see what it looks like and i click on create so now we just have the function ready and we're actually going to use it in just a bit so i leave it here for now and as always i want to start with a speed variable just like for the player and the opponent and this one i'm going to set to 250 but now we do need another thing for the opponent to function properly it needs to know where the ball happens to be on the screen so i want to create another variable that i call ball and you don't actually have to assign any value by default this one is fine so this one doesn't have any value by now and i want to pass a value into it once the scene is ready which is going to be the ball so once the ball scene is ready i want to work with this variable and let me first type what i'm doing and then explain so i want to get parent and then find note so what happens here so whenever the ball scene is ready it looks for its parent which is in this case our ball scene's parent is the level node and then from this level node we are looking for a specific note which is the ball which is really all we're doing here that whenever our level scene is ready we are looking for the main level node and then from this node we are trying to find a node called ball and then we are storing whatever the result is inside of this ball variable so now we can work very easily with this node and now just as before we have to add some more functions to move this thing which again is going to be physics process delta and here we just need move and slide and pass in the vector and now here we don't have a vector just yet so for now let me just pass in vector2.0 so this thing is not going to move at all because this arrow doesn't point in any direction instead we have to add some more code to figure out where this ball is in relation to our opponent and for this i'm going to create our first regular function so i'm going to call this func get opponent direction it doesn't need any arguments and here note there's no underscore before it meaning that this function has to be called for it to be run at all which is different compared to this and this function but i'm going to explain this when we get to it so in here we have to create some logic to figure out when the player has to move up and when the player has to move down and we can work with that actually quite easily because we can get the position of both the ball and the opponent very easily and let me explain what we are going to do in here in the most basic sense we are going to check is the ball above the opponent then we move the opponent up is the ball below the opponent then we move the opponent down however we are going to give a little bit of a wiggle room so that we are only going to move the player up if the ball is slightly above the player so if the ball on the opponent are roughly on the same height we are not going to move the opponent because if we did the opponent would adjust all the time and would look incredibly wiggly so we have to create what's called a nested if statement so we first have to check if there is enough distance between the ball and the opponent and then inside of this if statement we check if the ball is above or below the opponent so let's get to it i first want to do the outer if statement that if there is enough vertical distance between the two and for that let me write the entire line first and then explain so we want apps ball dot position dot y minus position dot y is greater than 25. so what does any of that mean i think ballposition.y and position.y are fairly clear baller position at y is the y position of the ball and position note y is the position of this note here so we are essentially subtracting one from the other but we are putting this inside of an abs function and absolute numbers are just always positive numbers so let's say if we're getting something like -50 out of here the absolute function would turn into a positive number and this is there to ensure that it doesn't matter if the ball is above or below the opponent so we're just looking for the distance between the two not if it's above or below this comes on the next line and what we want to check in here is if ball dot position dot y is greater than position dot y and if that is the case we want to return one and i'm going to explain what this means in just a bit for now just stick with me and all what we are checking right now is if the ball position is if the ball is below the player so if it has a greater y value and if that is not the case so else we want to return a minus one and again don't worry about return right now i'm going to cover this in just a bit and now we have our two possibilities that either the ball is below the opponent or it is above the opponent so the else statement here so if this entire if statement doesn't come to true then we want to else return zero and this is the entire logic to move the opponent so let me explain what the return means so every time a function is running it returns a value and let me actually open the code for our ball so here we can see this line we have move and collide and this is returning a value into this collision object so whenever this function is running it returns a value and when you create your own functions you can set what the function is returning so in this case if this is true our function is going to return 1 or it might return a negative one or it might return a zero so really all this function does is if the ball is below the opponent it returns a one if the ball is above the opponent it returns a minus one and if neither of these are true then it returns a zero whereas for the ball this move in collide returned a collision object so something much more complex but this number we can use immediately in here so our vector 2 when we add brackets to it we can specify what directions we are looking at when we create this and for the x we just want it to be zero because we don't want to move the opponent left or right we only want to move it up or down and for up or down we want to use this value here so we can just call this function inside of this vector so get i called it opponent direction so now whenever godot runs this function it creates a vector inside it that doesn't move on the x but for the y it looks at this entire function what is being returned and then again we have to multiply the entire thing by our speed and this is a slightly more complex example so it's probably making sense to go over this a couple of times if you're new to programming or good dough but let me run all of this and let's see if this is working and yeah it is and really nothing complex happens here all that's really happening is that we check if the ball is above or below the opponent and then we move the opponent up or down depending on where the ball is so we have almost a workable game there's one thing left to do that we have to reset the ball once it moves outside of the screen so that's going to come in the next part and again to achieve that we have a couple of different options we could just calculate something in code to check the position of the ball but i'm not going to do that instead i'm going to use a node for this approach and this is bringing us to the third kind of physics node it's called an area 2d node and an area to danio doesn't really calculate physics instead it just checks if the physics body is inside of it so what i'm going to do is to put area 2d notes to the left and to the right of the screen and whenever the ball is inside of them i'm going to put the ball back to the middle of the screen so really something very simple so let's jump right into godot and let's do this so here we're back in our level scene and i want to add a few more notes so with the level selected i click on the plus icon and now i want an area to denote i add it and here again the door wants it to have a shape so i press ctrl a and i add a collision shape 2d and here as always i want to add a new rectangle shape and here we can see our rectangle shape and move it roughly into place and here's one thing you do want to be aware of that both of the wall top and the wall bottom they are also physical shapes so if the wall is colliding with the area to d this area to d would also be triggered so the area 2d at least by default only cares if any physical body comes inside of it this could be a wall it could be a player this could be a ball it doesn't matter so at least in our case we have to make sure that it doesn't collide with either of the walls and granted this isn't the best approach to do this kind of thing but i think for our game at least it's serviceable so i'm not going to worry about it too much ok now we have an area to the side of the screen and the ball wouldn't bounce off this shape it would go through it but then this area to denote could tell us that it's colliding with the ball but step by step before that i want to copy this area to d and again select it so you can't select the children and move it all the way to the left behind the opponent and this doesn't have to be too precise okay now we have area nodes to the left and to the right side of the screen and they are going to know that the borders collided with them but by default they're not going to tell us and we have to add some specific functionality that they're actually telling us that the ball is colliding with them and to do that we have to cover a new concept that is called signals and all a signal does is it helps us to make nodes communicate with each other so in our case what we want to do is if the ball is colliding with the to denote we want the area to linear to tell us that it's colliding with the ball and that's really all there is to it in a bit more detail though when you're creating a signal you always have to connect the signal to a node with some code because the signal is effectively creating a new function that works like an inbuilt function that is only being called at specific instances so for our area to denote for example it's only being called when it's colliding with physical body but okay lots of theory let's actually implement this so here we are back in our good old editor and i'm going to start worrying about our left side and let me actually rename them to left and right and yeah i got the right side so i want this left side to tell this level scene when the ball is colliding with it so with left selected i go to the right and there's inspector and there's also node and if i click on that we have signals and groups for now we only look at signals groups come later but here let me explain this we have all the different options that could be signals and what we are looking for is body android so this signal is only being triggered when a body like the ball is entering this area to the node so i double click on it and now we have a problem that we can only connect this signal to a node with some code and it doesn't really make sense to connect it to the player the opponent or the ball well maybe the ball but i want to connect it to the level itself so what i have to do is to give this level its own script so again i click on the icon and i just click on empty and create a new script and let me minimize this again because we don't need it so now our level scene has a script as well that doesn't really do too much at least just yet but again i go to left and click on body edit again and now if i double click on it i can connect it to the level and i could also give it a specific name but usually the default names are fine so i click on connect and now inside of the script for our level scene we have a new function and this function is going to be triggered every time a body enters this area 2d and we also have an argument with the body and this is the body that entered the area 2d so we could use this to influence the ball itself and let's first try if this is working and there's a really useful tool to check if something is working is called the print function and let me just call it collision for now so what we're doing in this line that if this function is being executed we want to print this text so collision and we will be able to see this at the bottom in the output tab so with this one open let me run the game and the ball goes outside and unfortunately we can't see anything because we're only checking the left side right now we're not checking the right side so let's try this again okay see when i get lucky there we go okay now it's on the left side now we can see collision so we know that this function here works and it only works if the ball is colliding with it so print is really useful to test your code but in my case i don't really care about it for now so what i want to do now is whenever this function is being triggered i want to reset the ball and that brings us to a new concept that we have to select different nodes from a starting node so right now let me open the opponent for example all of these methods they always apply to the opponent node itself we never tried to influence the sprite node or the collision shape 2d we always worked directly with the opponent node but now this is slightly different because we want to go from the level note and influence the ball so what we have to do in our code is first select the ball and then influence the ball and we can do this very easily and there are actually different ways of doing this the easiest one is use the dollar sign and then the name of the note you want to target so my case ball so if we have this line here we would only target the ball and if i now for example change the position we would only change the position of the ball not the position of the level note and that is actually what i want to do and the position has to be a vector 2 and now we have to put in the x and the y position and i want to go right in the middle of the screen so it's 640 by 360. so when i open our screen dimensions again so i just halved both of these numbers which brings our ball right in the middle of the screen and at least for now that is all we needed but obviously this is just the left side so we also have to connect the right side and this could be a challenge again if you want to code along so pause the video now and try to connect the right side with a signal and also reset the ball if the ball collides with the right side but let me do it so with the right side selected i am going to click on body entered and with body entered i again connect the signal to the level scene and i don't change the name but you could if you wanted to and now i'm just going to copy this line here and that's basically all we needed so let's try all of this and let me actually lose and there we go we have the ball starting again in the middle and with that we actually have a really basic game all that's left to do now is to add some more refinements to make the game look a bit prettier and that's going to come in the next part and i'm going to start by adding a score which is actually super easy to add but it is going to require us to work with text which is something we haven't done so far but text is actually really easy so let's actually jump right in and i will explain it while we are implementing it so here again we are in our level scene and i want to add some text and text in godot is called a label and you have also a rich text label but for now i just want a label which is a really really simple text but it could be more complex but i don't need that so now we have a label and if you look at the inspector we can write for example test in there and if i zoom in we can see test so this is working quite well obviously we don't want it to be in the top left of the screen instead i want it to be roughly in the middle a bit further to the left so we can see it's the player score and actually let me rename it to player score and here again you can see it's a green node just like our color rect and i can actually put them together that makes sense and here we can use the layout again and what i first want to do is to check for the full rectangle so this node is looking at the entire screen but our note is still in the top left so effectively what we have created is a really large text box with some text in the top left so we have to change this text box to move the text right into the middle which we can do if you look at the inspector you have a line and via line which is short for vertical align and right now it's left and top but if i change it to center and center and now we have it right in the middle it might look a bit deceptive because of the ball but i just put the ball randomly on the screen so the test is actually in the middle of the screen and obviously we don't want it to be right in the middle so i want to add a margin to it that it's moved slightly further to the left and this we can do under margin and here we have left and right and you can just move either of them so let's go with negative 200 and this is going to move the text a bit further to the left and alright this looks fine so now i can copy the entire thing so i also have an opponent score opponent score and this opponent score i just moved the margin to 200 so it's a bit further to the right and let me trial of this in the game now and yeah we can see test and it looks roughly in the middle cool so now we have two things to do the first one is we have to update the score and the second one is that this text doesn't look very good so we have to update that as well and let me start with the actual score and this one is not that difficult to do so i go back to our code and in our code i'm going to create two new variables the first one is called player score it's going to be zero by default and then we also have an opponent score which is also going to be zero and now on every single frame of the game i want to set these scores as the text for our player score and opponent score labels and for this this time we are going to just use the process function so let me type func underscore process so this process works kind of like the physics process except in this case we are not calculating anything physical we're just setting some text hence we're only using process not physics process and what i want to do in here is to first target our player not player sprite player score and to change the text i need text and if you want to find out what the attributes are of a certain note you can just look at the node itself so players go in this case and hover over what you want to influence so if you hover over text you can see property text and this is what you have to use in the code to target this attribute and then for this text i want to set player score but this would not be working by default because of the data type that this kind of text is looking for a string so a certain kind of words but this player score is a number so we have to change this player score from a number to a text which we can do very easily with the str method which is called string and all it really does is it takes a number and turns it into a string so exactly what we need so let me try this now so now player score should be zero and it is cool but it doesn't update yet so we have to work on that but before that i'm going to copy this entire line and change it to opponent score and up opponent score and now we run this they should both be zero and they are cool now what we have to do is to update these two scores to reflect the actual score and this we can actually do very easily because we already know if the ball is leaving on the left side of the screen or the right side of the screen so if the ball is leaving on the left side of the screen we know the player's score is increasing by one and if the ball is leaving on the right side we have player score plus equal one and this is all we needed for the score so let me try this now and let me get score there we have one two oh yeah i messed up the sides so i just have to change this one around oh no it's player score and player score right so on the left this would be opponent score opponent score let's try this now and yep this looks better and yep this also works and there we can actually see one more problem that we're going to cover later that either the opponent or the ball could be moved by the ball in terms of physics but don't worry about this for now we're going to fix this in just a bit but for now we have a working score system so what's left to do for now is to change the style of these fonts because they look pretty bad right now and again this is quite easy to do so with the player score selected we have custom fonts and custom colors i'm going to start with custom fonts if you open this tab you have a drop down menu and you can type new bitmap font and new dynamic font we want a dynamic font so i click on it and now i have to type on dynamic font and don't worry about the text disappearing that's normal so i click on dynamic font and now we have settings extra spacing font and resource and in font we can set our custom font and in our assets folder there actually is a custom font it's called poets and one regular and if i drag it into we can see a custom font and here we can also change the size of it and make it smaller i think i went with 50 possibly a bit large let's go with 40. and this would be a custom font so if i run the game now this one would look drastically better cool and we can also change the color of this so custom colors and by default it's black and here you can change again the color around and in my case i'm going to use a hexadecimal number again that is b9 d8 and d7 which is a fairly whitish color but not perfect white and all right that's really all we need to make the text look prettier now we have to do the same thing for the opponent score and again if you want to challenge yourself pause the video now and try this yourself but all you really have to do is go again to custom fonts create a dynamic font click on dynamic font again click to font and now drag and drop the font in there from the asset folder and then for settings i went with a font size of 40 if i remember correctly and now under custom colors enable font color and click on it and it was d9 d8 and d7 click on enter and you're good to go so let me run all of this again now and we have our scoring system so seems fine and with that we're actually making pretty good progress in the next part i'm going to add a countdown timer so there's a bit of a delay before the ball restarts okay then it timer and timers in godot are actually fairly straightforward because again we have a specific note for that that we can use actually quite easily and more specifically what i'm trying to achieve are two things number one is that we're having a count on timer before the ball restarts after we have fit a goal and number two is that i also want to display this count on timer so that we can see two one and zero on the screen or something like that and some short number that counts down from a certain number to zero how long that is going to be is up to you but i found two is a good starting point because three actually felt a bit too long but the specific number really doesn't matter let's have a look at this so here we are back in the code and the first thing i have to add is a timer node so with our level selected i click on the plus sign again and i want a timer node and it literally says a countdown timer so create and again i'm going to rename it to count down timer and if you look to the right at the inspector you can see a couple of attributes number one is the wait time so this is the length of the timer then we have one shot so is this time we're going to run just once or multiple times in our case this is going to be true and then we have autostart so if it starts by itself or if we have to trigger it quite straightforward so in my case i want wait time to be 2 and one shot to be on and that's all we need for the attributes but now obviously if this timer were to run out we would again need a signal to tell other nodes that the time has run out kind of like for the signals for the area to denote for the left and right areas so here same principle this timer right now would be running however we have to tell another node that it has triggered so for this again we need a signal and for that i go to the top to node and here we only have one really big signal that's timeout and this is when the timer reaches zero so seems appropriate so i double click on it and i'm going to connect it to our level and here again besides our signal for the right body entered and left body entered now we also have a count on timer timeout and now here's the logic i'm trying to achieve with this that once we have scored a goal i want the ball to return to the middle of the screen and i also want our countdown timer to start ticking down and only once the countdown timer has reached zero then i want the ball to restart so for now we are not going to worry about the text displaying all of this we are just going to worry about the timer functionality and this is bringing us to kind of a problem that right now we're controlling our level scene but we do want to influence the ball which is in its own scene so we need to work across different scenes but from our level node we want to tell our ball not to move anymore at least for a certain amount of time and there are a couple of ways to achieve this the one i'm going to use is called a group which is fairly similar to a signal but with a slight difference so let me illustrate so far we have seen a signal where let's say for a timer where you send a signal from one node to the other so let's say from our count on timer node to our level node or from our area to denote to our level node so we always start from one node and go to the other node and for a group we are still starting at a single node however now we can target as many nodes as we want so any node that is inside of a specific group can be targeted and what this is really useful is that it doesn't matter where the node is so it could be in a different scene it could be inside of a scene of another scene it doesn't matter as long as the node is inside of a specific group we can always target it no matter where it is so what i'm going to do is to put our ball inside of a group and then from our level scene i'm going to target that group and then this group is going to tell the ball to execute certain functions so let's actually implement this so here i'm back in my code and let me just quickly save okay and now i want to open my ball scene so i click on ball and click on the little film icon and here we have our ball again and i still have the notes section open that is next to the inspector so far we looked at signals now i want to click on groups and then here all we can see is manage groups we can type some text in here and click on add and if you have a node selected in here like i have for ball and i can type in a name in here let's say ball group i can click on add and now our ball is inside of the ball group which you can see from this icon next to the note it's a circle inside of a square bit of a random icon but who cares so now what this means is that this node is inside of a group and whenever we target this group we could also target the node itself and how this most specifically works is that we're going to give this node a specific function let's say we're going to give it a function that i'm going to call stop ball and all that this function does is it sets this speed to zero so all we need is speed equal zero and then inside of our move and collide function if we multiply velocity and delta by zero it is going to be zero so the ball would stop moving so exactly what we want so now we have to figure out how to call this double function from our level script so i go back to our level script actually let me save the script first just to be sure so what i want to do is when either of these two areas are being hit i want to call the stop function and for that we need two commands the first one is get three and the second one is call group and in here we could pass in the name of the group and the method we want to call so in my case this is ball group and stop how do i call it stop ball stop ball so i think this entire part kind of makes sense we are calling a group and we have the name of the group and the method we want to call inside of this group so why do we need get tree and this i can actually illustrate so let me run the game right now and let's hope it doesn't crash yeah okay so the ball actually stops in the middle so we know it's working but while the game is running if you look to our scene 3 you can right now see local and remote and you can click on this still while the game is running and it shows our game and all the notes inside of our game in real time so you can see all the notes inside of the game while the game is running and here you can see a root note and only then our level note and this entire thing is our scene tree for the entire game and obviously it's still a fairly simple one but what we actually want to get is this root node that will get access to the entire tree while the game is running and this is what get tree is doing that it gets us the entire tree and from there we can access specific functions like calling a group which we couldn't do just from a specific note by itself so i hope that makes sense but we're making progress because the ball is stopping indeed so that's quite nice this has to be called on both sides of the field and with that we can start talking about restarting the ball and this works in basically the same way so i go back to my ball and in here i want to create another function that i'm going to call let's call it restart all and in here we could just set speed back to 600 but i don't think this would be enough and the reason for that is quite simple that if we were to restart the ball like this it would still point in the same direction so if the ball is going to top right and then hits the end of the field it will restart to the top right which would get really predictable so not only do i want to set the speed again to 600 i also want to restart the velocity and get different random values and i can literally just copy and paste them and now i would get new values when i restart the ball so quite straightforward and now again we have to call the group to restart this function and if you want to challenge yourself this should be doable if you got this far so try this for yourself but really all you have to do let me save this one again we need to call this function in a very similar way compared to this but i only want to do this once the timer has run out so this has to be inside of this countdown timer and now instead of stop ball i want to have start ball i think restart what i called it i'm terrible with naming functions but okay so now whenever this time has run out we're going to call this group and called the restart ball function so there's one more thing we need that we have to start this timer so whenever the ball has set either of the fields we want to start the timer and once the timer has finished we want to call this group so we have to figure out how to start this timer and that is actually super easy so all we need is to first target the node of the timer which again you do with the dollar sign and what you can also do is just drag and drop the node next to dollar sign and there you would get the name of the node this time in quotation marks but that is the same outcome so if you typed it with quotation marks or without it's the same thing they both result in the same thing that you are getting the note and now to start the timer all we need is start and let me copy this to both sides and now this should be working so let's try so we have the ball here and let me and there we go this is working so let me lose again and wait a bit and there we go so the ball is restarting after about two seconds over however long it takes so cool seems quite all right there's one thing we could be doing that right now we're duplicating code here quite substantially so instead what i'm going to do is create a new function um let me put it all the way at the bottom and that is to create a new function let's call it score achieved and in here all we have to do is copy this entire line or even cut it and then inside of each of these signals i just want to call this so score achieved and score achieved so now if you want to influence either of these we just have to work with this function and this doesn't duplicate code so quite a bit nicer but all right now we have a basic timer and all we need now is to display this timer and this is going to be another label so i have a player score right now and an opponent score i want to add another label so i select the level note and add another label that i'm going to call countdown timer alright i already have one um let's call it count down label that feels better and i'm gonna put it right to the other labels and the really important part here is that all of these labels are above all of the other notes in the scene tree especially the ball so i want the ball to be above the countdown label in the actual game otherwise i think it would look quite a bit weird that we have text over the ball okay now we have our countdown label and for now let me just write in here countdown and move it to the middle of the screen so again i click on layout i click on full rect to select the entire viewport and now i align it to the center and to the center and now with the margin i just move it up a tiny bit um i guess here seems fine it's fairly subjective whatever you feel like it looks good could also be at the bottom could be anywhere whatever you fancy and again we have to give this a custom font to match it with the other two pieces of text we have so i go to custom font get to dynamic font then get to font again it's quite click intensive and then drag and drop our font in there and i'm going to make this um let's go with 50. um yeah i think that seems fine and now this one got a slightly different color [Music] so again under custom colors i click on font color and this time let me demonstrate another way to pick a color and that is this color picker here so if you click on this godot lets you just pick another color maybe not the background let me use the white color here so if you just use this you can literally select any color on the screen and what i want to do is i want to select the color of the ball which right now we can't do because there's the collision shape above the ball so i go to the ball scene and just make this invisible and here's an important thing just because the shape is invisible does not mean it's not there anymore you just can't see it but for collision shape you can never see it anyway so it doesn't matter if you actually wanted to disable it you would have to go to disabled and click this on on but just because it's invisible doesn't mean it's not there so be aware of that but now with this one disabled we can actually see the color of our ball and now i can just go back to font color and just pick the color of the ball which is this orange red-ish color and all right this seems alright but now we have to figure out how to display this text only if the countdown timer is running and how to get the text of the count on time and for that we have to go back to our code and in here there are two things we need to work on number one is that we actually displayed the time left within our countdown label and this happens in the process function because we want to continuously do this on every single frame of our game so in here i want to target our countdown label and i want to set the text now what i want for the text is how much time is left for the timer and this we can target quite easily all we need is the countdown timer itself and it has an attribute called time left so this is how much time is left after the timer has started but there are two problems with this right now number one is that this is a number so as always we have to use the string method just like with the other labels oh and let me do this properly there we go but there is going to be another problem and i think if i run this code this should demonstrate it quite well meaning that we have a lot of numbers after the digit which well isn't great and this is another thing with data types that so far we have only seen integers which is numbers without a decimal point numbers with a decimal point are called floating point numbers or floats in short and while floats can be generally quite useful in this case we really don't want them so we want to convert the float of our count on time at time left to an integer which we can do really easily by using the in method which just takes a float and turns it into an integer so that's all we have to do in our code editor so before count on timer i type int and then i just copy and paste or cut the entire thing in there and now if i'm running this we can see let me lose one there we go and all of this is starting again but now right now it starts at one and goes to zero and this seems quite weird so i'm going to add one to this so just plus one and now two one and then we start and yeah i think that seems okay so there's one more thing we need to do that now when the timer is not running or when a timer has finished we want to hide this text because we don't need it anymore and this we can also do really easily so once the timer has run out i want to target the note again so count on timer and i want to target the visibility which you can see down here and there's visible and you can switch it on and off so i can go visible and this is going to be false false and here again this is directly using a boolean so far whenever we used an if statement we implicitly used a boolean so let me go with this one here if this value existed this line would be true but we can use boolean values immediately so you can use false and true in cases like this so if something is on it's true something is off it's false and what i want to do for our timer is that when the timer is running out we want to set this to false however when we are scoring a goal i want to set this to be true again so once the score is achieved i also want to set the countdown timer dot visible is equal to true and then by default i want this to be off so we can't see it when the scene is starting and let's try all of this so we are in our game again we can't see it by default and let me lose and the game crashes and the game crashes for a very simple reason targeting the count on timer i need to target the countdown label and the countdown timer is always invisible so this one wouldn't make sense so count on label and now this should be working so now let's start off this again and two one and go and there we go we have our countdown label so seems quite good now we are basically done with the entire game and we already have the really basic setup all that's really left to do is a couple of fine tuning things and adding the sound and that's going to be coming in the next part so adding the sounds is a really simple thing to do we just have to add a couple of notes and then it's basically done it's as easy as that but besides that we have to add another thing and this is something you have seen earlier a tiny bit that because we are moving with physics it can happen if the ball hits a pedal at a certain angle that the pedal is moving which i want to avoid and my fix for this is going to be the simplest one i can think of and all i'm really going to do is to reset the pedals on each side every time a score is being achieved so if a pedal is being moved to his side during the game it is going to be reset once the game restarts and that is just a couple of lines of code nothing fancy so let's start with the sound that's the much easier part and let's actually jump right in so here we're back in our level scene and what i want to add is a couple of sounds i want to add a sound to the ball that if the ball hits either of the pedal or with either of the walls then i want to play one sound and if a score is being achieved then i want to play another sound so let's start with the sound of achieving a score so with our level selected i'm going to add another note and the note we need is called an audio stream player and when you type just audio stream audio stream player you can see we have an audio stream player an audio stream player 2d and an audio stream player 3d and now you might be wondering why do we need spatial awareness for our sound and the answer is quite simple think of if you have a 3d scene you might have sound behind a wall or really far away and if that's the case you want the sound to be less loud same for 2d if the sound is really far away you want it to be less loud whereas for audio stream player this one doesn't care about space it will always have the same volume so this is what we need so i click on create and i want this to be score it's called score sound and in our asset folder we have a couple of sounds we have 8 bit beep and 8-bit blob let me drag this up a bit so beep and blob the score sound had to plop sound so all i have to do is to drag and drop this file into the stream and here you can preview this thing you have playing and auto play playing means it is literally playing all the time auto play means it's starting when the game is starting so if you want to click on play you can hear the sound right now and let me click on it and you should be able to hear a very long and monotonous sound which well is not intended and what is happening here is that godot is repeating the sound all the time whereas we only want to play it once and this we can achieve very easily all we have to do is to go to the import setting next to rsc3 something we haven't seen so far actually but in here you can set specific variables on how something is being imported and for otg files that's a sound format you can click on loop so is this file being imported as a loop or just as one specific sound and i want this to be one specific sound so i deselect loop and click on re-import and now we have only one sound so if i click on playing you can hear it only for a very brief period of time so exactly what we want and while we're added i also want to do the same thing for the other sound just so we have it all ready and now we have our sound all we have to do now is to play this whenever we achieve a score so for that i am going back to my code by pressing f3 and here we already have a score hd function so all we have to do in here is target our score sound and we just wanted to play so then it's going to play the sound once and let's try this and yeah i hope you can hear it it's quite short but it's definitely there cool so now we have the score sound the one thing left is we need to do the same thing for our ball so i open the bald script and in here what i want to do is whenever we have a collision i want to play the plop sound or the beep sound this one and we actually already have that so we know if this one is true we have a collision so in here we could execute the function for this but obviously we first need a node let me open the entire ball scene again and in here i'm going to add another note that is also going to be an audio string player and this one is going to be collision sound and now i want to add the beep sound and let me preview it and yeah sounds like a collision and it only plays once so now in here we can just play it so collision sound dot play and now let me run the entire game by pressing f5 [Music] and yeah this looks good um you might want to work on the sound design a bit but those i think are fine for a test game okay and we are almost done the one thing left to do is now a level scene let me open it is that whenever a score is being achieved i want to reset both of the players with a certain distance to their respective side and for this let me open the code we just have to work in this function and set the x position of each of the players so i want to target my player the position of the player and then the x position of the player and in here let me put it at 35 so it's 35 pixels from the left side of the screen and now the same for the opponent dot position dot x and we know our entire screen is 1280 pixels wide and from that i want to subtract 35 pixels and that is really all we need to do so let me run the code now and this is probably going to be a bit difficult to see you can see it very slowly but this would if we have any kind of physics mistake this is going to fix it quite drastically so with that we have a finished game
Info
Channel: Clear Code
Views: 122,087
Rating: undefined out of 5
Keywords:
Id: kr1BoEbuveI
Channel Id: undefined
Length: 127min 47sec (7667 seconds)
Published: Tue Aug 18 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.