Godot. Godot. Godot.
Whichever you prefer, if you want to use it to make a game, you've come to the right place. I've been making video games for more than 14 years now, and recently I've fallen in love with Godot. Godot is a great choice for many developers, and pretty beginner friendly. Also, it's open source and completely free to use.
Now you probably have a bunch of ideas of games that would be cool to make, but no matter if you're dreaming of making an FPS, a 2D platformer or anything in between using Godot, the first step is of course to install it. Now this process might be a bit tedious, but bear with me now. We go to GodotEngine.org, press Download Latest, Godot Engine, and we're done. This is a huge advantage of Godot.
It's extremely lightweight and can even run in the browser. Now you might want to unzip this folder and place it somewhere you remember, but other than that, we're ready to open up Godot. So let's double click it. And it's going to ask us if we want to look at some example projects.
I'll just press cancel. Then we can press new. Name our project, say, first game.
I'm going to place mine on my desktop, under my games folder. Let's create a separate folder for first game. So hit create folder and create an edit.
And here we are. A clean slate. A blank canvas. Oh, I am so ready to make this game about... Well...
This might be a good time to decide what our game will be about! But first, this video is sponsored by Zenwa! If you're excited about Godot 4, make sure to check out Zenwa Academy.
They offer comprehensive beginner and intermediate courses, including a fantastic free introductory course on Godot. What's really cool about Zenwa is how they combine fun and practical learning through professional video tutorials, written lessons, and interactive quizzes. Plus, you'll be building real projects across various genres, from RPGs to bullet hells. Zenwa also has a wide range of courses on Python, Unity, Unreal and other essential tools. With a single subscription, which includes a 7-day free trial, you unlock over 250 courses.
Use the coupon code below to get an extra 20% off the first year of your Zenwa subscription, on top of any existing site-wide discounts. The offer is valid for the first 50 subscribers, so make sure to use your coupon today to start your gamedev adventure. So, in the spirit of learning the basics of the engine... and giving you an overview of how you can start using it to make things, I've put together the most basic game I could imagine. Think of it like food without salt.
It doesn't have much flavor, but it does have a player, enemies, moving platforms, collectible coins, and most importantly, it should get you familiar with the engine in no time. Also, we'll be working in 2D. But another really cool thing about Godot is that it's very easy to transfer 2D concepts to 3D. So don't worry, if your dream game is in 3D, most of what you learn here is going to directly apply. As for programming, Godot uses its own scripting language called GDScript.
It's pretty fast and easy to use, but still quite powerful. We'll do a bit of programming in this video to get you started, but the main focus is really to get familiar with Godot as a whole and to quickly get a game up and running. Because of this, I don't expect you to fully understand all the code you see. Feel free to write after me or just lean back and observe.
Our next video will be about learning to program in GDScript. All right. I promised you food without salt, so let's get cooking! Now to make our delicious game, we need ingredients.
We need things like sprites, models, textures and sounds. These are called assets and a game engine like Godot is not so much made for creating these from scratch but more for putting everything together. It's really the stirring part of making a game.
Now since I can't expect you to go shopping for assets at your local supermarket I've used a bit of TV magic to prepare some beforehand. You can download them for free using the link below. I've bundled together sprites from the amazing Analog Studios and modified them a bit along with a pixel font, some custom sounds And a cute little music track.
It's also perfectly fine to use other assets you find on the internet. There are many great resources for free assets, just make sure you check the license and give proper credit to the author. CC0 means that the asset is completely free to use and there's no requirement to credit.
That being said, making your own assets is one of the places where you can really get creative, and I highly recommend you try it out as soon as you feel comfortable. Remember, you can always use these assets as placeholders and then modify or replace them later. Alright, let's get our assets! Into Godot! Importing assets in Godot is extremely simple.
The file system window is where we have all the files we use in our game. By default, the only thing in here is the Godot icon. So let's create a folder where we can put our assets. Let's right click, new folder and name it assets.
Let's also make one for scripts and scenes that we can use later. Now we can simply drag and drop our assets into the asset folder. So I'll select the assets folder, open up my assets here.
I'm gonna select all the sub folders and click and drag them into Godot. And voila. We can now see and use all of our assets in Godot.
So now we're ready to make our game. So let's talk about how we do that. To make anything in Godot, we use nodes.
If you want to make a player character, we do so by putting together a bunch of nodes. If you want to make an enemy, we do so by putting together nodes. If we want to make a main menu, you guessed it, we use nodes.
So nodes are the fundamental building blocks of your game. And nodes come in many types. Some display an image. Others play a sound or add physics. And we can even extend existing nodes to build more powerful ones.
So in its essence, making a game in Godot is combining and extending nodes to get the result we're looking for. It's a super creative and fun process. But building everything in one big world with nodes for the player, enemies, UI, and a bunch of levels all in one place would quickly become completely unmanageable and confusing. Instead, we use scenes.
Scenes allow us to bundle together nodes into reusable packages. A scene can be a character, a weapon, a menu. They can be as small as a single collectible coin or an entire level.
Scenes make it really easy to focus on building one part of our game at a time and then slowly combining them to make our game larger and larger. This is because we can put scenes inside of other scenes, which is called nesting, and allows us to take, say, a player scene, a platform scene, and a collectible coin scene and put them all inside of another scene, say a level 1 scene. And even cooler, since scenes are reusable, we can make a scene only once and then use it all over our game. We can make many levels that all use the same collectible coin scene. And if we want to change something about our coin, we simply edit the scene, and it automatically updates everywhere else.
As you can see, all the nodes and scenes in our game start to resemble a tree-like structure. And that's exactly what we call it. The Scene Tree. And fittingly, we call the node at the very beginning of the tree, the root.
So now that we know a bit about how Godot works, let's start by making the most essential part of our game, the player character. Player 1.0. So let's create a scene where we'll put everything together.
This is going to be a 2D game, so I'll select 2D scene. And let's rename this from node2d to game. And even though it's empty, let's go ahead and save it. So hit ctrl s, go under scenes, and let's save it here.
And now we can actually play our game. It's not going to be very exciting, but let's try it out. So let's hit play up here or simply press F5. It's going to tell us that we haven't selected a main scene. We need to tell Godot which scene to run.
I'm just going to press select current. And you can see that our game scene becomes blue to let us know that this is now our main scene. And as you can see, not much is happening here. So let's stop playing by hitting the stop icon here or pressing F8.
And let's put in a player to make it more exciting. So. First off, let's create a new scene by hitting the plus sign up here. And this will be our player scene. And the root node for our player is going to be what is called a character body 2D.
So let's add a new node by pressing the plus here or hitting control A. And let's search for character body 2D. As you can see, this is a 2D physics body that is specialized for characters moved by script. So it's perfect for a player character that we want to be able to collide with the environment.
So let's hit create. And now we can see our node here, but we can't actually see our player in the scene. So let's add some graphics.
Let's add another node. I'm gonna hit Control-A, and let's search for sprite. And as you can see, we can choose a single sprite, or in our case, we want to create an animated character. So let's choose the animated sprite 2D. Sprites are just what we call images in our 2D world.
Now, with this node selected, we can use the inspector here on the right to change properties. on that node. If we select a different node, say our character body 2D, we can now see the properties on that node instead. So our inspector allows us to change things about a node. In our animated sprite 2D, we want to add some animations and we want to give it some sprite frames, the individual frames that will make up our animation.
Let's click here and add a new sprite frames. And now with this selected, we can see that it will open up the sprite frames window at the bottom. And in this window, we're going to press this tiny icon here that lets us add frames from a sprite sheet.
So let's click that, go into our assets under our sprites. Let's find our knight.png. And as you can see, I've gone ahead and packed all the different sprite frames of the knight's animation into a single image.
This is called a sprite sheet. It's a very efficient way of working with lots of sprites, such as when doing animation. Otherwise we would have to create an image for each single frame, which would quickly become an unmanageable amount of files. Now to start adding these frames in, we first need to configure the grid here.
Currently it's set to four by four. Let's go ahead and increase this. I've created an 8x8 grid here.
And as you can see, each frame now has its own grid cell. And let's just start by adding the idle animation. To do this, we simply click the frames in the order that we would like. So I'm going to go from the left-hand side here and click.
As you can see, it says this to 0, the first frame. Then I'm going to click the next one and the next one and the next one. And now it goes from 0 to 3 and we'll play from left to right.
We can always click again to remove. and this is how you can quickly build an animation from different parts of your sprite sheet. So I'll select these four frames and hit Add Frames.
Now let's hit F to center our character on the screen, and I'm going to use the scroll wheel to zoom in. We can also click and drag with the middle mouse button to pan. Now our character looks weirdly blurry. That's because we're working with pixel art, which requires really hard edges.
By default, Godot is going to try to do some texture smoothing to make textures look better. but applied to pixel art, that is definitely not the case. So let's simply disable this. So let's go to project, project settings.
Let's go under rendering to textures. And here on the default texture filter, let's change this from linear to nearest, which will immediately make our pixel art look crisp. Then we can select our animated sprite. And let's try playing the animation.
That looks great. I'm gonna increase the FPS here to 10 to make it go a bit faster. I'm also going to rename the animation here to idle. I'm going to enable autoplay to make sure it plays right when we start the game.
And finally, I'm going to take the sprite here and move it up to make it kind of stand on this line. And that's it for our graphics for now. We'll add more animations later.
But as you can see, we're currently getting this warning here in the scene view. And if I hover over it, it's going to say that this node has no shape, so it can't collide or interact with other objects. And this is because a CharacterBody2D is a physics node. And whenever we're working with physics, we need to define a shape that the physics engine can work with. So let's add a new node.
I'm going to press the plus sign here. I'm going to search for CollisionShape2D. Hit Create.
And here in the Inspector, we can now define a new shape. I'm going to add a circle shape. I'm going to make this a bit smaller and drag it up.
Somewhere around there looks fine. Now you're probably thinking, well, this is pretty far from our actual graphics, but that's totally fine. Colliders rarely need to be very precise, and it's a good rule of thumb to make them a bit smaller than the graphics if you need to.
Having colliders that are too large is simply going to be frustrating when playing. So let's now rename the top node here to player, and let's save the scene, ctrl s, as player, hit save. And now we can go into our game scene. and simply drag our player in here.
So I'm going to go to the top here and drag in the player. We also need to create a camera so that we can control what is currently being shown. So let's add a new node, hit Control A, search for Camera 2D, hit Create. And now if we press F, we can see that we have this huge camera viewport. This is definitely currently too large, so let's zoom in on our camera.
I'm gonna set the zoom here to 4x4. and simply click and drag our camera to be on top of the player. And now we can try playing our game. And there you go. We now have a player that is playing an idle animation and nothing else is happening.
That's because we need to add a script that allows us to move around. So let's close our game, go into our player scene, and with our player node selected, let's press this add script button. Here we can choose a template.
Of course, we're going to do some programming in this video. but writing player movement can quickly become a bit overwhelming. So for now, we'll use the basic movement template provided by Godot.
Then later, we'll go in and modify it to play different animations and rebind input to the keys we'd like to use. As for the path here, I'm going to make sure that we put this inside of our scripts folder. And let's just name it player.
Let's hit create. And as you can see, this creates a script that will move around our character. I know that this might look really confusing at first. but don't worry, we'll have a look at what all this means later.
For now, let's just try playing. And our player immediately falls off the screen. That's because we need to give him a collider to stand on.
Right now, our player has a collider. but it doesn't have anything to collide with. So in our game, I'm gonna go back to the 2D view at the top here. This is where we can change from script view to 2D.
Let's add a new node. So let's hit the plus sign. Let's add a static body 2D. And this is another type of physics body.
It's the one we use for things that don't need to move. That's why it's called static. So it's perfect for creating some ground.
Let's hit create. And again, this is going to give us this warning here that it needs a shape. So let's add a collision shape. So I'm going to hit control A, search for collision shape. And for the shape here, we're going to create a new world boundary shape.
The world boundary is a type of collider that is perfect for stuff like, well, world boundaries, because it's going to extend infinitely on the horizontal axis here. So as you can see, it's currently pointing up. We could also point it to the side here. And now it's going to extend infinitely on the vertical. I'm going to hit control Z to undo that.
Instead, I'm going to select the entire static body here. I'm going to change to the move tool by pressing this icon here or simply W on the keyboard. And I'm going to move it down under our character.
Then I'm going to go back to our select tool, which is here, or simply press Q. And while our collider doesn't have any graphics, it's going to be invisible. We can now play.
And there we go. Our player now gently lands on the collider and we can move around using the arrow keys and jump with the spacebar. Now our player is currently a bit too fast and I think his jump is a bit too high, so let's modify our script to change that.
Let's close our game, go into our script, and at the top here there are two constants that we can modify. Our speed as well as our jump velocity. So I'm gonna set the speed to something less like 130 and the jump velocity to say negative 300. And now when we play, it looks and feels a lot better. So our player is moving around.
For current dates, there's not much to look at. So let's build a world to explore. World building 1.0. So to build our world, let's begin by removing our collider here.
We're going to build an actual ground for him to stand on and let's instead add a tile map node. So let's press new node and search for tile map. Now, the most common way to create levels in 2D is by using tiles. In other words, we build our game world by drawing different tiles onto a grid. This is a great way to work because we can create a lot of varied levels using just a few tiles.
The tile assets we use to paint are normally packed together into one big image, just like our player was. This is called the tile set. So the tile set is a collection of tiles that we can use to paint from, and the tile map that we just created is the node we use to paint these tiles into our world.
So to start painting on our tile map, we need to add a tile set. So in our inspector under tile set we'll create a new tileset and if we press it here we get to configure some things about it. The main thing you want to make sure is set correctly is the tile size. The tileset in our asset does indeed have 16 by 16 pixel tiles so we'll just leave that as is.
Now at the bottom here you can see that we have two tabs. We have the tile set and tile map. So before we can start painting with our tile map let's go into our tileset and configure this properly. The main thing we want to do is drag in our tileset asset. So let's go into our assets folder under sprites and drag in the world tileset.png.
It's going to ask us if we would like to automatically create tiles in the atlas. We do so let's press yes and now let's make some more room here and we can zoom in to view it. And as you can see it's actually gone ahead and automatically detected the grid cells that have tiles.
If for some reason it's made an error we can always use our eraser here to remove tiles. In this case here it thinks that the top of the palm tree is a bunch of different tiles, I'm going to use the eraser to get rid of these and instead go out of the erase mode and then hold down shift while clicking and dragging to turn this into one big tile. It's also split up the trees into three different tiles but in this case it's actually something that we want because it allows us to create trees of varying heights. I'll show you this once we start painting. Other than that I think it looks good.
So with this tile set set up we can now go to our tile map and start painting. Make sure that the scene has the select tool and that the tile map has the paint tool enabled. And now let's simply select a tile and start painting it in. If you make a mistake you can always right click to remove. So I'm just going to fast forward through me drawing out the level here.
As you can see I begin by blocking out the most essential game parts leaving in room for gameplay objects like moving platforms and enemies. And then only once I'm finished with that I start decorating. An nifty trick here is that you can select multiple tiles at once to paint in more than one.
And you can always go into select mode in order to select large chunks and move them. Now, once I'm ready to start decorating, let me just show you the cool trick with the trees here. So let's say we want to add a tree here at the top.
Well, then we can actually just paint the bottom and choose how tall we want the tree to be and then paint the top. So that's one of the advantages of working with tiles is that we can also make individual elements really, really flexible. So once you're happy with the level, let's just go ahead and press play and our player is going to fall right off. That's because we need to add a physics layer to our tiles.
To do this, we go to our tile map, go under our tile set, physics layers, and add a new layer. Then with this layer, we can go under our tile set and here we need to choose what tiles belong to the physics layer. because we don't want to collide with everything in our tile map.
The trees and bushes, we just want to pass right through. So let's go to paint here. And the property that we want to paint is the physics layer zero we just created. And now we can actually go ahead and paint onto our tiles these physics settings.
So I'm simply going to paint this onto all the different solid tiles. And if you make a mistake and want to remove a tile, we go here, select clear. And now we can paint with no physics, or we can go back to the default tile shape, which is the entire tile and paint with that, or simply hit F to do that.
So C and F are the shortcuts here. Now, there are also some tiles that we do want physics on, but where we need the collider to only be on part of the tile, such as our bridge here. So if I zoom in on our bridge, we can see that if I just paint physics onto these, it doesn't look right.
Instead, we need to go in and only paint a partial collider. So over here on the left, we can actually modify these colliders to exactly suit our needs. We can even add and remove points by clicking and right-clicking.
But in this case, four points will do just fine. And that's a good shape for our collider. Then we can paint these onto the three different tiles.
And then for the next one here, we can configure it. This slants up a bit. I'm gonna paint that on as well. And then for the final one here, let's go ahead and make that go in the opposite direction. And here you actually want to be pretty precise whenever you have an overlap of the colliders here.
I think that looks pretty good. This helps avoid that our character gets stuck. I'm also going to take the tile map and drag it to the very top so that we can always find it.
And now when we play, we are indeed colliding with our environment. Awesome. Now we probably want our camera to follow the player.
because he's currently just running off the screen. So I'm going to make some room here. I'm going to take the camera 2D and simply drag it under the player. Making it a child of the player means that it will just automatically follow the player node.
I'm also going to make sure that the camera is still positioned right on top of the player. And we can even turn on position smoothing to really smooth out our camera follow. So I'm going to enable position smoothing on the camera with a default speed of five pixels.
And now when we play, As you can see, our camera smoothly follows our player. Awesome. So now we have a first draft of our game world.
But so far, everything is stuck to the grid. Let's start adding some dynamic and moving elements, such as platforms. Platforms, some that move and some that don't.
So whenever we are creating a new element of our game, we begin by making a new scene. And for the root node here, I'm going to hit add and search for the animatable body 2D. This is a physics body that we use whenever we want to animate a node and still have it collide properly with other nodes in its path, which is perfect for moving platforms that should still collide properly with our player. So let's hit create and let's add some graphics.
So ctrl a, we'll search for sprite and select the sprite 2d and now we can drag in the texture we want. So let's go under our assets, sprites and drag in the platforms.png. Let's hit f and zoom in. And as you can see, this is also a sprite sheet and it's currently just displaying all of them.
So let's go in and define exactly which one we want to show. We can do this under Region, Enabled and hit Edit Region. And so we can kind of crop out the element that we want to show. I'm going to change the Snap Mode here to Pixel Snap and I'm just going to go for a default grass platform.
That looks good. And now when we close it, we can see our sprite perfectly cropped out. Again, we have the warning here, so let's go ahead and add a collision shape 2D. For this shape, I'm going to add a rectangle shape. And now we can simply click and drag this to configure it.
Then let's rename our top node here to Platform. And save the scene, so Ctrl S. In our scenes folder, hit save. We've actually created our platform, so in our game scene, we can drag it in, go under scenes, find the platform, drag it into wherever we'd like, and let's hit play.
And as you can see, it works! However, one problem right now is that we can't actually jump onto the platform from underneath. To fix this, we turn it into a one-way platform. So in our platform scene, let's select our collision shape and enable one-way collision. And now when we play...
We can jump onto platforms from underneath. However, the player is currently passing behind the platform. This is because the platform is currently after the player in the tree.
This means that each frame, the player is drawn first, and then the platform is drawn on top. We could just move the player in the tree, but I don't want to depend on that. Instead, we fix the draw order by changing the z-index of the player. So in our player scene, we go under ordering, and set the z-index to something higher like 5. By default, all visible nodes have a z-index of 0. Because they all have the same index, they are drawn according to their order in the tree. So by setting the z-index to a higher value like 5, we ensure that our player will always appear on top.
And now if we play, we can see that our player passes in front of the platform. So our platform is working, but it's currently just hovering there. We might want some platforms to move around to increase difficulty. So let's use animation to do that.
I'm going to leave this platform here as kind of a static platform. I'm just going to place it there. Then I'm going to place another platform over here by simply dragging it in. This is the platform that I would like to move back and forth. In fact, let me just go into the tile map and make this gap even larger.
There we go. So to add animation to this platform only, we simply select it, add a new node, and we want to use an animation player. Let's hit create.
And now we can add a new animation and let's name that move. Animation players in Godot are extremely powerful because they allow us to animate pretty much anything. In this case, we just want to do something really simple. We want to go to our platform and make a key frame under transform for the position. So I'll hit the key right here and hit create.
Then we can go forward in our timeline here to say, one second, move our platform to the right. So I'm going to click and drag. I'm also going to hold down shift to kind of snap it to one axis. Let's move it to there and let's add another keyframe.
And now we can see that if we play, the animation plays. We also want this to loop. So I'm going to select loop here.
However, this is going to loop in a way that it snaps back to the original keyframe. Instead, let's press it again. And now you can see that it's going to start ping-ponging back and forth.
If this is currently too fast, we can simply increase the length of our animation. So here's the length. Let's set it to 1.5 instead and drag our last keyframe to the end. And there we go.
We now have a moving platform. Let's just make sure that we set it to autoplay. And now when we play the game and go to the place where we made our platform, we can see that it's moving back and forth. And if we jump onto it, the player will smoothly follow it.
Really cool. And there's already so much you can do with this. Next up, pickups. Now let's add a coin that we can pick up. Again, we start by creating a new scene.
Let's create a new node, and let's this time search for area2d. This is a type of node that we use whenever we don't want to collide with other objects, but instead we just want to define an area in which we can detect collisions. So we simply use this to detect if another body enters, such as the player character. Let's create an area2d. Let's also add some graphics, so Ctrl A, search for Sprite, and we'll select the Animated Sprite.
Under Animation, let's add some new Sprite frames, select it, and let's load in from a sprite sheet here. I'm going to use the coin.png, zoom in on this, and this only has one grid cell on the vertical, and horizontally it has 12. And now we can click from left to right, or simply click and drag, and add the frames. Let's hit F and zoom in. Set the FPS to 10 and hit play.
And that's our coin animation. Let's make sure that this auto plays. And just like a normal physics body, an area 2D also needs a collision shape.
So let's add a collision shape 2D. And then for the shape, let's just choose a circle shape. Decrease the radius a bit. And that's actually all we need.
So let's select our area and rename it to coin and save the scene. And now we can simply drag it into our game. So under scenes, I'll take the coin and place it around the level.
You can always use Ctrl D to duplicate. And now if we play, we can see that the coin is here, but nothing happens if we enter the area. So it's time to make our first script.
So in our coin scene, we select the coin node and hit add script. This time for the template, let's just choose the default template. And for the path, let's make sure that this goes under the scripts folder. I'll create. And this is what it looks like when we create a default script in Godot.
We can see that we've created the script. on an area2d node, and that it's automatically made to function for us that we often use. Ready and process. Currently, both of them only have the pass keyword, which means do nothing. So this script, if we run it, will do absolutely nothing.
Now, the ready function is called right when our node enters the scene tree, which is just at the start of the game. So we can put code here that we want to happen immediately. Let's try it out by printing a quick message to see if it's working. So I'm going to write print, then in parentheses and quotes, I'm going to put I'm a coin.
And if we play now, the print doesn't do anything in our game, but it does show our message I'm a coin in the output window. This is also referred to as the console and is where we see messages such as prints and errors. However, you might also notice that the message displays multiple times.
That's because we currently have multiple coins around our game, and the script runs for each and every one. So since we have five coins, it displays I'm a coin five times. But we don't want anything to happen when we start the game.
So I'm actually just going to remove these two functions. Instead, we only want to do something once our player enters the coin area. And for this, we use a signal. Signals allow us to trigger code based on events that happen in our game. Godot has many......
built-in signals we can use. If we select our Area2D node and go to the node tab, we can see all the signals on this node. We want to use the body entered signal, which is triggered whenever a physics body enters the area.
Since our player has a character body 2D node, this is going to trigger the signal. So to connect it, we simply double click it and hit connect. As you can see, this creates a new function in our script called onBodyEntered.
with a green arrow that shows that this is triggered by a signal. So let's here try writing a print function that says something like plus one coin. Now when we play and enter the coin area, it's going to print plus one coin.
However, this message will actually display no matter which body enters the area. If we take one of these coins here and put it in the way of a moving platform, for example, this will also trigger the message. So now right when we play. we can see that it starts displaying the message and we'll do so every time the platform passes through the area.
To change this, we can either use code to check what body enters the area or we can simply put our player on a separate physics layer. Let's try that out. So under our player, we'll go to the inspector, go to collision, and here we can change the physics layer from layer one to two.
Let's hit control S to save. And then in our coin, we can also go under collision. we can actually have the coin itself stay on layer one.
We don't need a separate layer for that yet, but we want to make sure that it only detects colliders in layer two. For this, we use the mask. The mask defines what layers a node collides with.
So let's set that to layer two because that's the layer that our player is on. That should actually do it. Now our coin will only detect collisions from our player. And instead of just displaying a message, let's also remove the coin from our scene when we...
pick it up. So in our script, after printing one coin, let's add a new line, we'll call the queue free function, which is simply going to remove the entire coin scene from our game. And indeed it does. And our knight can now start gathering some coin. Now, depending on what type of loot we pick up, we want different things to happen.
In this case, I want to display a score that increases when we pick up a coin. But we'll look at that when we get to text. First, I think something a bit more pressing is dying and restarting our game. Dying 1.0. So we happily move along in our world until suddenly we miss a jump and fall into the abyss.
And then nothing happens. Let's change that. The first thing we want to do is limit our camera so that it doesn't follow our player when we fall down.
Luckily, this is really easy to do. We simply select our camera under the player, go under limit, and here we can set a position limit for the left, top, right, and bottom part of our camera. In our case, we need to set a limit for the bottom position. To do this, we can use the ruler tool here at the top, or simply press R, and measure from this baseline here to where we would like the limit of our camera to be. I think a good value would be somewhere around, say, 120. So I'll simply go back to select mode and put in 120 pixels on the bottom.
I'm also going to enable smoothing. And now when we play, we can see that our camera will follow the player, but whenever we fall off, it's simply going to stay put. Next, we need to detect that our player has entered a dangerous area and restart the game. In other words, we need to create a kill zone. I'll show you a really cool way to do this that allows us to reuse the same kill zone for more than just falling off the map, such as for spike traps, enemies, all kinds of elements of danger.
And when we want to create a reusable element, we start by making a scene. Then to detect if we enter an area, we again use the area2D node. And let's make sure to set the collision mask here to two. We only want to check for the player, which is on layer two. And we want to add a collision shape here.
That's because we want to be able to reuse this for all kinds of elements that might have different shapes. Instead, let's simply go ahead and rename this now to Kill Zone and save it as a new scene. Then in our game scene, we can add it by dragging it in or simply pressing the link button here and selecting the Kill Zone.
And then in here, we'll add the collision shape. So I'm going to hit Ctrl A, Collision Shape. And for the shape, we'll use the same world boundary shape that we used earlier for the ground.
Now let's make sure to select the Killzone node itself, go into Move, and use the Move tool to position it down here at the bottom. I'm going to place it pretty far down, so we're sure we don't hit this by accident. Or I mean, we're going to be hitting it by accident.
So let's make sure we don't hit it on purpose. Or I mean, I don't know. Anyways, I'm going to place it down here a good bit away from our level. And now we can add a script to make something happen when we enter the area.
So in our kill zone, let's select it, add a new script. For the template here, I'm just going to select empty and the path, let's put it under the scripts folder. And now we have this empty script to play with. I'm going to connect a signal. So go node, make sure we have the kill zone node selected.
And again, we'll use the body entered signal. Let's double click it, hit connect, and it's going to create a new function on body entered, in which case we can go ahead and print that you died. And now if we play and jump down, it's going to print that we died. Now, instead of immediately restarting the game, let's add a small delay.
We do this using another node called the timer node. So let's add a new node, search for timer, and under the inspector here, we can choose some different things about it. Let's set the wait time to something like 0.6 seconds.
Let's also make it a one shot to make sure that it doesn't loop. We can then start this timer in our code. To do that, however, we first need a reference to it.
Luckily, that's as simple as going to the top of our code, clicking and dragging the timer node and holding down control while releasing. This creates a variable. called timer that automatically finds the node using this path. Now if you haven't worked with paths before they are actually quite simple. They specify a way to get from one node to another in the tree.
So if we look at this example tree to get from the game node to the camera the path looks like this. It goes through the player and ends with the camera. And in our case where we just want to get from the kill zone to the timer right underneath We don't have to go through any other nodes, so the path is simply timer. Again, right now we are brushing over concepts such as variables and functions pretty briefly, but you can learn more about programming and what all this really means in our upcoming video on GDScript. For now, just know that using this click and drag method, we can now access our timer node using the name timer.
So to start our timer, we make a new line and write timer.start. Of course, we now need to trigger some code when our timer runs out. And again, we can use a signal for this.
So with our timer node selected, let's go under node. And here's the timeout signal. So let's double click that and hit connect. And this creates a new function called onTimerTimeout that runs when the timer ends. And then in here, we can simply restart our game.
To do this, we first access the scene tree. So get tree. and tell it to reload, so reload current scene.
So our player enters the kill zone and triggers the onBodyEntered function. This prints a message that we died and starts the timer. When the timer runs out, it triggers the onTimerTimeout function, which then reloads our scene and restarts the game.
And indeed when we play and jump off the map, we fall down and the scene restarts. Great! It's an infinite loop! Help me!
I'm stuck! Worldbuilding 2.0 Let's expand on our game world a bit now that we have more elements to work with. First of all, I want to make sure that we stay organized. So let's take some of these nodes and categorize them.
The easiest way to do this is by simply adding a new node. For this one, I'm just gonna select the base node here, hit Create, and now we can rename this. I'll make one for say coins, and simply take all of the coins and drag them under that node. We can do the same thing for platforms and any other elements that are cluttering up your scene.
Now I'm gonna paint in a bit more level and change the things that I don't like. And I'll put in some more gameplay elements. I'll also paint in some background tiles. But to do this, we need to add another layer to our tile map.
So not under our tile set, but under the tile map itself, we have this layers. And this is the one we've been painting in. Let's just call this mid for mid ground and add another one that we can call background.
Let's move this to the top to make sure that it's drawn first. And now when painting, we need to select the right layer to paint on. So let's select the background and then we can start painting in some background tiles.
A nice trick here is to use the rectangle tool to paint in a lot of tiles at once. And now our game looks a lot better. It has a background and a whole new part of the level that we can explore. And of course this process is just about trying things out and making changes until you're satisfied.
Enemy A proper hero of course needs a good enemy. So let's make one. Let's create a new scene. And since this enemy doesn't need to collide with anything, we can just go ahead and use a node 2D as the base.
Let's also add an animated sprite. So I'll search for animated sprite 2D. Let's go to animation, add some new sprite frames, select them, and let's load in from the sprite sheet here. In the pack, there's both a green and a purple version of the enemy. I'm just gonna choose the green one.
And this is a four by three. And I've included three animations here, one for the enemy kind of waking up, an aggressive idle animation, as well as one where the enemy takes damage. So I'll use the idle animation here. Let's add these four frames. Let's hit F and zoom in.
I'm also going to move this up. Set the animation to autoplay and the FPS to 10. And now if we preview, we have an animated slime. And this is where things get really cool. Because we made our killzone into a reusable scene, we can simply use it for our enemy as well.
So at the top here, I'll add in a new scene. I'm going to select the kill zone. And now all we need to do is give this a collider. So control A, search for a collision shape.
Let's add in a rectangle, fit it to fit our enemy. By the way, I'm holding down Alt to scale uniformly. And with that, we can simply rename our top node here to slime and save it as a scene.
Now in our game, we can drag it in. I'm going to place it over here. And if we play now and move to the enemy, we can see that just by throwing together a couple of nodes and reusing our kill zone, we've successfully added a new element of danger to our game. If we enter the enemy, we can see that indeed our game restarts. Of course, currently dying doesn't look very exciting, we'll fix that in the next chapter.
But first, let's make our enemy move back and forth. We could of course do this using an animation player, just like we did for our platforms. However, I think it would be cooler to make a script that moves our enemy to the right until we get close to a wall, in which case it changes direction and starts moving left. This way we can simply drag and drop the enemy between any two walls in our game and our script will do the rest. So let's start by making our enemy move to the right.
So I'll go into the slime, add a new script, use the default template and place it under the scripts folder, and hit create. Let's get rid of the ready function. And instead we are going to be using process. Just like movies, video games display motion by drawing frames and showing them in quick succession. While movies show frames at a fixed rate, most often 24 frames per second, video games generally try to draw as many frames as possible to get a smooth result.
How often this happens will depend on the system the game is running on and what is happening in the game. But unless the game is lagging, it should draw a new frame at least 60 times per second. And and often much more.
Before the computer can draw a new frame, however, it first has to update the state of the game. What has happened since the last frame? It does this for all the nodes in our game. Then it draws the new frame. This is referred to as the game loop, because it happens over and over again and it is really the driving force of our game.
Godot of course does this automatically, but we can add functionality to the game loop using the other function in the template. Process. Unlike ready which only runs once, Process runs every frame. This makes it perfect for doing things over time, such as moving an enemy.
We simply make sure to change the position of the enemy a tiny bit each frame. So in our script, we can simply remove the path keyword and instead access the position of our slime, more specifically the X coordinate of our position, and add one pixel to this every frame. Then in our game, let's go ahead and place a slime close to our player so that we can see this happening and play. And as you can see, the enemy just shoots past us on the screen. Now, one problem with this that might not be obvious, other than it's moving way too quickly, is that we are increasing the X position every frame by a fixed amount.
And because our frame rate can vary, this means that the enemy will sometimes move faster than others, which is not very good. To fix this, we use this little thing here called delta. Delta is the amount of time that has gone by since the last frame. If we are drawing many frames per second, Delta gets really small. And if we lag out a bit and are not drawing as many frames, Delta becomes bigger.
Because of this, we can use Delta to compensate for variations in frame rate. If we have a high frame rate, we want to only move our enemy a little each frame. And if we have a low frame rate, we want to move it a lot. In other words, we can multiply our movement by Delta to make it independent of the frame rate. Now, Delta can be a bit hard to wrap your head around at first, but don't worry.
you'll get the hang of it. A good rule of thumb is that whenever we have a speed value that we can adjust, such as our one here, we should probably multiply it with delta. So in our script, we simply go plus equals one, multiply it with delta. Now, what this essentially means is that we are going to be moving one pixel per second, which is not very fast. So let's instead change this to something like 60. And we can actually store this speed in a constant at the top of our script.
just like in the movement script. So here I'll write const speed and set it equal to 60. Then we can simply use speed here instead of hard coding the value. This makes it easy to change constants right at the top of your script. And now if we play, we can see that our enemy is moving at a reasonable rate and we know that this speed won't change from system to system. So let's get rid of this extra slime here and instead make this one actually change direction whenever we face a wall.
To do this, we need a way to control the direction we're currently moving in. So let's create a variable that does this. We'll create a var, call it direction, and set it equal to one by default.
Then if we need to go in the opposite direction, we'll set it to negative one instead. And to actually apply this, all we need to do is multiply it into our speed. So we'll go direction times speed times delta.
This is a really standard way of doing movement. We simply add onto our position in a direction, multiplied by speed and delta. So now all we need to do is check if the enemy gets close to a wall. And for this, we'll use a new type of node, the raycast node.
Raycasts are invisible rays that we can shoot out to detect collisions. So inside of our slime here, let's add a new node of type raycast2d. And as you can see, it draws an arrow to represent this.
Let's move the starting point here to the center of our enemy. and let's have it shoot out to around here. I'm gonna rename this to Raycast Right.
I'm then gonna press Control D to duplicate. I'm gonna have this shoot out in the opposite direction and rename this to Raycast Left. Now in our script, we can reference these nodes just like we did with our timer. We simply select them both, click and drag and hold down Control while releasing.
As you can see, this creates two variables. one raycast right and a raycast left. Then every frame before we move our slime we will go ahead and check if we are currently colliding to the right or to the left. If raycast right dot is colliding if this raycast is hitting something well then colon and then make sure to indent here with the tab we will set our direction to be negative one.
If we are colliding on the right we want to move to the left. And we'll add another one of these if statements. So if raycast, you guessed it, left, dot is colliding.
Well, then we'll set our direction back to one. And that's it. Our enemy is now ping-ponging back and forth between the two walls. And this is happening completely automatically through script.
Really cool. Now, the only thing that is left is to flip the enemy sprite when it changes direction. Luckily, if we go inspect our animated sprite here, under offset, we have this flip age property, which will simply flip the sprite. So let's control this through our script. In our script, we'll get a reference to our animated sprite 2D.
This creates a variable called animated sprite 2D. I'm just going to get rid of the 2D here to make the name a bit shorter. And then whenever we are colliding on the right here and we change direction to move towards the left, we will also go to our animated sprite and set the flip age property to true.
And when we are colliding on the left and we're changing direction again, well then we'll go to our animated sprite and set flip age back to false. And that's it. That's our entire script.
Let's find our enemy here and hooray, we've made an enemy. and a slimy one at that. But of course, dying to the enemy could definitely look cooler.
So let's fix that. Dying 2.0. Let's start by adding a slow motion effect when we die.
We can do this by changing the time scale of the entire game. So inside of our kill zone, we'll open up the script here. And right after we print you died, let's modify our time scale.
So I'll go engine.timescale and set it equal to 0.5. This means that we will go at half speed. Then when our timer runs out, let's set this back to default because otherwise we will actually still be slowed down when our scene reloads.
So we'll go engine.timescale and set it back to the default one. And if we play this now, this is actually already much better. Notice that it also takes twice as long before the game restarts because everything in our game slows down, including our timer. But I think it could be even cooler if we remove the player's collider to make him simply fall off the map. To do this, we need a reference to the player.
We actually already have this here. You'll notice that after the onBody entered here, there's a variable called body. This refers to the body that entered the area. And since the only thing that enters the kill zone is our player, body is our player. So we can actually add a new line here that goes to our body.
And then we simply need to get the collision shape node under our player. So we'll do.getNode and we'll search for the collision shape 2D and we can remove it. So we'll call.qfree on that node. Again, qfree means to remove that node. So here we're accessing our player, getting the collision shape node and removing it.
And now if we find our way to some danger, boom, we are hit and we fall off the map. Cue the sound effect. Player 2.0. So far, we've been using the character movement template pretty much as is, but we need to modify it in order to add animation to our player, as well as change the key bindings that we use to move.
So what are we looking at here? Well, the top two lines define two constants with our speed and jump velocity. There's also a variable here that defines the gravity based on our project settings. By default, this is a value of 980. So we have these three values, but the meat of the script is really inside of this physics process function.
Physics process is very similar to the process function we used for our enemy. However, while process is great for a lot of things, there is one part of the game engine that really struggles with not knowing how many times per second it is going to be run. That is the physics engine. Physics in general need to update at fixed intervals to avoid janky behavior. Luckily, physics process solves this problem, because it runs at a fixed rate, 60 times per second by default.
This is independent of your game's actual framerate and helps physics run smoothly. We use it for anything that involves the physics engine, like moving something that should collide with its environment, such as a player character. So in this function, a few things are happening. If the player is not standing on a surface, we add gravity.
If we press the spacebar and the player is standing on a surface, we add gravity. is on a surface, we jump, and then we get the direction we need to move in based on what arrow keys are pressed and move accordingly. Now let's start by rebinding some input keys.
For this, Godot uses an action system. We create actions for anything we want to do in the game. Jump is an action, so it's move left or move right.
We can then bind keys to these actions. Let's try it out. So let's go to project, project settings, input map, and here we can add some actions. I'm gonna add a jump action as well as a move left and a move right.
Then we can use the plus sign over here to bind a key. So to my jump here, I'm gonna hit plus and then it's listening for input. So I'm gonna press the space bar and hit okay. And as you can see, space is now bound to jump.
For a move left, I'm gonna bind the left arrow key, and I'm also going to bind the A key, so we can use Vast for movement as well. As you can see, there's no problem binding multiple keys to the same action, which is really handy. I'm also going to bind right arrow to move right, as well as the D key.
And now we can use these actions in our script. By default, Godot uses some built-in actions that are meant for navigating UI. This is why it says things like UI accept here. Let's replace these with our own actions instead.
And as you can see, it will actually help us by auto completing here. So I'm going to put in jump for my jump action. And then for moving left here, I'm going to change to move left. And for moving right, I'm going to change to move right. And now we can use the keys bound to our actions to move around, which in my case are both the vast keys and the arrow keys.
Awesome. The next thing we need to do is to update our player graphics to face the direction we are moving in and to play the right animation. Let's start by flipping our sprite based on direction. So just like with our enemy, we first need a reference to the animated sprite node.
Again here we can simply click and drag and hold down control. Again I'm gonna remove the 2D from the name to make it shorter and then we'll add some extra code to our function. Now this line here defines a variable called direction that is based on our input. If we don't press any buttons, direction will be zero.
If we press move right, direction will be one. And if we press move left, direction becomes minus one. So we can use this variable to check if we are moving left or right. I'm going to make some space in the code here and make my own comments as well. So use a hashtag for a comment.
This here gets the input direction, which can either be minus one, zero or one. And this down here actually applies the movement. So in between, we can add a section that flips the sprite. To do this, we check if our direction variable is greater than zero. Well that means we are moving to the right and we can set animated sprite dot flip horizontally to false.
If this is not the case, well then we want to check if our direction is less than zero. For this we can use the elseif or elif keyword. So elseif our direction is less than zero.
Well then we'll set animatedSprite.flipAge to true. And now if we play this, we can see that our player sprite indeed faces the right direction. Now let's add some animation.
So let's go to 2D view, select our animated sprite, and let's add two new animations. One called run and one for jumping. In our run animation, I'll add some new sprite frames.
Select our knight. Remember this is 8x8. and I'll simply add all of the frames in the run animation, which stretches over two lines here. I'll add those frames, set the FPS to 10, and play. Looks good.
Then for the jump animation, I'll also add a sprite frame, and there are a bunch of different ways to go about this, but in our case here, I think we should actually play our jump animation whenever we're just in the air. This means that this will also play when we're just falling off a platform. And for this, we could use a very quick looping animation or simply a single frame. I actually like this one from the roll animation. So I'm just going to use that.
Then in our script, we can of course play these animations. So after we get the input direction and flip the sprite, let's add a new segment, which is going to play animations. And here we also need to check our direction variable. More specifically, if our direction is equal to zero, well then we're standing still and we can go ahead and play animatedSprite.play the animation called idle.
If this is not the case, so else, well then we want to play animatedSprite.play the run animation. And that's actually it. If we now start running, we can see our run animation being played. Finally, we just need to add our jump animation.
And here we can use a built-in function of our character body2D, which is to check if we are standing or not. on the floor. So at the top here we'll check if we're currently on the floor is on floor.
Well then we want to go ahead and play our idle or run so I'll cut this using ctrl x paste it in here make sure you tab in and if we are not standing on the floor well then we're in the air and we can go and play animated sprite dot play our jump animation instead. So if we're on the floor and our direction is zero well then we're playing idle If it's not zero, well then we're playing run, and if we're not on the floor, we aren't doing any of those things, we're just playing the jump animation. And that's it.
Now if we play, we have a fully animated knight. I like to think that she's a former princess who got so tired of waiting to be saved from the big bad dragon that she took matters into her own hands. Who better to save some princesses from a dragon than someone who knows dragons like her own back pocket. But feel free to make up your own story. And that reminds me.
Story. We need a good way of communicating story. hints and other valuable information to the player.
And to do this, we need text. So let's add some text elements to our game. Text.
There are multiple ways of working with text in Godot, as part of a larger UI or as an integrated part of the game world. For this game, I decided to try making the text part of our world. In Godot, a text node is called a label.
So let's add one. Let's hit Ctrl A and search for a label. Let's focus on it.
And as you can see, this creates kind of a bounding box for our text. So I'm going to put it over here and scale it up a bit. And let's add some text in the field here. I'm going to put in a gameplay hint.
And as you can see, the text looks really blurry. That's because since we're using pixel art, we're actually zoomed in really, really far, which makes the otherwise smooth text appear blurry. So we can fix this by using a pixelated font with hard edges to match our style. I've of course included some in the assets. So let's go under theme overrides on our label, fonts.
And here we can drag in the pixel operator font. We can also change the font size on the font sizes here, enable that, and I'm going to set mine to eight. Note that we have to use multiples of eight in order for the text to appear crisp.
So you can see if I change this to nine, it becomes blurry again, but we can use 16, 24, 32, and so on. I'm also going to go to the colors here and change the font color using the color picker. And now we can place these text elements around our game to provide story or gameplay tips. Once we're happy, we can categorize all of them under a node.
So let's create a node, call it labels and drag all of them under that. And now when we play, as you can see, they appear as a natural part of our game world. And just like with sprites, because the player character has a greater z-index, it will draw on top. So let's use one of these text elements to display our current score.
Score and Points To create a score or a coin counter for our game we need two things. A script that keeps track of our current score and a label to display it. It's common practice to place game-wide variables such as a score inside some kind of game manager.
So let's make one. We'll hit Ctrl A to add a new node. Let's rename it GameManager.
and I'll place it right at the top here. The reason why we are using a regular node and not a node2d is because we don't need our game manager to have a transform, in other words, a position, rotation, and scale. Now let's add a script to our game manager.
We'll use the empty template. And for the path here, let's put it inside of our scripts folder. And let's also rename it with non-capital letters.
Create. And let's create a variable for our current score. So we'll write var for variable. name it score and default it to zero. Now so far in our code we've only used the built-in functions of Godot and some that we made with signals.
In this case here we want to create our own function that adds a point to our score and displace it. So I'll write func for a function, we'll name it addPoint, open and close some parentheses and put a colon. Then on a new line we'll write score plus equals one to increase our score by one and print our current score.
Now, unlike ready, which runs at the start of our game and our signal functions, which run when a signal gets triggered, this function currently has nothing that calls it. So right now our function is here, but it isn't being run. To change this, we need to go into our coin script and tell it to call this function whenever a coin is picked up. So inside of our coin script, we need a reference to our game manager. But if we just click and drag while holding down control, we get this really weird looking path.
This is because the game manager is higher up in the tree than the coins. And it's generally bad practice to use paths like this that try to access nodes at the same level or higher in the tree. Luckily, because our game manager is a one of a kind, and we are sure that there will always be only one game manager, we can solve this by marking it as unique. So let's right click our game manager and select access as unique name. As you can see, this creates a percentage icon next to the game manager, letting us know that it's a unique node.
This makes it much easier and safer to get a reference to the game manager because now when we drag it in... Instead of a dollar sign with a weird and unpredictable path, we get a percentage sign, which means that Godot quickly finds the node via its unique name instead of using a path. One limitation of this is that you can only access unique nodes from within the same scene.
If the GameManager and the coins were in different scenes, this wouldn't work. Now in our function we can replace the print line here with GameManager, access our GameManager and call the function addPoint. And now when a body enters our coin, it's going to go to the game manager and run our add point function. And if we play, we can see that every time we pick up a coin, it increases and prints our score in the output window. Finally, we can use what we learned about labels in the previous chapter to create one for displaying our coins.
I'm gonna make a little place for this in our level. For now, I'll just put in some text that says you collected X amount of coins. I'm also going to change the auto wrap mode to word.
Now we can wrap our text and the horizontal alignment to center. Finally, I'll use a bolder font. Now we can take this label and rename it to something like score label.
And since we want to change it from our game manager, let's drag it right under our game manager. Now in our script, We get a reference by clicking and dragging, holding down control. And instead of printing our score, we'll go into our score label and access the text property and change it to you collected.
And then here I'm going to add the number, add the score onto that amount of coins. Notice how I make sure to add spaces between the words. And while this looks good, it's actually going to give us an error. And that's because we need to change this. score here from a whole number variable called an integer into a text variable called a string.
Again we'll talk much more about variables in our video on GDScript. But for now we can cast this using str for string and then wrapping it in parentheses. And now when we play and pick up some coins along the way here, once we get to the end it says great job you collected six coins. And if I pick up another one, it's going to update to Awesome! And I don't know about you, this is great and all, but I think it's distinctly lacking a Bling sound when we pick up a coin.
Bling bling bling! Audio. One of the things that often get overlooked when making a game is audio.
But music and sound effects are a huge part of building the mood of your game. This is of course a beginner's tutorial, but let's at least get our feet wet, or should I say our ears wet. Nope, I shouldn't. Let's at least add a music track and a pickup sound for our coins.
Now in the assets, I've included a music track as well as a few sounds. And to play these, we need a new type of node, the audio stream player. So let's add a new node, search for audio stream player 2D. Let's rename this to music.
Then we can take our music track here, time for adventure, drag it into the stream slot. We're also going to set it to autoplay and by default this is not going to loop. To change that let's double click it.
This is going to open up our audio importer. Here we can preview our music track. Groovy. Anyways we can loop so let's enable loop here and hit re-import.
Now by default all sounds are played fairly loud and since this is background music we probably want to turn it down a bit. We can do this by adjusting the volume on each individual auto stream player or we can use the audio tab here at the bottom. This is actually a fully functioning audio mixer and we can add different buses to control our audio.
Let's add two, one for our music as well as one for sound effects. And then we can simply route our music here into our music bus. So now we can control the volume of our music using this slider.
I'm just going to set it to negative 12. And we have music. Unfortunately, it's going to restart whenever our scene is reloaded. A quick fix for this is to take our music node and make it into a scene. So I'll click and drag it into our scenes folder, hit save, and then we can add this scene as an autoload.
Autoloads are global scenes and scripts that we want to persist throughout our entire game, no matter which scene is currently loaded. So let's remove music here from our game scene and instead go to project project settings autoload. We'll click the little folder here and navigate to our music scene and hit add.
We've now registered our music scene as an auto load, which means that if we now play, even though our music scene isn't in our game, it automatically loads and starts playing our track. And even better, it doesn't reset when our game restarts. Now to add a pickup sound, we go to our coin and add an audio stream player. Let's rename this to Pick Up Sound.
Drag in our coin sound and set the bus here to sound effects. And now we can actually play this sound through script. But since we are removing the coin immediately by calling the QFree function, the sound won't actually get a chance to play.
We can of course fix this by adding code that waits until the sound has finished playing, but then we might get weird functionality where we try to pick up the coin multiple times while it's playing and it will still be visible until the sound is finished. So let me show you a really cool trick to get around tricky timing things like this. without writing any code, that is using an animation player.
So let's add an animation player. And here we'll create a new pickup animation. And the first thing that we want to do when we pick up the coin is to hide the coin sprite.
So I'll go into the animated sprite 2D and this will change the window. So I'll go back to animation here. And now under visibility, I get to keyframe the visible property.
Now, when working with animations that don't need to play until later in the game, it's nice to be able to go back to the default values after animating. By default here, our coin should be visible. Now, this is pretty cool. If I just create a key frame here for the default value, Godot is going to ask to create a reset track.
If we say yes to this, Godot is automatically going to create another animation track called reset that will simply reset this value to its default state. So now in our pickup animation, we can keyframe it to whatever we want. In our case, when we pick up the coin, we want it not to be visible.
So I'll disable that, keyframe it. And then if we want to go back to our default values, we simply go to our reset track and there it is. It goes back to default. So let's go to our pickup.
Let's also modify our collision shape. We don't want to be able to collide with it while it's playing the sound. So let's simply go ahead and add a default key here for the disabled property.
Hit create. And now we can set disable to true and add a new key. We can also go into our pickup sound here and let's add a default key for the playing property.
Let's hit create. And now since the sound plays pretty quickly, I can actually reach the key in time. So we can go down here instead.
I'm just gonna scale this up a bit. Go down here to the value, the key frame here and change it to on. So we can actually modify the key frames here as well. So now we have our pickup animation, and if we go to reset, we can see that everything goes back to default. So that's just a nice way of working with animation.
So now we play the sound, disable the collider and hide the sprite. After one second though, we can go ahead and remove the coin from our scene. So all of these keyframes here are on second one.
Let's put them over to right at the beginning of our animation at second zero. And then after one second here, we want to remove our coin. And this is a really cool part about the animation system is that we can actually add another track here, a call method track that is used to calling functions.
So on our coin, we want to call a function and I'll right click right where we want to do that, insert key. And the function that we want to call is the queue free method, which is right here. And so now after one second, it's going to call the queue free method on our coin without us writing any code. And voila.
All the things we could have done through code are all inside this animation. And again to get back we simply choose reset. Now all that is left is playing the animation through script.
So in our script we'll get a reference to our animation player and then instead of directly calling qfree we'll go animationplayer.play pickup. And if we play now we can hear our music and we can hear our pickup sound when we run into the coins. Awesome! Export!
Finally, we are ready to export. Really incredible that you made it this far. You can feel very proud.
So let's get our game out of Godot so we can share it with others. Godot can, of course, export to many different platforms, but I'm on a Windows computer here, so let's go ahead and make a quick Windows build. The first time we are exporting our game, we need to download the export templates.
These are a little large, so to keep Godot lightweight, they aren't included by default. To install them, we go to Editor, Manage Export Templates, and hit download and install. And the export templates are installed and ready to be used so we'll close, go to project and export. In this window we'll add a build platform so let's go add windows desktop. We'll enable Embed PCK, which will export it into a single file.
Then we scroll down. As for the product name here, I'm going to type in Princess Dragon Slayer. And we can hit Export Project.
I'm simply going to put this on my desktop. Uncheck Export with Debug and hit Save. This warning is not a problem. We'll hit OK.
And now on the desktop, we have this first game.exe. We can open that up. And voila, we made a game.
Woohoo! And that's it! Congratulations on making your first dish, or I mean game in Godot. If you don't understand everything or aren't sure about where to go from here, don't worry. That's totally normal.
It takes a little while to become familiar enough with the tools to feel really free with them. Never hesitate to use the documentation, tutorials or code examples you find online. When I started out, I spent a lot of time remixing other people's scripts before I started to write my own.
Now, where do you go from here? Well, that's totally up to you, but if you want to continue adding to this game, here's a list of things that you can try out. Expand the level. See how far you can get using just what you know now. I think you'd be surprised with how much fun gameplay you can get out of just these simple elements.
Add effects, like an animation or particles when picking up a coin. Or more sound and music. Add more danger elements like spikes or traps that turn on and off.
Most of these are just variations on the kill zone we've already made. Add a main menu, more enemies, give the player a weapon or add power-ups. You can also expand on the game manager, for example to use it to switch scenes. A common way to do this is by turning it into an auto-load, just like we did with our music track.
Or perhaps you want to improve player movement by adding coyote time and double jumps. The possibilities are endless. Also, don't forget to check out Zenba Academy. Be among the first 50 people to use the coupon code below to get 20% off the first year of your Zenwa subscription.
And that's it for making your first game in Godot, and I wish you the best of luck on making your second one.