Create Your First Complete 3D Game with Godot

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

This is the last tutorial of our Getting Started with Godot in 2021 free course, an enhanced video version of the new docs' getting started series.

In this 1:30 video, you'll get to create a complete 3D game from start to finish.

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

Thanks for all the work you do! Your tutorials are very helpful.

πŸ‘οΈŽ︎ 3 πŸ‘€οΈŽ︎ u/Zalmerogo πŸ“…οΈŽ︎ Apr 22 2021 πŸ—«︎ replies

Very nice.

normalized() can also be called if the vector is zero; then it will just stay zero. This is not documented but I noticed it in the source code.

πŸ‘οΈŽ︎ 2 πŸ‘€οΈŽ︎ u/G-Brain πŸ“…οΈŽ︎ Apr 23 2021 πŸ—«︎ replies

Retry screen opacity: 69.

πŸ‘οΈŽ︎ 1 πŸ‘€οΈŽ︎ u/G-Brain πŸ“…οΈŽ︎ Apr 23 2021 πŸ—«︎ replies
Captions
in this beginner friendly tutorial you're going to create a complete game from scratch with godot in 3d it is similar to the one we did last week and on purpose first it's not exactly the same game the mechanics are a bit different as you have to squash enemies and you'll get to learn new good of features but then having similar games will help you see how similar 2d and 3d game code can be it's mostly the movement code that gets really different in this video you'll set up a scene with a light a camera and world environment you'll get to spawn monsters procedurally around the game area you'll code a jump and squash mechanic making use of the third dimension and you'll also learn to create animations directly in godot with its animation editor this video is sponsored over getting started with godown 2021 series i assume you watched all the previous tutorials so if you haven't already you can find a link to the course in the description it's entirely free we also have a complimentary email series in which you will get more insights to get started with game development in general this is completely free you can unsubscribe anytime and there again you'll find the link in the description below with that let's get started to follow along you'll need to download and import the starter project in godot you'll find a link to it in the description below to download it click the 3dsquashthecrepes.zip file i'm going to save it in my downloads directory and there i need to extract the zip archive to do so i right click and click extract here here on linux and we want to import the project in godot i'm going to copy the path to the directory and in a new workspace i'll open good old click the import button paste the path and click import and edit in the starter project in the file system tab you'll find two directories fonts contains one text font we'll use for the interface and art contains two models with the glb extensions which is the gltf 3d model format some materials that go along with the models and a soundtrack with that we can get started creating the game scene we'll start by creating the main scene with the floor on which the characters will evolve we want a plane node as the root so click the other node button and add a regular node we're going to name it main then for the ground we want something that can detect collisions and prevent characters from falling through the floor there's a node named static body to do so so we'll press ctrl a and add a static body node the 3d nodes unlike the 2d ones don't have the mentioned 2d at the end and they have a red icon so click create to create your static body and we're going to rename it to ground a static body node needs a collision shape just like the area 2d we created until now or kinematic body 2d press ctrl a and add a collision shape as a child of it collision shape is like collision shape 2d except it's in 3d so it allows you to create a geometric 3d form that the physics engine will use for collisions in the shape slot in the inspector click the empty and create a new box shape you can resize this one by clicking on the three handles or you can click the box shape to expand it and change its extents property we're going to set the x extends to 30 meters why we're going to leave it at 1 and for z we're also going to use 30 meters a note about the 3d axis the floor is defined by the x and z axes x would be horizontal and z would be the depth axis and like in 2d the y-axis is for up and down notice a difference though is that the y-axis points up so it's positive going up also the dimensions of your game are in meters in 3d we're going to select the ground node and add a 3d mesh to it because we have the collision shape but it's going to be invisible in the game select the ground node press ctrl a to add a mesh instance node this allows you to create cubes and things like these 3d primitives click the mesh slot in the inspector to create a new cube mesh this is the one you use for that kind of slab here you can click the mesh to expand its properties and we're going to set its size this time it's not the extent so we have to double the values compared to the collision shape 60 on the x-axis 2 on the y-axis and 60 on the z axis and you can see this time it creates an opaque slab that is kind of hiding the grid behind it we're going to select the ground and move it down so it's right below the grid so we still have it visible can press the ctrl key while clicking and dragging to move by one meter increments then right now it shows as gray to make it visible to change the color in a sense we have to add a light in 3d the 3d engine uses light information to change how things are presented to you and so without lighting things might appear like all in the shadow select the main node and add a new directional light node this is one we typically use to represent the sun it's a light that emits uniformly in the same direction you're going to move it up using the move gizmo and we can rotate it by using the aux the blue or the red one here i have to use the middle mouse click to see the direction in which the light is pointing which is represented by this arrow i'm going to click and drag on the red circle to turn the light and you can see already that your slab becomes white we want it to cast shadow so we're going to expand the shadow section in the inspector and turn on enabled we're not going to see the difference but when we add the characters etc they will cast a shadow and that's all we have to do for this scene so save it as main.tscn and next we'll get to work on the player let's create the player c next go to scene new scene and we're going to create a kinematic body as the root so click other node and look for kinematic body press enter this body type is the third one we haven't seen yet in the previous video we saw rigid body and area the rigid body is one that relies on the physics engine to update the forces that are applied to the body area you can detect things that touch it but it doesn't detect collisions it won't be stopped by a wall kinematic body is in between the two it's one you use when you want full control over your character's movement you use it to code the controls in a very fine grained way we're going to rename the node to player and we're going to start by adding the player model but we'll do something special here press ctrl a to add a spatial node this is like no 2d but for 3d and we'll rename this one to pivot and i'll show you in a second why we do that we're going to open the r directory and click and drag the player.glb file onto the pivot node it's going to create an instance of the 3d model in the scene now what's that thing with the pivot well we can move the character model right above the floor so it's not going to clip with the floor we created in the main scene we can then use the pivot to rotate and move the character relative to a pivot point we'll use that to animate the character later on and have it curve as well when jumping then select the player node it's lacking a collision shape so we add a collision shape node here we're going to add a sphere shape in the inspector click and create a new sphere shape at the bottom you can change its size and we want to move it up a bit so you can press w key to bring the move gizmo and move the shape up a bit you can have the shape go a bit above the character no problem you just want to make sure that the bottom kind of aligns with the bottom of the character i'm also going to move the pivot node up a bit so the characters really above the grid as we're going to have an overhead camera it doesn't matter too much that there is a tiny bit of space down there between the player model and the floor because we won't notice it at runtime we have everything we need to code the player movement except for the input map which we're going to set up right now so save the player scene as player.tscn and go to project project settings input map to create an action you type its name in the bar at the top we're going to create fall like in a previous video move left press enter move right and then the last ones will be move forward and move back and the final one because we'll have jump support in that game so we'll create an action for jump i'm going to do a minimal setup to move forward with the tutorial but you can add multiple keys for each of them if you'd like i will map the wasd keys to the move inputs and space to jump click the plus sign key and press the key and okay to add a key mapping to the corresponding action for move right i'm going to press d for move forward we're going to have w and move back we're going to have s for the jump i'm going to use the space key and i'll stop there but don't hesitate to add mappings for a game controller or more keys like the arrow keys if you'd like okay you can close it now now you can attach a script to the player by selecting the node clicking the button in the top right of the scene dock and we're going to create a script with the empty template and leave the default path click create to head to the script editor i'll expand the script editor by pressing ctrl shift f11 and we'll start by defining the few properties we'll use to move our character it's going to have a speed a jump false let's say and some fall acceleration some gravity applied to it we're going to create exported variables for each of those so we can edit them in the inspector in the editor the first exported variable is going to be speed and we're going to set it to 14 meters per second the second variable i called it jump underscore impulse and it has a value of 20. it's a value will add to the character's y velocity to make it jump and then the next variable will pull it back down over time so i'll create a new exported variable called fall acceleration you could call it gravity if you prefer and we're going to set it to 75.0 you'll see how these work as we create the script and test the movement but we have one more to create a variable for the velocity so this one will be a regular variable because we'll update it from the code and we're going to set it by default to vector3.0 in the previous video we were working in 2d with vector2 objects in 3d we use vector3 to move the character we're going to introduce the physics process function so type it underscore physics process this one is similar to the process function except it's the one you should use for physics objects like the player you want to use that to move it for the area we didn't really need to but whenever you're going to use a rigid body or kinematic body and in some cases the area or other physics nodes you need to use physics process this one gets called at regular time intervals 60 times per second by default and this allows the game to keep the physics consistent even if for some reason the computer slows down the player has a lag spike the physics are going to stay consistent the problem with process is if you have a freeze in your game and the player's computer freezes for one second the next frame the character might move so far that they might move through walls through the floor and things like these and with physics we don't want that to happen so we use a different approach to updating the physics bodies like before we're going to calculate the direction i'll go really quickly through this one so we're going to create a direction variable it's going to be initialized to vector vector3.0 and we're going to use conditions to change the x and z axes which are the floor axis here i'm going to say if input dot is action pressed we're going to start with move right so if we press move right we're going to set direction dot x we're going to add one to it i'm going to select these two lines and duplicate them three times to edit the lines that are a bit similar so let's finish for the horizontal axis we're going to check if the player pressed move left then we're going to subtract 1 to the x direction now we're dealing with the z-axis the depth axis if the player presses move back we want to add one to the z-axis if the player presses move forward we want to subtract 1 to the z axis double check that here you do change direction.z and not direction.x and double check your add equal and minus equal how do i know that you want to add one for move back and remove one for move forward i invite you to test it this is based on how i place the camera in the game so this depends on how you set up the game you just want to test it after coding the movement and adjust if you need to like before if the direction vector is greater than 0 if it's not equal to vector 3.0 we're going to normalize it because if we move diagonally we might get the character moving faster than if we just move forward or on one axis so i'm going to say if direction is not equal to vector 3 dot 0 its default value then we're going to say direction equals direction dot normalized this ensures that the vector always has a length of one unit we will then update the velocity so we'll say velocity.x is equal to direction dot x times speed and velocity.z is equal to direction dot z times speed we have to break this into two lines because we're going to calculate the y velocity separately and update it every frame with the fall acceleration in other cases you can totally do a multiplication between a vector and a decimal value something like that velocity equals direction time speed would multiply the x y and z direction by the speed value but again as i told you we want to treat the y axis differently so we don't want to multiply it by speed at this point we can move the character by calling the move and slide function it's one of the methods of the kinematic body class which we use for the character which is quite convenient to move the character it will automatically smoothly collide and slide against walls other characters etc so it really helps you code your game movement faster and this function requires a velocity vector which is our velocity and it requires also the up direction vector and for us in our game it's going to be vector 3 dot up a constant that corresponds to the y axis pointing up this function if i control click on it you're going to see in the documentation that it returns a vector 3. that's what the underlying vector3 means and that value is a new velocity that's updated after taking into account collisions so we're going to get that value and assign it to our velocity variable you don't always have to do that but it allows you if your character kind of slides a bit against something it might lose a bit of its momentum and move and slide we'll calculate that and return the new velocity with that loss in momentum okay so with that we can already try and we'll later add the jump so i'll return to the normal view and go back to the main scene press ctrl f2 to go to the 3d view and we want to i'll fold the art folder and instantiate the player in the scene so you can click and drag it onto the scene or as a child of main so it appears in the center in 3d we must create a camera to view the game because otherwise the rendering engine doesn't know from which angle we want to see the character so we'll also select main ctrl a and add a camera node and this camera you want to move it around you'll see that by default it looks along the z axis negatively we can use the trick to place the camera and look down at the player we're going to create a new node like we did with our character's pivot select main control a and create a regular spatial node we'll name it camera pivot and we're going to place the camera as a child a bit this will make it so the camera moves relative to the pivot then look at what we can do i'm going to reset the transform because i move the camera a bit and i'm going to move it on the z-axis away from the character then you can select the camera pivot and look at what happens when you rotate it so i press e and i click and drag on the red circle and the camera moves along a much larger circle this time around so this is really nice really helpful to place objects okay so select the camera again and we're going to change its settings a bit you can press ctrl alt 2 to split your viewport into two and you can click the preview check box to see how you're going to render the game from the camera view want to do a few things here first in the camera you have a setting name projection and in 3d you have two available perspective and orthogonal well two main ones at least perspective is going to give you depth and make further objects look really distant from the camera while the orthographic mode is going to kind of squash everything make it look like isometric games we're going to use orthogonal when you do that you need to set the size of the camera to see well through the game because you can see it looks really zoomed in right now we're going to set the size to 19 units it might look a bit squash right now but once we finish setting up the game the view will be a bit square like that and so you should get roughly these proportions on the screen we're going to set the camera to current this is going to tell godot that we want to use this camera to view the game the last camera that has this property set from the editor or the code will be the active camera in your game finally i'm going to use the same transform as i used in the final project it was set to 19 units on the z-axis i'm going to go back and press ctrl 1 to go back to a single view and that is our camera setup we can now press the f5 key and select our main scene to start testing our character's movement so you can press wasd and you'll see the character moves in different directions we're going to do two more things we're going to make the character jump and fall smoothly and we'll make it also look in the direction it is moving press f8 to stop the game and go back to the player scene and click the player script to go back to it let's start with the view direction where we check that the direction is not zero while essentially checking if the player is pressing some direction keys if there are we can update the character's angle to look in a certain direction and we can do that using our pivot node in the scene so we're going to get the pivot node and we're going to call a function on it called look at this is a function that's going to turn your character or the node to look at a certain point in space in 3d you don't get the position of a character at least in goodwill 3.3 you write translation instead this is a property that represents where your character is it's positioned essentially relative to its parent and we're going to add the direction vector to it the reason we have to take the player's translation into account is that the lookout function requires what is called a global position this is the position of the player relative to the origin of the world so the point where the axes cross here and we can get it by using the translation property in this game then the function requires a second argument so here we start to see the extra complexity of 3d where we have to tell the functions what is the up direction and once again it's vector3 dot up you can press f5 to test the character and now you will see it turns to look in the direction it is moving okay one more step we're now going to implement jumping in the game so after we calculate the floor velocity we're going to use a condition to know if the character can jump we first have to ensure that the character is on the floor we don't want to be able to jump mid air so that would allow the player to jump and jump and jump again so we want to know if they are really touching the floor right now there is a method on kinematic body 2d which is called is on floor this will return the value true if the character is touching the floor right now we can then use the end keyword to check this first condition and the second one and they both have to be true for the code to execute and this condition will be input dot is action pressed and we're checking for the jump key if that is the case we can add our jump impulse to the velocity's y axis so we'll have to put dot y velocity dot y plus equals jump impulse that's not enough because this is going to make the character go up but we need it to go back down and the way we do that is using something called the kinematic equations in math which are simple equations that allow us to make things move and fall smoothly this is something you might have learned in high school or middle school under the form of newton's physics equations so we're going to subtract the fall acceleration every frame to the velocity dot y multiplied by delta this is often a question why do we multiply by delta here why don't we multiply the velocity by delta so i'll explain that right now before we test our final acceleration is an acceleration in meters per second squared the velocity is a speed in a given direction in meters per second when you make operations with a velocity and an acceleration for example you need the units to match and so we need to multiply our acceleration which is divided by second squared by a time interval in seconds to make it a speed difference for this frame and integrate it into our velocity now when you call move and slide we don't use delta we don't multiply the velocity by delta because the move and slide function is going to do it for us internally so to know that you would have to read its documentation i'll click it so you can see because there are quite a few details about how this work and how you can configure the movement it can really do quite a few things and this explains this detail now our character is ready to jump so we can press f5 move and jump and you'll see it jump smoothly and stops on the floor the fact that we are assigning the velocity return by move and slide to our velocity variable also makes it so that when the character touches the floor its velocity gets reset to zero so that every frame we can if it's in the air it's going to accelerate but as soon as it touches the floor it loses that vertical momentum and this prevents it from accumulating speed and eventually moving through the floor but with that we have the bass player movement and next we'll move on to designing the monster alright so next we're going to work on the monster i'm going to close the player scene and create a new scene which will use a kinematic body as its root this time while changing things for the mob we are using a kinematic body to control it you'll see it will work similarly to the rigid body let's rename the node to mob and i'll save the scene right away just so saving is done and we're going to have a setup similar to the player character we add a spatial node that will rename to pivot and that will use for animation and as a child of it we're going to click and drag mob glb which will instantiate the mob's model i'm going to move it up a bit by default so it's above the grid there we go and again remember that pivot node allows us to change the pivot of the monster basically then we will add the collision shape for the kinematic body 2d so let's add a collision shape node and this time we're going to use a box for the monster so let's go to the shape property and create a new box shape why do we use a box well because we want to be able to squash the monster and the box has a flat surface it will make it easy to detect if we fell on the monster or we hit it from the front well here's a trick to do that in an upcoming video so you want to size and place the box so it roughly encompasses the monster horizontally and in terms of depth and on the height you want it to reach roughly the the eye of the monster like that we will adjust it later when play testing the game like in the 2d tutorial we're going to use a visibility notifier node to delete the monster to destroy it when it leaves the camera view so press ctrl a to add a visibility notifier as a child of the mob node this one we want to make it encompass the mob completely so we're going to use the handles to scale the node so it's even a bit bigger than the mob it doesn't matter too much the node will just cause the monster to get destroyed when this entire box leaves the camera view we have the scene setup for now i'm going to add a new script to the mob mob.gd make sure it's empty and first of all we're going to connect our visibility notifier to the mob node select the node go to the node and signals tab and connect its screen exited signal to the mob node when the monster leaves the screen we're going to call q3 to delete it okay now we're going to code the monster's movement i'm going to close the player script to focus on the monster we're going to have monsters have a random velocity within a range so for that we're going to define two exported variables so we can edit them in the inspector minimum speed it's going to be 10 meters per second and i'll duplicate the line with control d to add a variable named max speed and i'll set it to 18 meters per second unlike the rigid body we used in the previous video which had a linear velocity property our kinematic body does not so we're going to create that property we write a new variable named velocity and initialize it to vector3 vector3.0 a rigidbody also moves automatically if you give it a linear velocity but it's not the case for a kinematic body we have to code its movement so we're going to define the physics process function and in this function we're going to call move and slide using our velocity vector this will replicate this behavior we had where we set the velocity once and the monster will move at a constant speed until it leaves the screen and gets destroyed we're going to do a little thing you might see these warnings appear in the bottom right of the view these are just warning there are not errors in your code but they're there to help you keep your code clean or avoid forgetting common things one is that when you don't use a function's argument typically you put a leading underscore to tell the compiler that this is intentional so we'll do this when you save you will see you'll have one less warning anyway we're going to code a function to initialize the monster set its start position have it look towards the player and give it a random speed in the previous video we did that in the main node this would be another way to code it to place the code on the monster to have all the monster code in one place let's add a new function that will name initialize and this one will take a start position where the monster will spawn we pass the player's position here to be able to look towards the player so first we'll set the monster's translation to the start position we'll use once again a pathfollow node to do so then to turn the monster to look towards the player we'll use a function named look at the target is a position so we'll use the player's position and we have to give the up vector so we're going to pass vector 3 dot up it's because these functions that rotate a character rotate around the up vector then we'll add a random offset to that rotation there is a method called rotate y which will rotate the character around the vertical axis and we can pass it a random value as an angle we'll use the rent range function to create a random value within a range and we'll set it between minus pi divided by 4 and plus pi divided by 4 remember that the angles are in radians and so this gives us a range of 90 degrees between -45 degrees and positive 45 degrees that will place the monster and make it look in a certain direction now this does not give it a velocity yet so it will not move that's why we have to calculate first a random speed we are going to use rand range again and we'll want to get a value between mean speed and max speed we can then use that for our velocity one thing you have to do here in 3d is we want the character to move forward in the direction it is looking and to do that we're going to use the technique we used in your first script when we made the character turn in circles we're going to first have a forward vector of a certain length based on the speed so our base velocity will be vector3 that forward this represents the forward direction and we'll multiply that by random speed to give it a certain length now this is not the direction the monster is looking yet so we have to turn that vector and to do so we'll use the vector3 dot rotated method so we'll write velocity equals velocity dot rotate rotated and we have to pass the up vector followed by the angle we want to rotate and this is the monster's current y rotation which is caused by the look at and rotate y method calls i have an extra parenthesis to remove here with that we can move on to spawning our monster around the game area we can now close the mob scene as we'll work in the main one press ctrl f2 to go back to the 3d view and here we want to trace a rectangle around the game area from which we'll randomly spawn the monsters before we do that we have to set our project windows size settings i'm going to display the camera view here and we'll go to project project settings and want to go down to the window category which you can search for using the search bar click it and we want to change the game size so we're going to use 960 x 720 this is the base resolution we used in the final project we'll also go down to the stretch category which controls how the game renders as you change the scale of the game window and we'll change the mode to viewport viewport will render at this resolution 960 times 720 and if you enlarge the window it will stretch the rendered image this is typically what we use for 3d games and for the aspect ratio we'll use keep which will add black bars around the game as we stretch it but it keeps the game window consistent in size which is convenient for the gameplay so here we have to trace a rectangle around the character and we want it to fit the camera view you can press ctrl 2 to split the viewports vertically into two and the second viewport you wanted to preview the camera if it's not set to preview mode you want to select the camera node for this checkbox to appear okay and we'll use the upper view to place and trace our path now it's a bit difficult as you can see to know exactly where to trace the path so it's right outside the view so the monsters spawn outside and seem to enter the game view but they don't spawn too far away from it we'll use the trick to visualize that we're going to add some meshes that we can see clearly in our view and we can see how far it is from the game's mount select the main node and add a new spatial node that will name cylinders we're going to create a bunch of cylinders in there it's just to group them that will create this node and as a child of it we're going to add a mesh instance for the mesh in the inspector you want to create a cylinder it's going to be placed in the center and we're already going to move it around now we can turn on grid snapping here by clicking the little snap icon and there you can click and drag the cylinder and you can see in the bottom view how it moves and you can move it until it's right outside the view the yellow bounds tell you what the camera is going to render in the end the aspect ratio of the game so you want it right outside the view we're also going to change the mesh's color to make it more visible in the view expand the material category and click empty to create a new spatial material you click then the resource to open it in the inspector and edit it and all we want to change here is the albedo which controls the base color of our cylinder right now it's set to white you can change it for anything that's really visible like a bright orange this will help us spot it more easily when we go in a top-down view and start tracing our path all right so we can duplicate that mesh instance by pressing ctrl d and move it around so you want to move it on the x-axis but you also want to ensure that it is outside the view right so we're going to roughly move it so that it's aligned horizontally with the other one but it's also right outside the view and we can then select the two mesh instance nodes and press ctrl d to duplicate it the new nodes are selected by default so we can click on the z-axis to see them move down until they are outside of the camera view there we go so that's our indicators to trace a path around the screen we can fold the cylinders and note that at runtime they don't have to be visible we can just hide them by clicking the visibility button next to the cylinders node but for now we want them visible we're going to add a new path node to trace our path first we want to trace it in a pure top down view so we're going to click the perspective button and you want to use the top view you can also use 7 on your keypad and there it works similarly to the 2d path node we're going to click the green plus button to be able to add points and click on each of the cylinders as we have grid snapping the points will snap to the position of the cylinders so we add four vertices and then we click the right most icon to close the curve click and there we go we have a path going around the screen we have a node we can use to sample a random position along that path it's called pathfollow so select the path node and we're going to add a new pathfile node and this one if i add a mob as a child of it temporarily i'm going to click and drag mob.tscn onto it and i select the pathfollow i can increase its unit offset to move the monster along it you can see the way the monster rotates is a bit weird and this is due to the node settings so as i said positioning in 3d is a little more complicated than in 2d here we have to change the rotation mode from x y z to just y we only want to rotate the monster's y y-axis and then we'll automatically correct the rotation as we move the monster around with our initialize function okay so i'm going to delete that temporary mob and rename the node to spawn path and spawn location let's say for the pathfollow node like in the previous video we'll use a timer to spawn monsters at regular time intervals select the main node and add a new timer node we'll call it mob timer and this one will have a wait time of let's say 0.5 like in the previous video right or 0.7 it's going to cycle and emit the timeout signal every 0.7 second will listen to that signal to spawn a monster which is what we're going to code next so add a script to the main node which will spawn the monsters right away we're going to connect to the mod timer's timeout signal so double click it and connect it to the main node and with that we can get coding i'll expand the script editor close the mob script and we're going to focus on this one so when the mob timer times out we're going to create a new mob i'll define a variable called mob and now we need a scene to instance we're going to add an exported variable called mob scene and we need to put a type hint here so good it knows what kind of object what kind of data we're going to put in that variable so you add parentheses after the export keyword and we're looking for the packed scene data which is the data type of our tscn files which we can then instantiate to create new mobs now we don't have to set it necessarily in the inspector exporting the variable makes it so we can conveniently change it from the editor but we can also call a function like load or preload in gdscript we're going to use preload and pass a path to a sync file like mob.tscn okay so one quick tip here it's that if the file is in the same folder as for example the main.gd script you don't have to put the full path with the res at the start otherwise re is slash corresponds to the root folder of your good old game directory then i told you there's preload and load so what's the difference preload loads the scene when you compile the game that is when you press f5 for example but also when the player is going to double click your game the load keyword loads the scene on demand so you can use it inside a function for example anyway here we are going to use preload in this little game it doesn't make much difference and going back to our onboard timer timeout we're going to create a new mob instance so we're going to get the mob scene and call its instance function this creates a new mob for us we're going to calculate its location and the player's position to then pass it to the mob's initialize function we coded before let's first do the mob spawn location and for that we're going to get the spawn path spawn location node and like in the previous video to get a random position along it we are going to set the node's unit offset to a random value so unit offset is this property i was playing with right before on the spawn location when i increase it you can see that the point the gizmo is moving along the curve it's a value between 0 and 1 1 corresponding to the end of the curve and 0 to the start and so when we set it to a random value rand f generates a random value between 0 and 1 we get a random value along the curve and to get the position of a node in 3d what you typically do is access its transform it's a value that represents the translation rotation and scale of a 3d object and you're going to get the origin of the node this is its position in space now we have the two values we need to place the monster we can get its start position from the mob spawn location and the player position but first we need to add the node as a child of the main node we need to add it to the scene so we add the mob at the runtime as a child of main and we're going to call mob dot initialize it needs first the spawn location it's going to be the mob spawn location dot translation this is going to be the random location generated when we updated the unit offset and we passed the player position the initialize method will then take care of placing the mob and having it look towards the player and start moving now we can in the ready function called randomize to ensure that every time we play the game monsters spawn differently now if we play the game nothing happens and the problem is here that i forgot to turn on the mob timer so in the scene ensure that you set the mob timer to automatically start at the start of the game i'm going to press f5 and monsters start popping in the view you can see they collide with one another if they encounter each other and they stop with the player that is normal it's the player blocking them when we'll add the player dying or monsters dying it will work a bit better but still we don't want monsters to collide in one another i want them to go through each other instead of trembling or having weird bugs like they do and for that we have to go back to the mob scene so double click mob dot tscn control f2 to go back to the 3d view and we have to configure our kinematic body's physics layers click the mob node and extend the physics body's collision here so under physics body the collision category right now the mob is set to be on layer 1 and to collide with things that are on layer 1. we're going to remove that mask and we're also going to place the mob on layer 2. you can see the list of layers as check boxes here by clicking the three dots to the right of the collision layer and currently they'll name layer one two three this is not great i think you'll admit so we want to rename these layers to know exactly what is where you can go to project project settings and we're going to search for the 3d physics layers so you can search for layer and click 3d physics here and next to each layer you can give a label and so we're going to name them player for layer 1 enemies for layer 2 and world for layer 3 world will be the flaw and we'll update the layers on the different components later to avoid any problems in our code but for now we already have the enemies on there too and they won't collide with anything you'll see why because initially if you test now enemies will go through the player but we want that to happen because we'll add collisions to detect specifically when they hit the player from the front and you are not jumping to only kill the player in that case all right and we can perhaps move the mob node a bit higher up so we get a bit of shadow to have it floating above the ground like the player you can see a bit of shadow now when we'll animate it it will look even nicer as the shadow will animate with the monster but with that you have monsters spawning procedurally around the game next we'll add the squashing mechanic to kill the monsters before we code the squashing mechanic we're going to finish updating the layers and masks on our physics bodies we did so on the mob which is currently on layer 2 and doesn't detect or look for any layer this means that the enemy wouldn't collide with the flaw for example which is not a problem in this case because with our code the enemy only moves on the x y plane it doesn't have a gravity applied to it only the player because the player has to jump and fall back down we're going to open the player scene and select the player node to set its physics bodies collisions so the player is on layer 1 but we don't want it to only mask layer 1. we want it to detect the enemies and the world so we'll uncheck player it doesn't need to detect itself and check enemies and world now the problem is the ground is on layer 1 by default so we need to update it as well go to the main scene select the ground static body node and expand its collisions the ground is going to be not on layer 1 but layer 3 the world and want to remove the mask because it doesn't need to detect anything it just needs to sit there and wait for the player to fall on it with that you can play the game jump and you'll see that your collisions still work there are several points to the setup including improving performance because you limit the number of interactions between layers and masks but also ensuring that things collide as you intend them to we can now code the squash mechanic that kills the monsters we're going to look at what the player node is colliding with when you fall and it can detect two things either it can hit the floor or it can hit a monster and we need to differentiate between the two like in the previous lesson we'll use node groups go to the mob scene select the mob and go to the note tab groups we're going to add a tag to the mob well just write it mob with or without an s i chose without in this case and we'll use that in the code to know if we are hitting a mob notice the group icon that appears next to the map node we're now going to go to the player script where we'll code a bouncing mechanic we're going to add a new variable for that we're going to call it bound simples and it's going to be of 16 meters it's going to be an instant increase in speed if we fall over a monster then here's how we can detect the monster encode so we're going to go to the physics process function at the end here we want to use a function from the kinematic body class called gets light count it returns the number of time your node collided when you called move and slide it's going to be a number it can be 0 1 2 3 and for each of those slides the collision might be different so in general when you're going to check for the collisions of the kinematic body and you're using move and slide you want to use a loop to loop over all the collisions that happen this frame and so we can use a for loop for that so we can say for index in gets light count to explain in godot when you write for some variable in a number it's a shorthand for calling the range function on that number which if the number is three it's going to create an array with the values zero one and two and so index will be equal to zero the first time then one then two now if the number is zero the array is going to be empty you're not going to get any range and so godot is going to skip the loop it's going to end immediately so this is a really nice way to check collisions in our case so for each of the collisions that happened we need to get an object representing it and we're going to do that with a variable and another function we'll create a new variable named collision and call get slide collision another method of the kinematic body we can pass our index as the argument as you need to tell the number of the collision you want to get it's a collision that happened this frame right and so then we can check for the object that we get so if you click on it you can see it has a number of properties that give you information about the collision that happened i'm going to go back to the player script and what we can do here is we can check if the collider that this collision had is our mob using the is in group method so we can just say if collision dot collider has a property name collider which is the object you collided with and we can call the is in group method on that and want to check for the mob group we created before so if this function call returns true then we know that our collider is the mob to make things clearer we are going to store it in a variable so we can say well mob is collision.collider now we only want to squash the mob when we fall on it from above and we're going to use the dot product of vectors to do that this allows us to roughly compare the angle between two vectors we can write it like that a vector3 dot up so the up direction dot dot we're going to call the dot product method on that and we compare it with the collision normal if it's greater than a value in this case of 0.1 it means that the vectors are roughly aligned they can be in different directions but basically it roughly means that you are above the monster let me explain now what this is so the collision normal is a vector that is perpendicular to the collision that happened so if you fell on the head of the monster it's a vector that's going to be pointing up this depends on the geometric shapes and how they interact but as our monster has a box collider the normal is going to be pointing up and the dot product is going to give you a value close to 1 when the vectors roughly align and it's going to give you a value of zero when the vectors are perpendicular so that's why we often use this method the dot product of vectors to compare the angle between them so if that condition is fulfilled then we can destroy the mob uh we're going to add a method to the mob called squash we haven't defined it yet but we're going to add it next that will kill the mob you can use a method like that to play an animation when you're killing the monster those kinds of things we're going to also change the player's velocity we're going to set it to our bounce impulse which is similar to what we do when we jump this is going to make the character bounce up after falling on the monster our squash method doesn't exist yet on the mob so we're going to open the mod.gd script note you can do control alt o to open the quick script open window and open mod.gd we're going to define a squash method what we want to do here is to define also a signal squashed which we're going to emit and use to count the player's call and we can add a function below initialize function name squash it's not going to take any argument there we'll emit our new squashed signal and then we'll cue free the monster again you can use that function later to play an animation of the monster dying uh spawn some particles and those kinds of things which is why it's nice to use a function like that from the player script with that you should be able to play the game with f5 and jump over the monsters and squash them like so next up we're going to add the ability for monsters to kill the player we can use a new area node to detect when monsters are hitting the player from the ground we'll go to the player scene you can press ctrl f2 to go back to the 3d main screen and we're going to add a new area node as a child of the player ctrl a to add a new area node we're going to call it mob detector this will show you another use of areas which you can use to detect all kinds of things and you can attach them on characters to create hitboxes or hud boxes if you attach them to a weapon we're going to add a collision shape to it once again and this time around we'll create a cylinder shape in the inspector the cylinder is really big right now but we're going to make it thin and move it up to the top of the character so you want to make it a bit thin and move it a bit up like that and for the radius we'll have to test it in the game but roughly the radius of the character would be fine why do we need to move it up we'll use that so that when the character jumps whoops the entire player jumps the cylinder will be too high for the monsters to touch it so the they won't be able to kill the player that will allow you to squash them safely when you jump however when you're on the ground want to place the collision shape so monsters will hit that cylindrical shape and kill the player we'll test it and modify its position if necessary after adding the code to kill the player we're going to select the mob detector and connect its body entered signal to the player script we'll connect it to the player script and i almost forgot that we need to configure the mod detector so back to the inspector with the node selected we're going to go down a little bit and expand the collision category the mob detector is not going to be on any layer but it's going to mask layer 2 the enemies layer to detect the mobs then it's not going to be monitorable it's going to be only monitoring what does this mean this means that no other area or collider can detect our area it's only this area that is looking for things in the world with that it will detect monsters okay so now in the player script i'm going to expand it and we're going to use this callback to kill the player like before we're going to use a signal to inform the game when the player died so we can display some kind of game over or a restart screen to create a new signal named hit at the top then i'm going to fold physics process for now and below it i'm going to define a new function named die in this function we're going to emit our hit signal and we're going to q3 we're going to delete the player then when we have the signal callback we call the die function note that like before instead of creating an x-ray function you could directly connect the signal to the die method now we can press f5 to test that when a monster touches us it kills us and right now it's not the case so let's see i'm going to make the collision shape a bit lower and perhaps i want it to be a tiny bit larger let's see i'll press f5 collide with a monster and the character dies you can see we get an error and that is because we don't end the game when the player dies because we've frayed it the player node is not in the scene tree anymore and we wrongly try to get it in our code so we'll update main.gd to end the game when the player dies go back to the main scene and want to connect the player's new hit signal to the main script select the player node go to the node tab and double click hit to connect it to the main node and on player hit we're going to just get the mob timer and stop it monsters will stop spawning stopping the game you can try it out you hit a monster the monsters stop spawning they just keep moving and leave the screen and voila next up we're going to add the skull and the ability to replay the game back to the main scene we can start working on the user interface we're going to add a score label that will stick to the top left corner of the screen select the main node and add a new control node this is the base type for ui nodes and you can see them all in green when we add it we get sent to the 2d main screen because you edit interfaces into the end guitar we're going to make that node span the entire viewport by going to layout full rectangle and i'm going to rename it user interface you could rename it ui as you prefer we're instantly going to add a label as a child of it i'll rename this to score label i'm going to add some text saying score column followed by some value here zoom in a bit and we're going to offset the label from the top left corner of the screen to give it some margin so you could click and drag to move the label you could click this icon at the top to use grid snapping you can press shift g to toggle it and then click and drag to move the node all shift with the arrow keys is going to nudge by 10 pixel increments the score is a bit small right now so we're going to increase its font size and we saw one method of doing that in the previous video by adding a custom font to the label in this video i want us to use godot's theme results so you can see how we can add a default font to the user interface and it will apply to all the text you will add as a child bit to create a resource we can select the user interface go to theme and click here to create a new theme but you can also create those files directly in the file system you can right click on a directory and click new resource and then you can see all the resource types that godot offers there are probably as many as nodes you can type theme to filter it and press enter to create the file so i'm going to call it ui theme.t res the file gets added to your file system and you can double click anytime to edit the file in the inspector and you'll see an interface appear at the bottom giving you a preview of your theme settings by default you can only set a default font on the theme which will affect all the text on the buttons on all the things you put in your interface really so here we're going to create one so click default font to create a new dynamic font we're going to click to expand it and expand the font and settings areas these dynamic fonts expect a ttf or otf vector font file and we put one in the fonts directory you can click and drag it onto the font data slot this will change the text in the preview at the bottom and there you can change the size setting to increase the size of the text in pixels you can say 20 24 something like that and then you can click the theme button panel to fold it all right so we have our theme but it's not applied to our scene yet so we have to go back to our user interface node you can click it and drag and drop the ui theme.t res onto the theme property the score automatically updates and now i'm going to nudge it back up because i find it a little too much into the screen okay so if you play you'll see one problem the background is white so the score is not visible the color we'll use here will be only on the score label so we select the score label and we're gonna go to custom colors and check the font color right now it becomes black we can find a more appealing tone maybe something like a dark gray purple something like this it's hard to see in the main scene in the 2d view but if you press f5 you'll see that now the score is more readable so we have this call now we need to update it somehow we're going to add a new script to the score label so select it click the new script button and you want to save it as call label.gd as the game is really simple i'm going to store the score directly on this node so create a new variable named score and we're going to create a new function to update the score we could write it like a callback because we're going to increase the score every time we squash a monster so we could say like with our signals on mob squashed we're going to add one to the school and we're going to update the notes text label has a property named text which we use to control the text so we can say score and here's one thing you can do with go to strings you can use placeholders in a text string inside quotes so you write this person sign s placeholder and will be replaced by the values you put after that so you have to put another person sign and then you put the values you want to use for replacement in that case it's going to be the score and gudo will automatically convert the score as a number into a text string we name it as a callback because it's going to be called when a mob is squashed and we're going to connect the mob signal to it now the thing is we spawn monsters procedurally and we need to connect the signal of every mob to this function how do we do that we can't do it in mob gt we're going to do it in main dot gd where we create the mobs so in mob.gd and the function onward timer timeout when we create the mobs we're going to connect their squash signal to the skull label so we write mob dot connect they have a squashed signal so that's the first argument the signal then we pass a target and before we've used self as a target but we can use other nodes that we get with the dollar sign or the get node function we're going to pass user interface score label and we're going to call it's on mob squashed function that appears in the autocompletion here so now when a monster gets squashed the signal will be emitted and will automatically trigger a call to on mob squashed let's try the game you have to squash monsters and you'll see the score update in the top left i have two three let's try that three okay so you can see the score system is working and that's really all we need for it the last part for this interface which i decided to keep minimal in this project is to add a retry screen we're going to go back to the user interface node and we're going to add two nodes as a child a bit one is going to be a color rectangle we're going to use a color that's going to span the entire screen to darken it so click the layout full rect option to make it span the entire viewport and we're going to change the rectangle's color by clicking its color property we're going to make it dark but not only that there's an a channel which controls the alpha the opacity of the tone and we can lower it to darken the screen we can name the node retry and we're going to add a text label to place in the center as a child of it so add a new label node as a child of it and we're going to use this time layout center we can use center or we can use age center wide which is going to make the nodes span the entire width of the viewport in the center and we can right press enter to retry and we're going to align the text in the center of the screen we don't want this to be always visible so we're going to hide it by default and via code when the player dies we're going to display it we're going to go back to the main script where we already connected the player's hit signal to an on player hit callback function so when the player gets hit we're going to show the retry node we can get the retry node and call its show function so we can test that we go into a monster and the screen appears and now we press enter but nothing happens we're going to use godo's input callback to listen to the enter key go back to the top of the script and below the ready function add the unhandled input function so we're going to check if the player pressed the enter key we can check for event dot is action pressed and we're going to listen to ui accept which is a default input event the thing is that's not enough for our condition we're going to ensure that our retry screen is visible and if it's visible it means that the player died so we can use that for our condition we're going to check the retry node is visible we just check for its visible property which is a boolean so it's going to be true or false and if so we can call get tree dot reload current scene we get the scene tree which is the object that represents your entire tree of nodes in the game and it has this method reload current scene which is going to reload the game now um here we are using event dot is action pressed something that i think is new in the series or we've seen it a while ago a few lessons ago the event is an object in godot of type input event it's a bit similar to using the input singleton that we used until now which also has his action pressed and his action just pressed but this function gets called with an object that represents just the key the player pressed so if you press enter this function will be called with an event representing the enter key being pressed so it's convenient for one-time actions like when you're pressing enter to use the interface anyway our retry screen this is all we needed to make it work so we can press enter when the screen is visible and the rest of the time you can hear i'm pressing the enter key frantically but it's not reloading the game so this is working it's only reloading when we have the retry screen visible and with that our game is almost complete but it looks a bit blonde don't you agree that's why we're going to work on animation next and make it look much better with very little effort let's do that we're going to look into godot's animation system so i'm going to close all the scripts just to clean up my script view and open the player scene by clicking the scene icon in front of it there's a node in godot that allows you to create animations on your characters in the editor it's the animation player so select the player and let's add an animation player node this opens the animation view in the bottom and we're going to click the animation menu to create a new animation right away i'll call this one float it's going to make the character float there's an icon to the right of the animation drop down which allows you to autoplay the animation on load and another icon there that looks like a loop to make the animation loop that's what we want for this one so we're going to create an animation using the timeline here you can click and drag to move your cursor over time and it's a bit cramped at the moment so we're going to use the slider in the bottom you can move it to the right to zoom into the timeline okay the way this works in godot is you can select any node and you're going to see these key icons appear next to the properties and you can pretty much animate anything in there right you can create a keys so when you click such a button it's going to create a track with what is called a keyframe here it's a marker that tells the engine at this point in time in the animation i want my value to be 20 in that case you can see when i select it in the inspector and in between those keys godot is going to interpolate that is to say to change the value to make an average as you move between two of those keyframes i'm going to click the trash icon to remove that first keyframe and what we want to animate here is the player node the model only to move it without affecting all the collision shapes to not affect gameplay and we want to animate its transform so you can expand the transform and you can add a key for the translation and rotation degrees you might be getting a menu that asks whether you want to add new animation tracks and you can click yes i've changed the setting in the editor to change that so you can look for animation and you have this option confirm insert track that i personally don't use so um here what we're going to do is we're going to animate the character going up and down and we're going to animate it also rotating at the same time to give it a wave like motion for that we're going to need a few keyframes so i'm going to delete the keys by clicking and dragging and pressing delete it's not going to delete the animation tracks only the keyframes and then i'm manually going to insert the keys we're going to need a bit of trial and error here when making this animation but basically you can right click anywhere to insert a key and it's going to insert a key with the transform value that you are currently having in the scene so if i move the character up and down it's going to store that that value upon clicking insert key a particularity is if for example i move the character and i click on my timeline you can see it snaps back to the recorded value in that keyframe so you have to be wary of that you always have to insert new keyframes so i'm going to make it move up a bit so i'm going to go to 0.5 0.6 seconds something like that move the character up a bit and right click insert a key and now if i drag over my animation timeline you can see the character moving up and down what i want here is for the character to go up to stay up a little bit and then to fall back down and there's a trick we can use for that to make the animation bounce here when you select one of the keyframes by clicking on it you can see in the inspector the property named easing this is a curve that represents how the values will transition between two keyframes how the computer will interpolate them so when you select a keyframe like that you can say i want you know if i pull it to the left the value will increase quickly and then the character will slow down as it reaches the key you can press shift d to play the animation from the start and s to stop it you also have the controls in the top left here so shift d and you can see how the character is now a bit bouncier okay we can change the keyframe here as well right we can try an easing by pulling the curve left and now the character spends more time in the extremes of the animation that is when it's up and down so we can pull it the other way around to make the animation like a bounce so we have the character bouncing a bit i'm going to make the curve less less exaggerated for the second keyframe now we need to add the rotation to make it look like it's waving around so the way we're going to do this is we're going to rotate the character to make it look like it's moving over a wave if that makes any sense we're going to make it so when it's up like that it has to be rotated looking like it's going up so i'm going to rotate it back around the x-axis and note you can use the rotation tool to work only on rotation and right-click insert key now we only have one key so the character is always rotating up but when it's at the bottom then we want a little uh before that so we want it to be looking down when it's going down like so and we're going to test the animation and you can see that right now it looks like the vertical movement and the rotation are out of synchronization and that often happens with animation where you have to add many more keyframes and use your eye a lot to make the animation feel believable so what i'm going to do here is i'm going to add a key around 0.3 second to make the creature whip a bit to make it when it hits the floor it's going to rotate a bit faster and anticipate going back up let's see that um i also want it after reaching the peak i don't want it to rotate so fast and to go back down so far so i think i'm going to move it up back up again either keyframe on the translation key there we go it's going to feel a bit better if i do that and i'm going to have it hold its rotation a bit more so for that i can use the easing i select the right mouse key in the rotation track and i'm going to the easings in godot are always a bit confusing but if i pull the curve left a bit it seems to be helping a bit okay the animation is a bit wacky still but i'll leave it at that because it's going to be enough for the game perhaps one thing we can do is make it a bit longer stretch it a bit more so in the top right of the animation editor you have this number that controls the duration of the animation in second we're going to make it 1.2 seconds make it a bit longer and i'm going to select some of the keys like when the character reaches the top and push them a bit to the right see what the timing does okay i'm going to push them 0.1 seconds left all right the animation is not amazing but it's better than nothing uh you have to to really play quite a lot with the easing curve the timing of these keyframes until it looks good in the editor that is really what matters at the end of the day but okay i'm going to be working with that because even if the animation is a bit wacky from the right what matters is also the view angle in the game and so in the game while only watching the character from up top so you can press f5 to see how your character is animating already right and we're going to use code to make it so right now when it's moving the animation stays the same and it feels a bit weird and i'm noticing now with the shadow and the white background that one thing that looks a bit wonky on the character is the amount of rotation it's peak rotation is a bit too high so i'm going to correct that let's stop the animation with the s key select the animation player of course and it's the extreme here of the rotation is a bit too much so i want to select the keyframe and perhaps go to a value that's like minus 13 or something on the x axis and you have to click to update the the view this is looking a tiny bit better so now we can go to the player script and we're going to control this animation it's speed to be exact so what we can do in the physics process function i'm going to expand the script editor we are calculating the player's move direction and here we were updating the pivot to make the character turn in the direction the player wants to move there we can also update the animation speed to do so we get the animation player node and it has a property called playback speed this is a multiplier that's going to be added to the animation playback and we can set it to 4 when the character is moving when the direction is not vector3.0 else if there's no direction we duplicate the line with ctrl d alt down arrow to move it down and swap it with the else statement and we're going to reset it to 1.0 okay so let's see now when we move the character you can see how with just the same animation we just play it faster and it feels like it's moving right it feels like it it's trying to to kind of swim or something like that we're going to add one more thing to this um when we jump the character doesn't arc you know with the with the jump so it feels a bit weird it keeps animating the same way we can use code to control that as well we're going to go to the bottom of the function for that and we're going to use a tiny bit more math to rotate the character to follow the curve of the jump so we're going to get the pivot node for that because we're animating the the character and the animation player takes full control over the character when we do that at least over the tracks that we animate that is the transform and the rotation this is why that pivot node is pivotal we're going to get its x rotation and to be exact set it to a new value based on the current y velocity here's what we can do we can say rotation.x is equal to pi divided by 6 times velocity dot y divided by jump impulse so we're going to give the character a maximum arc of pi divided by 6. we multiply that by the y velocity which is going to be a number that can go up to 20 something and we divide it by the jump impulse why because it's the maximum vertical momentum that the character can get when we add that jump impulse to it we can press f5 now and you're going to see that when you jump the character arcs and it arcs up and then it arcs back down why does it do that well because the y velocity goes up when we jump but then it goes back down under the effect of our fall acceleration giving us a nice animation over the rotation so that's for the player's animation pretty cool right with just a few lines of code and a few minutes making an animation we have that nice effect now it'd be cool if we could add it to the enemies don't you think and we can do that introducing a new feature we're going to copy the player's animation over to the enemies ctrl shift f11 we're going to open the mob scene so double click mob dot tscn and there are a few ways we can go about adding the animation track one thing we have to do though is our nodes that we're animating here is named player and in the mob scene it's called mob but the animation player if you click it you'll see that it uses the node name to know what to animate right so we need a similar setup where we have a pivot node and we're going to rename this one to character it's going to rename in the animation player as well we save the scene and in the mob scene we're going to rename the mob node to character as well now we can right click on the mob and there's a feature called merge from scene it allows you to duplicate nodes and data from one scene to another so you can click that you double click player.tscn and we're going to select the animation player and now our monster has a float animation ta-da so you can play the game and you'll see monsters animate now they all play the animation at the same speed and yet they have different velocity so it'd be nice if we could also change the playback speed to match that which we're going to do now let's open the mob script and we're going to go to the end of the initialize function because we only need to set the animation speed once as the monsters have a constant speed we're going to get the animation player dot playback speed and we're going to set this equal to well we're going to use our random speed and we're going to divide it by we can say divided by the minimum speed so the animation playback speed will be 1 if the monster is at the minimum speed and it will be higher if random speed is greater than the minimum speed you can now press f5 and enjoy your completed game you have the monsters animating you might need to tweak the monster's animation because their shape is a bit different from the main character so i'll leave that up to you to lower the rotation a little bit also note that we don't have music right now but we can add it very quickly to be honest we're going to go to the main scene and select the main node we're going to add an audio stream player here and if we go to the alt directory we have the house in a forest music loop so we can with the audio stream player selected click and drag it onto the stream slot and we can set it to auto play in the inspector there's one last thing we'll do here to make our game look a little bit nicer if i go back to the 3d view and zoom in on my character you can see how the shadow is a dark gray and while getting a dark gray color that's muddying the characters orange and it's doing something similar to the enemy we can change that using something called the world environment select the main node and add a new world environment node this node takes a resource called an environment now when you create a 3d game godot creates one of those resources for you the default environment.t res you can click and drag it onto your scenes environment and you're going to see it gets even worse now with the shadows becoming completely black click the resource to edit it in the inspector and you can see it gives you a few pass processing effects that you can use in your game like a 3d fog a depth of field it's blurring the view close or far away from the camera glow and those kinds of things but here we are mostly interested in the ambient light the background by the way it's set to clear color currently and it means it's going to use your project's default color like you've seen in 2d before that dark gray as the background but our background is covered by the plane so we don't care too much about that the ambient light is a color that gets added to the shadows and everything in your scene to change the tone of the shadows to give them a bit more warmth so you can click the color here and in the drop down you can play a bit with a value like a purple or something like that so you don't want to go too too much into it but you'll notice that this is how in some indie games some ambiences are created in different level you want to make a lava level you can use a red or orange ambient color and it changes the tone instantly and it's very very cheap in terms of performance it's something that's been done for decades now literally so you want to use a tone that's going to be in the purples perhaps in the blues purples that has bits of saturation to it but not too much because you want the shadow to look nice but you don't want the eye the white of the eye to look pink basically that should be the baseline i'm going to choose something like that and just so you see see the difference between this purple and what we had before with the dark grey right it's not the same perhaps i'm going to make it a bit lighter to really tone down the game's shadows something like that before playing the game i'm going to mute the audio for the recording but you'll have the music playing now when you press f5 and you can enjoy a nicer looking game you can see how just that change in the shadows and in the colors make the game look more cartoony and more stylized as well this is supposed to be your first 3d game ever so you can pat yourself in the back for getting there i want to thank you very much for getting to the end of the series and now we can talk a bit about what to do to go further i pitched our email series and um i invite you to check it out if you haven't already because it's complementary to this course from there you'll want to create more kinds of games and in particular i really invite you to experiment on your own taking for example the two games you just made and try to change some mechanics or add some others shift codes around and see what you can achieve from there you'll really want to start practicing and for that we have an article called the beginner's learning path to godot on our website which is a list of curated resources to learn godot for free on your own and so that would probably be the next thing you can look at to go further you will find this very course in it but also others that you can check out and enjoy to learn new things with that i want to thank you kindly for watching be creative have fun and let's see one another in the next one bye
Info
Channel: GDQuest
Views: 50,832
Rating: undefined out of 5
Keywords: godot 3d tutorial, godot tutorial for beginners, godot tutorial, godot tutorial 3d, godot tutorial 3d game, godot 3d tutorial for beginners, godot getting started
Id: YiE9tcoCfhE
Channel Id: undefined
Length: 93min 46sec (5626 seconds)
Published: Thu Apr 22 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.