Code Your First Complete 2D Game with Godot

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

This is an updated video tutorial for KidsCanCode's Dodge the Creeps 2D game tutorial.

I made it with his permission as part of a project to offer a complete free video course based on the docs' getting started series.

Chris made a video for it some years ago but Godot changed a lot since then, so here's an updated one.

Next week, we'll release a similar complete step-by-step tutorial for a 3D version of the game, with a jump and squash mechanic!

You can find the complete free course here: https://www.gdquest.com/tutorial/godot/learning-paths/getting-started-in-2021/

πŸ‘οΈŽ︎ 8 πŸ‘€οΈŽ︎ u/NathanGDquest πŸ“…οΈŽ︎ Apr 15 2021 πŸ—«︎ replies

Thanks so much for this, maybe now I can finally complete this tutorial πŸ’€

πŸ‘οΈŽ︎ 2 πŸ‘€οΈŽ︎ u/HiddenChar πŸ“…οΈŽ︎ Apr 15 2021 πŸ—«︎ replies
Captions
in this video you will get to create your first complete to the game with the good at game engine it's called dodge the creeps and in it you dodge aliens that spawn all around the screen this will allow us to touch on topics such as movement how to spawn enemies randomly how to handle the score a bit of interface and well the loose condition is if you touch a creep it's game over you start again i have to give credits to chris from kitscan code who initially made this project for the offshore good of documentation he has a website i recommend it early in the series and several times on the channel goodall recipes it's really great this tutorial is part of a complete free course to get started with godot you'll find a link on the screen in the description below to get all the previous lessons i assume that you watch them already please check them out if you haven't already we also have a complementary free email course that will give you more insight about good oh you can find all the details in the description below you can unsubscribe anytime no strings attached and with that let's get started with the tutorial let's now get started by downloading the starter project it contains the sprites and audio files you'll need to follow along link in the description below you have to click on the zip file here i'm going to click on it download it in my downloads directory and then i'll head to that directory to extract the archive and import the project so i prepared a good project for you but it does not contain anything other than the assets we'll need i'm going to copy the directory and open a new instance of goto here click the import button paste the path to the project and click import and edit to open it in the engine we'll first create and then code our player we wanted to interact with the monsters as we saw to do so we're going to create a new scene with an area 2d node at the root so you want to click other node and look for area 2d it's a node that can detect something within an area like your character touching another we're going to rename the node to player and we're going to add two things as a child of it we have several sprites in the art folder for the player we have four and they're here to make really little animations we can create animated sprites there's a note with the same name which we're going to create now so you can press ctrl a to create a new node as a child of the selected one and look for animated sprite to set up the animations in the inspector we have to set the frames to a new sprite frames you click on empty and create new sprite frames and when you click on the sprite frames a new editor appears in the bottom panel on the left you have the animations and we're going to have two the character looking to the right and looking up so you can click on default and you can rename that to right and we want to go in the file system tab in the alt directory and select the two player walk frames i'm going to click and drag them over the second area the animation frames to create the animation the animation will run at a speed of 5 frames per second fps and will loop automatically and you can see the character appears here as well now we're going to create a new animation by clicking the new animation icon in the left and click it to rename it to up for this one we want to select the two player up sprites and drag them into our animation frames now we can head back to the inspector on the right to set the default animation with the animation drop down here and you can set it to right to have the character look right by default with that we can click away from the character to hide the interface and you'll see in our scene we have a little warning sign so when a node is lacking configuration this will appear and you can click the message to see the problem area2d needs a component as a child a collision shape or a collision polygon it's a shape that gives the mathematical geometric form of your character from the physics engine we're going to select the player and press ctrl a to add a new collision shape 2d node so be sure to cite collision shape 2d and not collision polygon 2d collision shape 2d then needs a shape on the right in the inspector you can click on shape and create one of these geometric shapes we're going to create a capsule here capsule shape 2d it appears in the view and you have two handles that you can click to change the capsule's shape so you can click the top gizmo to make it longer and the right one to set the radius of the capsule with that we have our scene setup so we're going to get coding but first we have to save it so press ctrl s and save the file as player.tscn now we have saved the scene we can attach a script to the player node select the node click the attach script button and we are going to start with the empty template this time around you can click create all right so while first going to code the character's movement and to do so we'll instantly define a speed property by typing var speed i'll set it to 400 pixels per second this will dictate the player's movement speed now one thing we can do is make it editable in the editor in the inspector directly on our player to do so we use the export keyword before a property so around the top of your script when you save you can go back to the player node and the speed is now editable in the inspector note that when you change that value it's going to override what you have written in the script it's going to take over it and you can click the icon to reset the value to that of the script okay so back to the script i'll click on it we're going to start calculating our player's direction to do so we define the process function which is where we define how the character updates every frame and we're going to create a new variable name direction this is going to be the player's input direction and we're going to set it to vector 2.0 by default and if you remember this is equivalent to a vector with coordinates 0 0. now we want to check for the player's input and we can do so by doing if input dot is action pressed like this and use one of the predefined actions but they are not defined for for example moving with the wasd keys we're going to have to create new actions instead which we can do by going to project project settings and the input map tab there you have the predefined actions that come with your ongo project and we can create new ones by entering their name in the action field at the top so we're going to uh call them move underscore and we're going to create move right you can press enter to create the action it appears here at the bottom we're going to do move left move up and move down now for each of them we can click the plus icon next to it and select what kind of key price or input we want to map to that action key stands for the keyboard keys and we can use that to then type the key in that little pop-up it tells you what key is going to be added to the action so for move right it's going to be d for move left i'm going to add the a key move up the w key and move down the s key you can add more you could add the arrow keys and you could also add for each of them a joy access if you want to use a gamepad an xbox playstation or nintendo controller something like that but i'm going to stick to that so we can move forward all right so now we can use these actions directly in our script we can write if input dot is action pressed and we have our new move actions at the top so if we press move right we're going to set direction dot x we're going to add one to it why do we add one well because we're going to do something similar for move left and to do so we're going to select our two lines and press ctrl d to duplicate them be sure to make the indentation level match for the if keywords and the instruction inside so we can change move right to move left and then for direction we're going to set it to minus equal one so if you press left and right it's going to add one remove one you're going to be left with zero the character will not move it's one way to implement all the code direction where opposing keys are going to cancel out we can do something similar for up and down so to do so we can select you need to select up to the line before and press ctrl d to duplicate the selection and now we're going to change these instructions to check if we pressed move down to start with in that case we're going to set direction dot y we're going to add one to it because the y-axis points down in games and we're going to change the last one to move up in which case we're going to subtract 1 to the y direction be really careful that you set them right that you change the x direction when pressing move right or move left and that you change the y direction when pressing move down and up so now this gives us a direction vector which can have positive one minus one on both the x and y axes this is not enough to calculate a direction because if you are pressing right and up or down you're going to have a vector of length greater than one this happens in some games where when you press two keys you move faster going diagonally than going just up and down in most games you don't want that to happen it's almost like a bug so we're going to check if the length of the direction vector is greater than one we can type direction.length it's a method of the vector if it's greater than the one then we're going to change the direction vector there's a function to make it a length of one in any case which is the normalized method so you can type direction equals direction.normalize so if the player presses two keys at the same time and makes the vector too long we normalize it to ensure that the player moves at a constant speed regardless of the direction now we can use that to move the character so we're going to add to the position the product of direction times speed times delta and this is how you would typically move an area node note this is not the only way to code a character and we'll see how to use kinematic bodies in 3d in the next video but for now you can press f6 to test your player and you can move it with the wasd keys okay be sure to press f6 also click this icon up there to play the current scene right now there's a nasty thing that happens when we move the character away from the screen it can move away and away and away and we don't want that to happen we want to keep the player within the screen at all times to do so we can get the size of this game window here and limit the player's position to it so we're going to add a new property at the top of the script we're going to call it screen size we could set it to vector 2.0 i guess then in the ready function so when the character gets added to the game world we're going to get the screen size from the engine and to do so there's a function called get viewport wrecked gives you the viewport rectangle and this viewport rectangle has a size property which is a vector2 that gives you the size of the game viewport if you want to see it when we play the game you can print the value of the print function press f6 and you're going to see here the default size of our game is 10 24 x 600 we can now use that in the process function we're going to go back down and we're going to limit the player's position so there we can say position.x is going to be equal to there's a function called clamp which is going to limit a value between two other values so we can clamp the position.x between zero which is the the left edge of the screen the start of the game world and screen size dot x then we can do something similar for position.y it's going to be clamp position.y between zero and the screen size dot y if you play the game now you can try to move the character and it won't go outside the screen it's going to be limited so you can see it's the center point of the character to be exact if you go back to the character scene it's this point this little cross you see in the center that's going to be limited that won't be able to go out of the screen but that's better than being able to go far away now we're going to work on animations we set up our animated sprites so it would be nice to do something with it we're going to first play and stop the animation based on the character's direction so here when we're checking for the length of the direction vector if the length is greater than one means the player is pressing two keys at the same time we could change this to if direction that length is greater than zero it means that the player is pressing at least one movement key in which case we can normalize the vector it won't do anything bad and we can do something else we can play our animated sprites animation so first we need to get the animated sprite node let's say child player here and it has a method called play to play its current animation we don't have to pass any argument we'll play the current animation i want to change this bit here because we can write the getnode function to get a node but there's a shorthand for it it's the dollar sign in gd script and you can see it appears in green and this gives you the ability to get the animated sprite note it's just a shorthand for the get note function we use it a lot in gd script just because otherwise you'll get to write the get note function a ton this is a bit more readable okay so if we have a movement direction we play the animation now we can add an else clause to our condition we have to align the else keyword with the if one if we don't have a movement direction then we're going to get the animated sprite node and call the stop method on it which will stop the animation you can press f6 to test the game and if you move the character is going to animate but when you release the key the animation stops now while not using our two animations remember that we had the up and right animations so to play those we're going to add some code at the bottom of our process function we can make it so if there's a horizontal direction we play the right animation otherwise if there's a vertical direction we're going to play the up animation so let's do it like this if direction dot x is not equal to zero it means the player is pressing left or right in that case we get the animated sprite and we set its animation it's a property of the animated sprite two we're going to type write in quotes we type the exact name of the animation then we have another keyword for conditions that is l if it's the contraction of else and if and it means if this is false but the following condition we're going to write is true we're going to run my block of code you can say alif direction.y is not equal to zero if there's a vertical input we're going to set the animation to up okay so that's one more step we can play the game and see that when we press up or down the character looks up and if we press left or right the character looks right now it would be cool if the character when we press down would look down and we can do that so our sprite has some properties if i go back to the scene and select the animated sprite you can flip it using the flip h and v properties so if i click flip h it's going to look left if i click flip v it's going to flip vertically so going back to the script we can access the properties it's the same name but with underscores and if you hover a property you're going to see the name in the code in this case flip underscore h so back to the script we're going to update our conditions here if the x direction is not zero we can set the animated sprites flip h to and so we can use a boolean expression here remember i told you that these expressions we put after the if evaluate to true or false flip h is like a switch so it takes a boolean value either true or false and so we can use one of these expressions that will turn into true or false based on the expression that we write and we can say we're going to flip the character if the x direction is lower than zero if it's equal to minus one that is to say if the player is pressing the a key to go left we also want to do one thing if the character is moving horizontally want to ensure that flip v is turned off so the character is not looking down so we're going to type animated sprite dot flip v is equals to false here note that the order of these lines here really doesn't matter and finally if the character is moving down up or down we're going to do something similar to this line we're going to take the animated sprite and set flip v flip vertical we want to flip vertically if the character is moving down that is if direction dot y is greater than zero when the player is pressing the s key moving down if you do that you can now play the game and you're going to see if you move up or down the character is going to look up all down if you move left or right the character is going to look in the direction it's moving and so with that we have the character's animation and that does it for now for our player we'll add some more code later when we put the game together but we have a moving character what do we do next we need to do the monster we will now create the enemy base scene we're going to make a template that we can then generate all around the screen with code we create a new scene by going to scene new scene and we'll create another kind of node a rigidbody2d we'll rename it mob as in mmorpgs and some games the rigid body just to explain is one of the three body types in godot there's one called kinematic body one called static and rigid body basically the the rigid body you can move it with physics forces and its movement relies a lot on the physics engine the bouncing balls we had a few lessons ago were rigid bodies and here it's going to make our code fairly simple so we want our monster to have an animated sprite so select it press ctrl a and add an animated sprite node as a chart select the mob again because we're going to add a collision shape collision shape 2d like we did for the area the physics bodies all need a collision shape or collision polygon to work and later we'll add another node but we're going to set up those two already so select the animated sprite node and once again we're going to create new sprite frames and click to open the animation editor we're going to use the animations to generate enemies with different looks the first one is a flying enemy so i renamed the default animation to fly and in the art directory you will see enemy flying one and two so you can drag those we're going to create a new animation this time for the swimming enemy you have two enemy swimming frames so you click and drag them here and the last one is we'll call it walking so walk and you can select and drag the enemy walking sprites in there we will use code to select one of these animations at random when we spawn a new enemy you can now fold the sprite frames editor and we're going to set the collision shape 2d once again we want to add a capsule shape 2d to it and we're going to rotate it by 90 degrees so you have a rotate tool here you can press the e key to activate it and you can click and maintain the control key down to snap the rotation to 15 degree increments until you rotate it 90 degrees and then you can resize the capsule to match the enemy using the two handles so when the player touches that area it will die now we'll do one thing introduce a new feature called groups it's a tagging system in godot so select the mob node and next to the inspector in the node tab in the group sub tab we can add a tag to this node it's just a keyword that we can then check for in our code to find monsters to detect them or to call a function on all of them so we're going to add a new group named mobs you can press enter to add it and our scene setup is done we can get coding now so we're going to press ctrl s to save the mob scene then we attach a new script to it and you can leave the default that you have the empty template and save to mob.gd click create we're going to define some properties on our monsters that will not use directly in this script but the code that will spawn enemies randomly is going to use these properties we're going to have two and we'll export them so we can edit them in the inspector one is going to be the minimum speed and i'll expand the code editor the minimum speed let's say 150 pixels per second we can now duplicate the the line and call the next one max speed which will be 250 pixels per second here we'll write some code to change the monster's look randomly we'll use the ready function to do that which will run whenever a monster is added to the game scene and there we'll set the animated sprite to play so we can say animated sprite dot play or we could do there's also playing property that does the same thing playing equals true now we want to randomly set a monster here and what we can do for that is we're going to find a new variable mob types and it's going to be a list of our animation names in the animated sprite here so we have fly swim and walk but we don't want to hard code it we'd rather get them so later you can add more monsters you know you design more you add more animations and everything just works to do so we're going to use a function of our sprite frames we get the animated sprite node dot frames and if we go to the animated sprite this is the first property that we set here this is an object called a resource which has a method that can give us the list of animation names so we write a dot get animation names there we go so this is a list an array of our animation names it's going to look like we're going to have fly walk etc and so we can assign one of these at random to our currently playing animation we're going to get the animated sprite dot animation this is the currently playing animation is equal to we're going to access mob types and we add square brackets which allows you to index the list so you could say zero to get the first animation one to get the second two to get the third now of course if you add or remove animations the maximum number then will be different so we want to write code to dynamically select a random number based on the number of animations and here's how we can do it we call a function called rand i it generates a random number which can be very very large and so one way to get a number that is within the available map types is to use the modular sign the percentage key on your keyboard which returns the remainder of a division by the number we're going to write and that number is going to be mob types dot size this method on the mob types array returns the number of elements in the array and a modulo is going to at most give you this number -1 which is the maximum index of our array because array starts at index zero so if we have three mod types we can pass number zero one or two in the square brackets and this expression here will do that for us i'll move the monster temporarily to the center of my scene so we can see how it's working right now if we press f6 you can see it's falling automatically this is due to that rigid body which has some gravity applied to it by default to remove the gravity we set the gravity scale property down to zero then if you press f6 you're going to see every time it's the same monster so it looks like our code's not working but actually it is it's just that when you use random numbers in a computer the numbers are not exactly random they're just calculated by the computer to appear to be random to randomize the character we're going to add a temporary line just for testing called randomize it will randomize the base number the computer uses to generate pseudo random numbers and now if you press f6 every time you're going to see a different character so sometimes you'll have the same twice in a row but you can see they change okay be sure to remove that line it was just for testing and we're going to do uh one last thing while we're here so i'll place my character back to the top left by setting its transform position back to zero i reset the property in the inspector and then i'm going to add one more node to the mob it's called visibility notifier 2d this node tells you when your monster entered or left the screen and we're going to use that to delete the monster to destroy the object when it leaves the screen first you can see it's a bit hard to see but you have a pink rectangle that appears this is what the engine uses to detect entering or leaving the screen it's a bit small by default so we want to make it a bit larger to do this we're going to set the x to minus 50 the y to minus 30 minus 40 let's say and we're going to set the width and height to 180. so when this entire box is going to be outside the screen we'll use that to delete the character you can unhide the collision shape and so the visibility notifier gives you signals to do this so with the node selected we go to the node tab to the signals sub-tab and we're going to connect the screen exited signal by double clicking on it to our mob we click connect which creates a new function and when the monster exited the screen when we get the signal we're going to call a function called q3 this is a function that will free the monster from memory from the game destroying it essentially it's called q-free for technical reasons there's another function called free which instantly destroys the monster q3 is safer and lets the engine handle removing the monster at the end of the frame but with that we have our monster ready to spawn and that's what we'll do next setting up our game scene so we'll create a new scene where we'll set up our main game as the route we want to add a regular node here which we'll call main and save the scene as main.tscn we're going to start by adding some background to it i'll zoom out and add a color rectangle node we'll use the layout menu for rectangle to make the color rectangle span the entire viewport then we can set scholar to a dark gray teal here i prepared the color that we use in the final demo now the game is currently in landscape view we want to change it to be a bit more vertical to do so we're going to go to project project settings and you want to scroll down on the left until you reach display window then you can change your game's base resolution we're going to change the width to 480 and the height to 720 it's important to change it now because it will affect where we place elements on the screen we'll scroll down a bit as well down to the stretch category this controls how the game window renders as you change its size there's a mode named 2d which makes it so as you make the window bigger the rendering is also of a higher resolution that's as opposed to viewport which is going to always maintain your width and height stretching the pixels onto the game window which you use typically in 3d games but here you are going to work with 2d and for the aspect ratio we're going to set it to keep here's how it looks we're going to have a rectangle fill the entire viewport now if you try to expand the game you get black bands there's another mode called expand which will render more of the game it depends on the kind of game you are making next up we're going to create a path to randomly spawn monsters all around the screen there's a note in godot to do so it's called path 2d so select the main node and ctrl a to add a path to the node here we can use the icons at the top to create new points i'm also going to turn on the grid with the grid icon so this is grid snapping and the one next to it is the grid and by default it's a bit small so we can click the three dots next to it to configure snapping and configure the grid for the grid steps we can use a value that divides 720 and 480 our game's dimensions 40 pixels is a good one can press enter and click ok to see the grid change now we're going to click the green plus icon the one to add points at the top and then click in the top left corner click in the top right corner and fill the path clockwise like so and when you reach the bottom left corner there is an icon to close the curve so you can click it and it will complete the path if you go back to the leftmost tool this one allows you to select existing points and you can see that you have two vertices in the top left corner now it's important to create the points in this order because the orientation of the monsters will depend on the odds in which you created the path we're going to rename this to mob path this is the path along which will generate the mobs and we're going to add another node as a child of it which allows us to randomly generate a point along that path so select mod path and add a pathfollow 2d node to it this one it might be a bit hard to see in the video but you can see the cursor here the position and the properties in the inspector if i increase the unit offset the cursor moves along the path so we can easily generate a value between 0 and 1 to get a random position around the screen we'll call this node mob spawn location to visualize that a bit better actually we can add a temporary mob as a child of it and we can increase the unit offset so you can see how it moves along the path then you can delete the node we need one more node to spawn our monsters a timer so we're going to select main and add a timer node as a child of it we're going to set it to auto start and to a duration of 0.5 seconds this timer will cycle emitting its timeout signal every time it times out we will spawn a new monster so we'll call this timer mob timer so save your scene and we can get coding now you can attach a new script to main and right away we're going to connect the mob timer's timeout signal to the main node so select my timer go to the nut tab and double click the timeout signal connect it to main and this is where we'll spawn the monsters first of all we need a scene to instantiate via code so we're going to create an exported variable we'll call it mob scene this gives us an error because when you export a variable godot needs to know the type of it to give you the proper field here in the editor whether it's a text drop down those kinds of things we can give a hint of what we want to put in that mob scene by adding parentheses and we're going to use the packed scene type this is the type for your tscn files once you do that when you select the main node the mob scene field appears in the inspector there you can click and drag mod.tscn from your file system onto the property with that we can focus on spawning monsters we're going to do a few things first we're going to get a random location to spawn the monster then we'll create an instance of the monster and place it at that location and finally we'll set its velocity to move towards the player towards the other side of the screen let's start by getting the location so we'll get the mob spawn location node we're going to store the reference in a variable and we can use the dollar sign to get it here mobs1 location we can get a random position along the curve by setting its unit offset property so let's set mobspawn location dot unit offset to we're going to call the rand f function this generates a random decimal value between 0 and 1. to place the mob there we need to create a new one so we're going to create a new variable named mob and we're going to instantiate the mob scene from code so we call mobscene.instance to do that then like that the mob does not exist in the scene tree yet so we need to add it there's an agile method to do so we're going to add the mob as a child of the main node then we can assign the position we got to the mob so we're going to get mob spawn location dot position when you change the unit offset it updates the position of the pathfollow node and so you can use it to assign it to our mob then we're going to set the monsters direction we're going to rotate it to look in a certain direction and to move in that direction we can also get that rotation from the mob spawn location so we do mob spawn location dot rotation plus you saw that when we added the monster to the spawn location here it was aligned with it and as we moved along the path the monster stays aligned with it so now going back to the code we want to turn the monster by 90 degrees and that's where the order in which you created the point matters if we add pi out of two it's going to turn 90 degrees then we're going to add a random angle to that direction so we're going to add we're going to use another function which generates a random number called random range we're going to generate a value between minus pi divided by 4 so minus 45 degrees and plus pi divided by 4 which will offset the direction randomly finally we'll use that as the mob's rotation so mod rotation equals direction these four lines will randomize the monster's position and direction but it won't move just yet to move it we're going to calculate a velocity that velocity is going to be a vector 2 and we're only going to set the x-axis there we're also going to randomize the velocity so we'll use rand range again we're going to randomize it between mob dot min speed the minimum speed and mom dot max speed and on the y axis we'll use a value of zero so we have a vector pointing to the right now we're going to use the rotated method on that vector to rotate it and we can assign the result to the mob's linear velocity this is a property of rigid body 2d which will make the monster move we're going to assign it velocity dot rotated by the direction which is really a random angle with that you can already play the scene and you should see monsters spawn randomly going in various directions there is one more thing that we can add here in the ready function at the start of the game we're going to call the randomize function just so that the numbers that we generate are different every game this will make the monsters spawn differently every game there's one little thing that i forgot if we play a bit you'll see the monsters start to hit each other and get blocked we have to fix that so that has to do with the mob's properties we'll head back to the mob scene right now select the mob and in the inspector we're going to go down to collisions and we're going to remove the layer and mask this is causing the monsters to detect each other and to hit each other and once we've done that we're going to go back to main play the scene and the monsters should now go through each other we'll now complete the gameplay by adding an instance of our player to the scene click and drag the player.tscn file onto the main node to instantiate it then we're going to move it to the center and to do so you press w and click and drag w is the move tool up there if you play the scene with f6 you can't collide with the enemies right now so we need to fix that we need to add some code i also noticed that i made little mistake in the mob scene so we're going to open it double click on it and i told you to turn off the layer and the mask the collision layer and mask but we need the layer to be on for the player node to detect collisions with the monster you can then close the mob scene that's not enough though we also need to go back to the player scene and the area can detect monsters that touch it that enter it but we need to set this up so select the player node and go to the node tab signals and area provides you with signals like area entered and body entered the body entered signal detects any physics body like the monster's rigid body 2d and area entered will detect other areas overlapping with this one so want to connect body entered you we double click on it to the player node it's going to add that function at the bottom now we're going to make some changes to the code so first when an enemy touches the player we're going to hide the note there's a function to turn the visibility of the node off then we're going to deactivate its collision shape so collisions aren't detected anymore so to do so we get access to the collision shape 2d node and we're going to do something a bit special so if we select the collision shape in the inspector you can see it has a disabled property you can turn it on to disable the collider then nothing will be detected anymore now there's little particularity of physics engine which are that you can't make some changes instantly in the code sometimes so we have to call a method called set deferred and we're going to pass the property name as a string as the first argument it's going to be the disable property and we're going to set the property to true this is similar to saying collision shape 2d dot disabled equals true except that set deferred will automatically wait for the end of the physics calculation the physics frame before changing the property allowing you to change it safely and make the change work we're also going to define a signal here that we'll use later so we're going to scroll to the top of the script and define a signal named hit to know when the player was hit by something then we go back down and we're going to emit that signal when the character got hit by an enemy so we call the emit signal method we saw in the previous video and we're going to emit the hit signal we'll define one last function as well here we're going to call it start and we'll have the game code call it at the start of the game it will initialize the player if you want the start function will take a new position and we're going to set the character's position to that new position it will be passed by the game it will reset the player's position when we start the game will also show the player which allows us to hide the player when it dies then when you click play again you're going to show the player again and then we have to set collision shape 2d dot disabled equals false we need to use set daffod to turn on the disabled property but we won't have to do that when restarting the game because we won't have any physics interaction happening here when the character gets hit and that function gets called the physics engine is in the middle of calculating interactions this is why we have to call this method and that should be enough to test our gameplay so you can press f5 we're going to set the main scene as our main scene to play when we press f5 click open and let's see if i touch an enemy i disappear so the gameplay is working now we need to add some interface and to make the monsters stop spawning when we got hit so we can restart the game we're going to do a bit of interface design now so let's go back to the main scene actually we're going to create a new one i'm going to go to scene new scene and the top of the scene is going to be a special note called a canvas layer create an other node and type canvas layer to create it we're going to name it hud for heads-up display this scene will contain our interface we're going to create labels like we did before in the series so let's add a new label node we're going to add two of them so we're going to select the label and press ctrl d to duplicate it the first label is going to be for our score we're going to call it score label the second one is going to be message label it's going to be a message that will display in the center of the screen so select the score label the the score going to display around the top so we'll go to layout and we're going to have center top here well center label at the top message label we're going to center on the screen so select the node and go to layout center we're going to write the game's name in there dodge the creeps and we'll also use code to update the text and we'll set a nicer font with a bigger text size in a second for the score label we're going to set the score to zero by default and we are lacking a button select the hud node and add a new button node and the button we're also going to center on the screen so you go to layout center and then you want to move it down a bit these options the layout options anchor the nodes for example in that case relative to the center so while offsetting it from the center and with the button selected we're going to set the text to start now of course everything looks way too small the text is pretty ugly so we're going to add a different text font before configuring the nodes to align them a bit more nicely in the file system dock you have a fonts directory with a text font that we included in the project we're going to assign it to all our objects here select the school label and we're going to scroll down to where we have custom fonts here i'll just mention that the method we're going to use is fine when you just have a bit of text in your game so you can use the custom font property to set it on two or three nodes in larger games you might want to use the theme property which allows you to apply the same font and the same ui styles to many nodes at once anyway expand custom fonts and click the empty here to create a new dynamic font resource in it dynamic font is one you create from these ttf or otf vector font files okay so i'm going to create the dynamic font and click to expand it first we need to set the font um it's going to take one of these files so click and drag xone regular.ttf onto the font data and you'll see the zero up there changes it's still a bit small though so i want to expand the settings this time to change the size to something like 60 let's say seems big enough now we want to copy that font onto the other two notes to do so right click the results you're going to click copy and then select the other two nodes and you want to expand custom fonts right click and paste when you select multiple nodes you can edit them all at once and the inspector will show you all the properties that they have in common that's why some of the properties disappear as well now we want to configure our nodes to stay centered on the screen so we're going to select the score here and we're going to resize the box a bit to give it maximum space it's going to take all the width of the display in this properties we want to set align to center to center the text inside that box that's all we need to do we do it so when we add more characters the text doesn't expand to the right but stays centered and to do so we want the text box to span the entire width of the screen then we have dodge the creeps here we want to do the same so align center we're going to turn on auto wrap as well so the text wraps in the text box then you want to expand the box horizontally and you can control alt click and drag on the handles to do so and you want it to take the entire width here for the button we're going to go to layout center again to recenter it and move it down you can control shift click and drag to constrain the button when moving it down and then you can select the nodes and you can move them back up perhaps i want you a bit more down like that there you go that will be our interface with that we can save the scene to hud.tscn and get coding select the hud node and attach a new script to it in this script we're going to define a few functions that we can call from the main game to display a message to update the score we're going to start with a signal called start game we'll emit it when the player presses the start button and we can actually do this right now select the button here and in the note tab we'll connect the press signal to the hud when that happens we want to hide the button so i'll call button.height and we'll emit the start game signal then we'll add two more functions above that one to update the score so let's call it update score it's going to update the number displayed on the score label so for that we'll pass in an argument a number called score and we'll get the score label and set its text property we have the score value which is a number and we need to convert it to text using the sdr which stands for string function and passing in the score here that way the main node which is going to keep track of the current score will be able to update it in the interface you often have that separation in games the next function will do is show message and it's going to display some text in the message label because we'll want to not only display the title but game over and a message to tell the player to get ready to start so this one is going to get the message label and we're going to set its text to the text here we're also going to show it because during gameplay we'll hide it so we're going to call its show function and finally one thing we want to do is when we display a message like game over or get ready we only want to display it for a few moments to do so we'll use a timer so select the hide node and going back to the scene add a new timer node as a child of it we'll call it message timer we'll connect its timeout signal to the hud and we're going to select the node and the inspector will set its wait time to something like two seconds we don't want it to automatically start we'll control the timer from code and we want to turn on one shot before we saw that timers cycle continuously with the one shot property they will play only once until they emit the timeout signal then we won't do anything until you call their start method again from there we go back to the script and in the show message function we're going to start the timer so we get the message timer and we're going to call start on it this is a function to start the timer then in the on message timer timeout function we're going to hide the message label so we'll get the message label and call the hide method on it so when we call show message we show the label for some seconds until the timer times out where we hide the message we're going to use that function right away by adding a function to display the game over message it will write a new function called show game over that way the main node the main script can call it and handle the flow of the game and we'll call show message init and show the game over message and i guess we'll stop there for now we'll add some more code later but let's bounce back to the main game scene to add our hud and to start displaying the score and everything so click and drag hud as a child of the main here and we'll start counting and updating the score we are now going to count the score and update the score label to do so we're going to use a timer we'll increase the score every second so select the main node and create a new timer node we're going to call it score timer we leave the wait time to one second and we don't want it to o to start we'll start it when starting the game then we're going to enter main.gd the script and add a new score property which will initialize to zero this is where we start coding our new game and game over functions we're going to start with the new game function and every time we start a new game the score we want to reset it to zero this will happen when the player clicks the start button we also want at some point to start our timer so we're going to get our score timer and start it and in the game over function we want to stop the timer so function game over we're going to get the score timer as well and call it stop method then we need to increment the score to do so we're going to use the score timer's timeout signal so select the score timer node and double click its timeout signal to connect it to the main node when the score timer times out every one second we're going to add one to the score and we're going to update the score in the heads-up display remember we created an update score function and we're going to pass it the score number now we have to call our new game function somehow remember we had a start game signal on the hud triggered when the player clicks the start button we want to connect this one to our main node to start the game calling the new game function we can directly connect the signal to the new game function select hqd double click the start game signal and we're going to set the receiver method here we have to type the exact name so new game we click connect and you'll see the icon appear next to the new game function now when you play the game and you click the start button the timer should start at the top it's a bit messy because the monsters start spawning before that and we're going to address this next now we have the score working so select the mob timer and in the inspector we want to turn off o to start then we want to start it manually we're going to delay everything have a little sequence here we're going to add a new timer node as a child of main and call this one start timer we'll use it to delay the start a little bit and set its wait time say to two seconds one thing we can do a new game here is we can get the start timer and start it before we start the score timer so be sure you start the start timer first and then we're going to introduce a new keyword in gd script called yield yield allows us to wait for some node some object to emit a given signal the code will read until the yield keyword then it will pause the function until the signal gets emitted this allows us to write sequences that take some time in a linear fashion making our code readable so i'm going to get the start timer node here again and we're going to wait for its timeout signal so we start the timer we wait for it to time out and then we start the score timer i almost forgot we have to set the start timer to one shot there we also want to start the mob timer manually and i'll double check that i've turned it off right i turned the autostart off now we can play the game and click the start button wait for two seconds and then the monster starts spawning and the score starts going up two seconds a bit long so i'm going to select the start timer and lower it back down to one second anyway this shows you how you can use the yield keyword to give a sequence some time we're going to do a little more than that so before our yield call we're going to set the score back down to zero and the hud i'm going to group that with the score up there so we're going to get the a2d node and call update score with the current score which is zero this is so that when the player restarts the game the score is set back down to zero and when we start the timer we also want to show a message so we're going to get the hqd node and call it show message function we're going to call it get ready something like that then we'll wait for the start timer to timeout and start the score and monsters let's try it out i'm going to click start it says get ready and there you go the message disappears when we start the game and we can start playing before we fix the size of the player and monsters we want to call game over when the character dies there again we're going to select the player and connect its hit signal in the note tab i'm going to double click and connect it to game over on the main node for now we only stop the score timer we also want to stop the mob timer so we'll call mob timer.stop we're going to call hqt.showgameover and we can now play the game to test this out so we get ready the monsters start spawning the score appears when we die we get game over and the score stays like this our function to show the game over doesn't reset the game yet but we'll get to it next before that i want to fix the huge size on the characters and the monsters because it makes the game really hard to play the player is really too big and so are the monsters really to do that we're going to open the player scene and we want to set the size of the animated sprite and collision shape to something smaller so i'll select the animated sprite scale it to 0.5 0.5 have to go to the transform section to do so then for the collision shape 2d we manually scale it down to the character's size there you go now it's at a reasonable size you could scale the player node directly but it's something that's not recommended with physics there are some cases where scaling a lot of nodes including physics shapes like that can cause some issues at least it was the case in the past so better size the other nodes properly then we're going to open the mob tscn for the monster we're not going to reduce the size as much so i'm going to set the scale of the sprite to 0.7.7 i guess and for the collision shape we resize it manually we don't really have to worry about the visibility rectangle because all we care is that when the rectangle left the game window completely the monster will be destroyed anyway you can now press f5 to try the game again and see the monsters have a more reasonable size we could increase the frequency at which they spawn or tweak other gameplay settings like their speed or something like that to control the difficulty now next we have to complete the game over allowing us to restart the game let's go back to the main scene and to the hud to be exact we're going to just open the script to complete the showgamer function so right now we just show a message and when the message timer times out the message label gets hidden here we're going to wait for the message timer to timeout and display the game's title again we can say yield we're going to get the message timer and wait for its timeout signal so as i explain the function will pause here until the message timer emits the timeout signal then the execution will continue we're going to set the message labels text to our game title again it's dodge the creeps then the message timer is going to hide the message label so after it did that we're going to make it visible again we can call it show method to be consistent with the rest of our code and finally we're going to wait for a little bit of time and next show the start button again so this will give us a nice sequence of events and i want to show you another technique here we can use the yield keyword we can also create timers in code and wait for that timeout signal to do so you have to call get tree this is going to get the object that represents your entire scene tree here this tree has a function called create timer and you can create a timer of a given duration so we're going to create a one second timer these timers are one shot they don't cycle then they have a timeout signal which we can wait for using the yield keyword so when you do that it's like a throwaway timer it will run for one second emit the timeout signal and then disappear it's gone forever but it's really convenient when you are coding something and you don't want to add new timers to your scene tree and so when it times out we show the button again the button which will allow the player to restart the game so let's test that we click start i need to die really quickly oh wait for the game over dodge the creeps comes back and we can start again and if we click start the monsters stay there right so we need to do a few more things to complete the game we need to destroy all the monsters when we restart the game to start from a clean slate we have to place the player again at the start like to reset them to show them again to restart the gameplay and perhaps when we start the game we don't want to have the player behind the text we want it hidden outside of the screen or something like that so we'll do all that right now first destroying all the monsters to do that we go back to the main script to the new game function and around the top we're going to use the group features we used on the monsters to delete them all the access to group happens with the scene tree object we use to create the timer so we have to call get tree to get that object the scene tree and it has a function called call group it takes the name of a group if i go back to the mob scene remember we had a group named mobs in lower case so we're going to pass it the name of that group mobs be careful to spell it right and then we call a function on all nodes that are part of the group we're going to call q3 this will cause all monsters to be destroyed when the player restarts the game we also want to call the start function we created on the player earlier so we'll call player.start and want to pass it a given position we're going to add a new node in the main scene which will be the player's spawning point so here's what we'll do we select the player and move it outside the screen then we're going to add a new node as a child of main and there's one called position 2d which gives you a little cross that's visual in the editor we'll call this one start position and head back to the main script to get that start position so we get the start position node and pass its position to the player why do we create a new node well it's because during gameplay the player is going to move so then if you want to reset its position you need a fixed thing and that node gives us just that plus it's nicely editable in the editor let's try the game now we're going to call start and we can move we die we wait for a bit for the button to appear we call start the monsters disappear the character gets re-centered i have one last thing to do you can see that at the start of the game the player was visible so we're going to open the script and in ready we're going to call the hide function and that completes our main game loop what do we have left music we don't have any sound in the game so we're going to add some music you will find two sounds in the r directory one is a music loop and the other is a game over sound so we're going to use both of these to play music you use nodes in godot as well so we'll select the main node and add a new audio stream player it plays an audio file we'll create that node and call this one music we'll also need one for the game over sound because you can't assign multiple sounds to one of these nodes so let's duplicate it with ctrl d and we'll name this one def sound okay so select the music node we're going to assign it the house in the forest.og file you place it in its stream property and for the dev sound you're going to click and drag game over over the stream property they both have a play function that we can call from code so we'll do just that open the main script and at the end of the new game function we're going to play the music we can do it before starting the start timer here we're going to get the music node and call its play function then we're gonna go to game over and on game over we'll get the death sound and play the dev sound but we also want to stop the music otherwise the two will play at the same time so we get the music node and call it stop function you can see the pattern where all the things you can play and pause in godot have these play and stop method whether it's for animation timers those kinds of things now i'm just going to open the audio tab at the bottom this is where you can find the audio channels and i'm going to mute it just for the recording and play the game but you can play and everything should be fine now you should have the complete game with the music playing if you followed all the steps until there so we have a game over the game over sound plays dodge the creep restarts we can press start the player goes back to the center the score resets to zero there you go you made a complete game from scratch let's say 2d1 and this has been an opportunity to see lots of things you've done procedural generation you've done some interface design movement testing collisions using different kinds of physics buddies congratulations and thank you for following until here there's a next video coming which will show you how to create a complete 3d game from scratch people are often afraid of 3d but you'll see that a lot of the code is very similar if you like this tutorial you will surely like our complete free email series it's a complimentary course to this one where i give more insights about game development goto resources to check out you can find the link on the screen in the description below be sure to also subscribe and i'll see you next week when you'll do your first 3d game from scratch see you then
Info
Channel: GDQuest
Views: 64,337
Rating: undefined out of 5
Keywords: godot 2d game tutorial, godot getting started, godot tutorial for beginners, godot tutorial 2d, make your first 2d game, godot 2d tutorial for beginners, godot tutorial
Id: WEt2JHEe-do
Channel Id: undefined
Length: 71min 36sec (4296 seconds)
Published: Thu Apr 15 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.