Learn Godot Game Development: From Basics to 3D Shooter
Course Overview
- Create seven diverse games using Godot engine: runner, platformer, farming, monster battle, 3D space shooter, 3D platformer, 3D shooter
- Suitable for complete beginners: no prior coding knowledge required
- Option to access full course on Patreon or Udemy
Godot Engine Basics
- Understanding video game frames and real-time frame creation
- Godot’s scene and node system as building blocks for game elements
- Importance of scene trees, nodes hierarchy, and parenting
- Using 2D and 3D viewports and editor customization
GDScript Fundamentals
- Writing and attaching scripts to nodes
- Variables, data types (strings, integers, booleans, arrays, dictionaries, vectors)
- Functions with parameters, return values, and scope
- Conditional statements (if, elif, else) and loops (while)
- Using signals for event-driven programming
Practical Coding Exercises
- Create a Godot stick figure using nodes and scenes
- Implement bouncing sprite with position constraints
- Perform math calculations like Pythagoras’ theorem using GDScript
Game Development Projects
Frogga Style Game
- Project setup: scenes for game, player, backgrounds
- Applying sprites and configuring viewport and resolutions
- Player movement with keyboard input and vector math
- Camera setup to follow player with smoothing and limits
- Collision handling with physics bodies
- Scene organization and node management
- Spawning cars via timers and adding animations and colors
- Managing game flow: title screen, score timer, scene transitions
- Sound integration for background music and effects
Metroid Style Platformer
- Advanced animations: animation player and tweens
- Tile map layers for building levels with collision shapes
- Player movement including jumping and shooting with reload timer
- Implementing enemies (drones) with area detection, movement, health, and explosion animations
- Shader basics and flash effects on hit
- Using groups to manage multiple enemy instances
3D Space Shooter
- Transition to 3D: nodes for 3D objects, meshes, and camera
- Importing and setting up GLB 3D models
- Lighting systems: directional light, point light, shadows
- Basic 3D player movement using CharacterBody3D
- Shooting mechanics with lasers and meteors
- Spawning meteors with randomized positions, speeds, and rotations
- Collision detection and game termination on impact
- Materials and shaders for advanced visual effects
- Obstacles placement and randomization
- Camera positioning and smooth player follow
- Final polish: adding sounds and animated effects
For strategic insight into shooter game mechanics and player tactics, check out Mastering Positioning in Third-Person Shooters: Essential Strategies.
Tips and Best Practices
- Organize scenes and nodes to keep clean structure
- Use Godot’s built-in documentation and editor hints liberally
- Employ signal connections for decoupled event handling
- Manage collision layers and masks to optimize interactions
- Use delta time in physics updates for frame-rate independent movement
- Leverage tweening for smooth animations
- Customize shaders for enhanced visuals
For a comprehensive guide on Godot horror game creation, which complements skills in scene and node management, explore Godot में बिना भूत के हॉरर गेम कैसे बनाएं: पूरी गाइड.
Conclusion
By completing this course, you will gain a solid foundation in Godot game development, covering 2D and 3D games including coding, scene management, animations, physics, input handling, audio, and user interface design. You will be equipped to create complete games and expand into various programming areas confidently.
[Music] Hello. In this course, you're going to learn how to code by making games in
Godot. We will create seven games in total. A runner game, a platformer, a farming
game, a monster battle game, a 3D space shooter, a 3D platformer, and a 3D shooter.
All the games will be made in the popular game engine Godot, which is entirely free and super easy to use.
By the end of this course, you will be able to create games and you should feel comfortable coding. Meaning you can
branch out into other areas like data analysis, AI, or app development. For this course, there are no requirements.
I will assume that you have no coding knowledge at all. Although, if you can code already and
you just want to learn Godot, you can skip the first part and jump straight into game development.
You can get this course on Patreon for £5 a month. On there, you also get all of my other
courses and you see future courses early. And if you don't like subscriptions, you can buy this course
on Udemy for about $10. This is why for the super regular discounts. And if you don't want to buy anything,
this video contains the introduction to coding and three of the games. The runner, the platformer, and the basic 3D
shooter. This will teach you all the basics of coding and Godot. So, I hope you enjoy.
Before we start coding, we need to talk about how video games work to understand what a game engine like Godot does.
Fundamentally, any video game is just an interactive movie. Like in a movie, we are playing
individual images in sequence. And for some reason, these images are called frames. If that happens fast
enough, it looks like a movement. For a movie, that is usually 24 frames per second. For a video game, you want
to have at least 30. Now, the difference between a movie and a video game is that video games
dynamically create each frame depending on player input, enemy movement, timers, and a range of other options. So, what a
video game engine like Godot does is it first calculates where stuff needs to be.
For that, it checks player input, the movement of every object, if an enemy was defeated, and loads of other things,
whatever you specify. And once all of that was calculated, we are drawing one frame.
This we do at least 30 times per second until the game is over. This is how any video game works.
So, Godot basically is giving you tools to capture user input, it lets you draw images and 3D objects, it can play
sounds, and you can use it for lots of other more advanced things like physics calculations, light simulation, and even
online communication. Godot is a really powerful tool and it is entirely free and open source.
To get it, all you have to do is go to godotengine.org and click on download latest.
The website should then give you the right download link. If you want something specific, just
scroll down. Godot works on basically any platform. Just choose what works for you.
Once the download is done, unzip and open the folder and then click on the icon that doesn't say console.
You should be seeing a dialogue like this. And yes, Godot does not need to be
installed. Just keep the downloaded folder somewhere safe so you don't accidentally
delete it. With this dialogue, you can manage all of your Godot projects. At the moment, we don't have any.
To fix that, you can either create a new one or import an existing project. I want to create a new one. Then you get
a create new project dialogue where you can give the project a name. Let's just call it test
project or whatever you want to call it, doesn't really matter.
After that, you get a project path where you can select where you want to store it.
Just choose a good spot. Ideally, create a folder specifically for your Godot projects.
Also, keep in mind, Godot is going to create a folder by default inside of this path.
If you don't want that, just disable this toggle. After that, we have three options for
the renderer. Forward plus, mobile, and compatibility. On the right side, you can see a bit of
information about them. Forward plus is going to give you the most options and the best look.
I'm going to use this one throughout this entire tutorial. However, if you want to make, for
example, mobile games, then you have to account for less powerful hardware and more limitations. Compatibility is
mostly for browser games where you have very limited amounts of hardware power. Now, in our case, we only care about
forward plus. That's the most straightforward one. You can also use version control, but that we don't
really care about. Once you have all of that, click on create.
And here we are. This is what you see when you start up Godot for the first time.
Now, I will be talking about the different elements in just a second. First of all, though,
you can customize this thing quite a bit. For that, you want to go to editor and
then editor settings. In there, you have interface and editor, which allows you to customize a lot of
different things. For example, if all of this is too small for you, you can set the display scale.
The default is auto at 150%, but this you can increase. Which you can even push further with a
custom display scale. In my case, to make sure all of this is visible, I'm going to set it to 2.5 and
then the display scale to custom. That way, we're getting this scale. If you now go to save and restart,
Godot is asking if you want to save the current scene, which I do want to do. And then we get the same editor with all
of the elements quite a bit larger. Now, in your case, you probably don't have to do that. Just choose something
that fits your needs. Most people leave it as it is, which is totally fine. But in my case, lots of people watch these
videos on a phone. For those purposes, this thing has to be larger. Besides that, you can go to theme and
choose a custom theme. Under preset, default is this bluish color, which I wouldn't recommend
because blue is just a bit distracting. My default is gray. If you have that one selected, after a
second, Godot is going to change the look and there we go. We have something much more neutral.
Finally, if you want to hide the top bar, you can press shift and F11
and then you are in full screen, which is what I'm going to go with, but in your case, just choose whatever you
prefer. Cool. With that, we can start working inside of Godot. Let's talk about the different UI
elements. The really big thing right in the middle of the screen is the viewport.
At the moment, it's 3D. If you hold the middle mouse button, you can rotate in here.
Later on, we are going to explore this quite a bit more, but for now, it's not too important. Instead, if you look at
the top, we have 2D, 3D, script, game, and asset library. We are mostly going to work in 2D for
now and in there, we have a 2D space. Besides that, we have script in which we are later going to have all of our
scripts. Then we have game and finally, we have the asset library, which allows you to download different kind of
plugins. We are going to have a deeper look at this later on, but in the most basic
sense, it allows you to expand Godot by adding specific tools. And by the way, you can switch between these different
modes using the F keys. F1 is 2D, F2 is 3D, and F3 is script. Those are the ones you're going to use all the time. For
now, I want to work inside of 2D. Inside of this scene, you can place a whole bunch of elements.
Those you usually get from the file system that you can find in the bottom left.
By default, Godot has one folder with one image file, icon.svg. This is the Godot logo.
To add this to your game, in the most basic sense, all you have to do is drag and drop it into the viewport and then
you have one image that you can move around. And well, you can also scale it
and do quite a few things. I'll talk about this in a bit more detail later on, but for now, I want to undo it with
control Z. While you could simply add a graphic into this viewport, this is not usually how you're supposed to approach
it. Instead, you want to look at the scene panel. This allows you to create a scene tree
where we can create a 2D scene, a 3D scene, a user interface, or create another node.
If you click on other node, you can see all of the nodes in Godot. And nodes in Godot are incredibly important. I'll
talk about those in just a second. But basically, in here, we have a whole bunch of nodes that can do different
things. The easiest one is a timer, which is just a basic countdown timer.
I think this one is self-explanatory. Besides that, we have an animation player or if you look under node 2D,
we have an animated sprite 2D, which is just an animated picture. We have GPU particles, we have a camera,
we have a collision shape, and if you look under collision object 2D, we have, for example, an area 2D that lets you
check if something entered an area. For now, don't worry too much about these nodes. I'll talk about them in a
lot more detail in just a second. I guess what we can do for now is drag the image back into the viewport and then
you can see inside of the scene tree, we have one node called icon. That's because this file name is called icon.
The actual node is a Sprite 2D. If you hover it, you can see type Sprite 2D.
Once you have that, you can look on the right side. There you have the inspector. This gives you all of the
properties of this node. For example, under transform, we have the position, rotation, scale, and skew of this one
node. If you change these values, you can see they update inside of the viewport in
real time. And in there, you can do a ton of different things and
manipulate this node to your heart's content. Although not something I want to do,
let's undo all of this. That way, we are ending up right here. Every node has a ton of properties that
you could be changing. And being able to change them is pretty much what gives you a game.
And all right, with that, we have the basics of Godot. So, let's talk about how we combine all of these different
elements. To understand how Godot works, you have to understand scenes and nodes. They are
the fundamental part of literally any game made in Godot. Let's start with nodes.
Those are the fundamental building blocks of literally any project in Godot.
They could, for example, be images, timers, sounds, 3D objects, animation players, and really a lot more. Godot
has hundreds of nodes. Back inside of Godot, if you click on this plus icon, you can see all of the nodes.
There are lots of drop-down menus in here. If you click on them, you can see everything that's available.
Now, the way this is supposed to work is that you are combining different nodes inside of a scene. Scenes actually have
two purposes. Number one, they are container for nodes. In other words, you're combining different nodes inside
of a scene. Besides that, scenes also manage what is displayed inside of the game.
For example, a scene could be a level. Imagine a Mario level where you have a fire world, a forest world, a water
world, and so on. Each of these levels would be one scene and you can tell Godot which one to
display. Now, this is a concept we really have to practice. So, let's have a look at all
of this in practice right away. Back inside of the editor, I want to get rid of this Sprite 2D by simply deleting it.
Godot is going to double-check I do want to delete it. After we have that,
I want to create a root node. For now, a 2D scene. This node we can rename to, let's say,
first scene. Usually in Godot,
you are going with this naming style where you start with a capital letter and then you don't add spaces and
instead you are adding for the second word another capital letter. You could add spaces, but when it comes to coding,
those can be really confusing. So, I would recommend to not do that. This will be our first scene, which I want to
save. This you can do either by pressing control S or inside of scene, you can save the scene.
Then Godot is asking you for the location. I want to keep the default one here. So, click on save and then in the
file system, you can see first scene. Also, if you look at the viewport, we have our first scene.
And inside of this scene, we have one node at the moment, a very basic Node 2D. This is our root node.
To this, we can add other nodes. This you do by either clicking on the plus icon or pressing control and A. In
either case, you get to create new node. In there, you can select any of these nodes. There is kind of a color skin
going on. 2D nodes are blue and they are inside of Node 2D. If you click on the drop-down menu, you
can see all of the 2D nodes. Green ones are for user interfaces and there, for example, we have text and
text input. There's quite a bit more in here, but for now, that doesn't really matter.
Then we have red nodes. Those are for 3D games. These tend to be a bit more advanced,
but for now, it's not too much of an issue. Finally, we have other nodes and those
tend to be white-ish. For example, in there, you have a timer or you have an animation player
that can be used for both 2D and 3D games. I think at the beginning, this can be quite overwhelming. So, don't
worry too much about any of this. For now, you primarily want to work inside of Node 2Ds.
And one of the easiest nodes that you're always going to start with is a Sprite 2D.
And at the moment, I can't find it. Oh, there it is. Sprite 2D. Now, most of the time, you don't
actually go for this menu manually. Instead, you search at the top.
I want to have a Sprite and then Godot is already going to a Sprite 2D. This I want to use, so click
on create. Then we have our first scene and a Sprite 2D.
This Sprite 2D at the moment is not visible. If you zoom out,
then you can see that, well, we can't see anything. That is because this Sprite 2D needs to
have a texture, which you can see inside of the inspector. At the moment, the texture is empty.
Now, if you click on the drop-down menu, Godot is giving you a ton of options. For example, you could create a simple
gradient 2D and then you are getting something that you do want to customize. So, in there, you want to drag and drop
the points around and then you get a proper result. Although not something I want to do. So,
let's undo it. Instead, you are supposed to drag a texture in there that you're getting
from the file system. In my case at the moment, we only have a single file, icon.svg.
Drag this one inside of texture and then finally, you can see the actual image. And once again, inside of the
inspector, you can transform this thing to your heart's content. Like you have seen a few minutes ago.
By this system, you can add more and more nodes to your scene. For example, we could be adding another Sprite 2D
with another Godot logo and then move the second Godot logo somewhere over here.
To make those two distinct, I could go to visibility and then modulate. This one lets you add a color tint. If
you click on it, you can change the color quite a bit. Let's make the Godot logo quite red or
really whatever you want. It doesn't really matter. With that, we have two Godot logos inside of the scene.
Or in other words, we are building a scene tree. This is effectively what we are creating in here.
Now, really important thing that you do have to understand is that these nodes are related. For example, this Sprite 2D
is a child of the first scene node, which means when we are changing this first scene, the changes also apply to
both of the children. If I go to first scene and then to transform,
there we have rotation. If I rotate this node, the children rotate as well. However, if I rotate a child on its own,
like this Sprite 2D, then the other nodes are not affected. In other words, a parent affects the
child, but the child does not affect the parent. On top of that, these two nodes right now are siblings.
They both have first scene as the parent, but otherwise, they're not really related, which means if you move
one, you don't affect the other. However, what you could be doing is attach this Sprite 2D 2 by simply
dragging it onto Sprite 2D and then Sprite 2D 2 would be the child of Sprite 2D, which itself is the child
of the first scene. Because of that, when we are changing Sprite 2D, we are also changing its
children. And if we change the first scene, then we are changing all of them as well.
I hope this system makes sense. Basically, once a node is a child of another node,
it is affected by all of the changes to the parent. A super important thing to understand. Now, besides that, if you
want to create a new scene, all you have to do is click on this plus icon. Godot already tells you add a new scene and
then you can create another scene. Inside of this scene, I want you to do an exercise.
Create a Godot stick figure by using Sprite 2Ds. The end result should look something
like this. This should happen via nodes and scenes. Pause the video now and see how far you
get. Inside of Godot, I want to create a 2D scene
that I want to rename right away to stick figure.
To this node then, I want to add a Sprite 2D. You can do this either via what you had
selected before or inside of recent nodes. Click on create and then once again, we can't see
anything. For that, you want to drag icon.svg into texture.
Then we can see Godot and let's say this part could, for example, be the torso. To make that look a bit more realistic,
we want to scale it up by using these points or by going to transform and then increasing the scale on the Y axis.
By default, those two scale together. If you want to scale one individually, click on this chain icon and then you
can change these individually. Alternatively, you can also drag these points and then change all of this
dynamically. This gives us the torso. Attached to that, I want to have another Sprite 2D
which should be the head. For this head, once again, we want to add icon.svg to texture. Once we have
that, we can't really see a difference, but if you move the head to the side, you can see that, well, the head,
because it's a child of the torso, is going to get the same scaling behavior. In other words, if I change
the scaling of the torso, we are also affecting the head. Which is usually not ideal, but for now,
what we can do is simply scale this thing quite a bit down to something like so and so
and then move it on top of the node. That way, we're getting some kind of a head.
Besides that, once again, I want to add another Sprite 2D, which you can also do by simply dragging icon.svg into the
viewport. That way, Godot is automatically creating another Sprite 2D with the name of the file you just
added, which is not what I want. This should be, let's call it the right arm. Which at the moment is not a child of
torso, so it doesn't get the scaling behavior applied to it. That's totally fine. This thing, I just
want to scale down a bit to something like so and then, inside of transform, I want to
rotate it to something like this. Next up, I want to press control and D. That way, we are duplicating the node, and
this gives us the other part of the arm. Which we want to rotate as well. Let's say something like this.
And I guess right arm two should be a child of the right arm. That way, if we're changing the upper arm, we're
changing this node as well. Next up, I want to add another node. This is going to be
the left arm. Which at the moment is a child of the right arm, which I don't want.
I simply want to drag it onto stick figure, and then left arm is not a child anymore.
Because of that, if you go to transform, we can undo all of these changes, and then we get the default Godot logo.
And this I want to once again scale down a bit and rotate so it looks a bit more like an arm.
Then we can duplicate this thing again, move it here, and transform it just a bit more.
Let's say something like this, and then left arm two should be a child of left arm.
Two more things I want to add, and for that, I simply want to add the other Godot logo, and once again, this should
be a child of stick figure. Then I can undo all of these changes. And for this part, I simply want to add
a leg. So, let's make this a bit thinner and a lot longer and move it down here.
This should be the right leg, which we can duplicate and then move it to the side.
This would be the left leg. And with that, we have a very basic Godot stick figure.
All of this, I want to save as stickfigure.tscn. Click on save, and now, inside of the
file system, we have stickfigure.tscn. Looks pretty horrendous, to be honest, but I think you get the idea. Now, once
we have that, what is super important to understand is that this scene can be added to another scene.
For example, to our first scene, we can click on this icon, where we can instantiate a child scene.
If you click on it, you can see all of the scenes inside of the project. At the moment, we only have two. First
scene, that's our current scene, and then the stick figure, which is what I want to add.
If we are doing that, we are getting the stick figure. At the moment, it's rotated because
first scene itself is rotated by a certain amount, which I don't want to have.
If I undo that, then we have the stick figure inside of our first scene. And I hope
you understand how this system comes together, because it's really important to understand. For example, later on,
the stick figure would be replaced by a proper player, which has all of the parts that the player actually needs.
And then the first scene would be a level. That itself is a scene with all of the
parts of the level, and one part of this level is the player itself. So, effectively, the scene is going to be
what you display inside of the game, and the scene is something that organizes different nodes. It does two things. If
you then combine different scenes together, you can create pretty complex projects that are still maintainable,
because you only ever touch small parts of it. We are going to practice this sort of system a lot more throughout
this course. I just hope for now you understand the absolute basics of it. Two more things that I absolutely want
to cover. Number one, let me move this thing a bit down here, this thing here, and this Sprite down here.
All of this should be inside of this blue frame. This is what you actually see when you
are running the game, which by the way, you are doing via these buttons up here. The most important button is run
project, or F5. If you click on it, Godot is asking you what the main scene is going to be. You can select one
manually, or you can select the current one, which in our case is first scene, which is what I want to do.
If you click on it, then the game is going to run, and we can see the stuff that we have just created.
On top of that, on the top of this window, we get a lot more things that aren't too important, so don't worry
about them. Although, the one thing you do want to worry about is the resolution, which at the moment is 1152
by 648. Now, if you resize this window, this can change. You can also go to project, project
settings, and then, under display and window, set a custom window resolution. Although,
that's not too important at the moment. Besides that, what can be really confusing is the positioning inside of
this window. If you click on first scene, we have a position of zero and zero. This is in the top left. You can
see it via this red cross dot thing. If you click on the first Sprite 2D, this one here, it currently has a position of
151 and 168 for X and Y, or the horizontal and vertical axis. What do these numbers actually mean? To
understand them, you have to understand how the window works. The origin point is in the top left. This is position
zero for X and zero for Y. If you go further to the right, then X is going to become larger and larger
until you reach the right side. This at the moment would be position 1152. In other words, this for example could
be 100, this could be 200, and so on until we reach the right side of the window.
I think this part makes sense. The further right you get, the greater X becomes. On the Y axis, this gets a bit
more confusing, I think. To go down, you want to increase the number. For example, this would be 100 pixels. If
you go down a bit further, you'll be at 200 pixels, and if you keep on going down, at some point, you reach the end
of the window, which I think was 648. This can be sometimes counterintuitive. You want to increase the number to go
down. Most game engines work like that, where the origin point is in the top left, and
if you want to go up, then you have to go with negative numbers. So, this part here, for
example, would be negative 100. Especially in the beginning, this can be confusing, but once you work with it for
a bit, it does become fairly intuitive. And just to play around with it for a bit,
if you have this node selected, I can set the value to zero and zero. That way, we are right in the center.
If I then increase this value for X to, let's say, 50, we are going further to the right, and
if I set the Y value to 100, we're going quite a bit down. If I set Y to negative 100, then we are
going up. And via that system, you can place different nodes inside of this window. And well, with that, we have the
foundation of Godot. At this point, you just have to learn about more nodes that do more things, and you have to learn
about GDScript to make all of this interactive. To add a script to a scene, you want to have a node selected, and
then click on this icon. Via that, you can attach a script. Let's stick with our first scene, and
then we can select the language. The default here is GDScript, that's totally fine.
Then we have inherit. This has to match the type of node that we are working with, and usually, you
want to stick with the default. The next important field is the path where we want to save the script that we are
creating. Most of the time, you can stick with the defaults and simply click on create. Once you have that, inside of
the file system, we have firstscene.gd. And we can write some code in here. That way, we can create the logic for our
game. From this point on, you can continue in two ways. If you don't know any coding,
simply keep on watching from here. I will talk about of coding. If, however, you already know some coding, even just
a little bit, I would recommend that you skip ahead and start with the first game. If you
have done any kind of coding before, you should be good to go already. And of course, you can always go back and look
at the coding part. I guess if you are not sure, here are a couple of code snippets that we are going to use inside
of the first game. If this doesn't look overwhelming, you safely skip ahead. Let's get started with coding. And for
this part, I will assume that you have never touched a programming language before.
Don't worry, it's actually not that hard. In the most basic sense, all that we are
doing is create some kind of logic. For example, if you want to move an object to the
right, if its position is less than 800 pixels, it would look something like this.
We start by creating an if statement by writing if. Then we are checking a value that can change. So, this position X
could be part of an object that is moving to the right. This we are comparing against a static value, in
this case 800. This condition can either be true or false. If it is true, then we are doing the stuff that is
indented on the next line. And if that is the case, we're getting the current position X,
and we are assigning it a new value, which is going to be the current value plus five. So, we are moving it further
in a certain direction. And that's really all we are doing most of the time. The majority of the logic
isn't going to get that much more complicated. In practice, this kind of logic can be created in multiple
different ways. Godot is actually supporting multiple coding languages. The default one is called GDScript,
which is really really easy to learn. It is actually very similar to Python, which is one of the most common
programming languages. If you know GDScript, you basically know Python. And Python can be used for a ton of other
things, like data science, databases, AI, and so on. Besides that, Godot does support other languages, but I'm going
to focus on the basics. So, we're going to work with GDScript. Once we have that, to actually write code in Godot,
you want to attach a script to a node. And via that, you can change the property of that node, like the
position, size, rotation, and anything that you can find inside of the inspector. Or in other words, back
inside of the scene that we have seen earlier, if you click on this Sprite2D,
you can change any of these properties, like position, rotation, scale, and skew.
You could also change the visibility, modulate, and really anything that you see in here can be changed via GDScript.
All you have to do is hover over the property, and then Godot is telling you how you can change it. And there can be
a ton of information in here. You can also change other nodes, create new nodes, target other scenes, and even
get data from the internet. There's basically no limit to what you can do. Godot is incredibly flexible and lets
you do a ton of things. We are nearly ready to start. There's just one more thing that we have to
cover, and that is that Godot organizes the code via functions. Functions, in the most basic sense, are
just blocks of code. Via those, you are grouping different lines of code together to do a certain thing.
For now, we are going to work inside of two functions that are inbuilt into Godot. The ready function, which is
executed when a scene is ready. You'll see in a second what that means. Besides that, we have the process
function, which is run on every single frame of the game. And before I start throwing too much theory at you, let's
have a look at all of this in practice. Back inside of Godot. This is getting a bit too complex, so I
want to create a new scene, which is supposed to be a plain 2D scene. Let's rename this one to coding one.
This I want to save right away. You could create another folder in here if you click on this icon, but in my
case, I'm going to leave it as it is. Click on save. And now,
we have a scene with one node, coding one, which is totally fine for now. To this scene, I want to add a script,
like we have done before. So, attach a new script, and leave all of the defaults here in place.
Then create. And now, to actually do something, we have to work inside of a function,
because remember, all of the logic in Godot has to be inside of a function. To create a
function, you want to write the keyword funk, and then the name of the function.
You can basically choose any name in here, but there are some special names. They usually start with an underscore.
If you simply type an underscore, then Godot is suggesting you all of the inbuilt Godot functions.
The one that I want to work with is ready. If you click on that, you get ready,
then two parentheses, an arrow, and then void. This last part we actually don't need, so you can get rid of it to keep
things easier. This would be the most basic way to create a function.
You have the keyword funk, this always has to be there, then the name of the function, and then
two parentheses. We will see later why these are important. If we only type this, Godot is going to
complain, which you can see at the bottom, that Godot is expecting an indented block
after the function declaration, which means we have declared a function here, and after that, if you press enter,
Godot is creating an indented line, which basically means that we are pressing tab, and whatever we are
writing next is going to be indented. Having this line being indented means it is part of this function.
That way, if we later on create another function, let's call it something,
then anything that is indented afterwards is part of this function. Or in other words, via indentation, you
can group things together. So, what can we actually do inside of this ready function?
And well, the most basic thing that you want to do is to print data for now. For that, you simply want to write
print, and then use parentheses again. After that, whatever you write inside of this
print statement is going to be printed out once we are running the game. For now, let's simply write a number, 1
2 3. Could be any number for now, doesn't really matter.
Once we have that, we want to run this one scene, coding one. If you simply click on this icon,
run project or F5, then nothing is going to happen because earlier, we have set this first scene as
the main scene, which means no matter where you are, if you are clicking on this icon, you always run the first
scene. If you don't want that, inside of coding one, you can click on
this icon here, where you are running the current scene, or simply press F6.
If you are doing that, then the game is going to run, and if you look at the bottom,
there we have the output tab, and this at the moment says 1 2 3. That we are getting because inside of script, we are
printing 1 2 and 3 once the scene is ready. Alternatively, what you can also do,
inside of project, project settings, you can go to run, and then set the main scene.
I guess for now, we can set the main scene to coding one. Then I can close this dialogue, and
simply run the project. And now, we are running coding one via F5 or this button.
At the moment, we are using two inbuilt functions of Godot. Print is a function, and ready is a function. But this might
be a little bit confusing, because for the first ready function, we had to use funk, whereas for the second function,
we don't do that. So, what's happening here? To understand that, let's talk a bit more about functions. There are two
things that we are doing at the moment. Number one is we are creating a function. For that, we are using the
funk keyword, then the function name, and then we have parentheses that can accept parameters, which we don't have
at the moment. That's going to come later. But via those, we could add information to the function. After that,
we have indented code with the actual logic. Now, the important thing is that this is only creating a function. It
doesn't actually use that function, at least by default. To actually use this function, you have to call it, which is
another way of saying that you want to execute the code that you have created. For that, you want to use the function
name, and then add in arguments, depending on how many parameters you have. Now, in our case, we are creating
the ready function. And this function is special because Godot is calling it internally. Whenever we are executing
the project, this function is being called by Godot once the scene is ready.
So, we only have to create it, Godot is calling it for us. But for the print function, it's the
other way around. It's an inbuilt function into Godot, so we don't have to create it, we just have
to call it. And when we are calling it, we have to add an argument into it. At the moment, this is 1 2 and 3.
And the result of this is that Godot, inside of output, is printing 1 2 and 3.
If you want to display some text in here, you couldn't simply write something.
That wouldn't work. Instead, I will talk about later why this doesn't
work. But what you have to do is put this inside of quotation marks. Single or double ones would both work, you just
have to be consistent. I will use double ones because that's what Godot uses internally, but it's
really up to you. If I now run the project again, we get something inside of the output.
And that way, you can print anything inside of the output. To practice all of this, I want you to create a new
function and call it as well. So now we're doing both things. The new function should print something
and 1 2 3. In other words, you want to call the print statement twice inside of that new
function. And the new function itself, you want to call inside of the ready function.
Pause the video now and try to figure out this one out and see how far you get.
First of all, we want to create a new function. For that, once again, we will need the funk keyword and then the name
of our function. I guess I should have mentioned this earlier, but this has to be inside of
one string of characters. This could, for example, be something. After that, you need the parentheses,
opening and closing ones, and then colons. Then, inside of the function, we need one level of indentation, like so.
Godot should be doing this automatically, and then we want to call the print function.
And write something. And on the next line, we also want to print 1 2 and 3. By that, we have a new
function that does two things. We are printing something, and we are printing 1 2 and 3. But this function, by
default, doesn't do anything. If I run the code, the output is only something, which we
are getting from this print statement. To actually use this function, you have to call it, which you do by writing the
function name, in my case, something, and then add the parentheses afterwards, opening and closing ones.
If you're doing that, then we're getting something twice and then 1 2 3.
The first something comes from this print statement, the second one from this one, and then we get 1 2 and 3. I
guess the first print statement should say something else, let's say test, then this becomes a bit easier to see. We
have test, something, and 1 2 3. And by that, I think you can already see a couple of basic things. The most
important one is that Godot is executing code line by line. We are starting inside of the ready function, which is
called once the scene is ready. In there, first of all, we are calling print and test.
After that, we are calling the something function, which is down here. Inside of this function, we are printing
two more things. Something and 1 2 and 3. Because of that, we can see test first,
then we have something, and then we have 1 2 and 3. So with that already, we can create a new function, and we can call
functions as well. Either in-built ones or ones that we have created ourselves. In a little bit, we are going to talk a
lot more about functions. They tend to be slightly more advanced, and usually you cover other things
first. But since Godot executes all of the code inside of functions, I had to cover it right away. So I hope this part
isn't too confusing. The only thing that you have to really understand is that you are creating
functions via funk, the name of the function, and then parentheses. Also, don't forget about the colon.
You want to indent some lines, so you know that this line belongs to this function.
After which, you can write any kind of logic. In the next part, we're going to talk about that a lot more. To call a
function, you want to write the name of the function and then parentheses. Inside of the parentheses, you can add
arguments, which we don't have for the something function, the one that we created, but
for the print statement, we can add one argument, and this one prints a certain thing.
So with that, we have functions. Next up then, we can work on actual logic. Now that we can create basic functions, we
can work on logic and variables. And let's start with logic right away inside of Godot. Here we are again, and
I want to keep on working inside of coding one, specifically the script. At the moment, we are only printing
test, which doesn't really do very much. So instead, let's do something a bit more interesting.
And I guess while we are here, we can get rid of all of this stuff as well, because it's going to be a bit
confusing. I only want to have the ready function where we are printing something.
And that something is not going to be a word, it's going to be a math equation. And for that, you can simply type
something like 2 + 2, run the project, then you get the result, four. Other operations would be
2 - 2, then we get zero. You can also do two multiplied with two,
or let's say two multiplied with three, that way we are going to get six. And finally, you can do two divided by
three. Although then we would be getting zero, because Godot is rounding this value, that we can change later. For
now, not too important. Let's do 9 divided by 3, that way we're getting three as the result.
These are the very basic things that you can do via math inside of Godot. And Godot supports a huge range of math
operations. The best way to learn about them is to use the documentation.
Godot actually has multiple kinds of documentation. There's one inside of the Godot engine right away.
If you click on help, there's search help, and then you basically get an overview of all of the parts of the
engine. This isn't really a tutorial, it's more of a manual. If you go to Google, you
can look for GDScript reference. That way, the first result should be the
Godot documentation. If you click on that, you get a page that tells you all about
GDScript. It is quite a long page, but in there, you have a ton of information. I would recommend to have this page open
all the time, it's super super useful. Right at the beginning, we have an example of GDScript, and there are some
things that we have already seen, like for example, a function with a couple of parameters, that we're going to cover
later. Besides that, there are loads of things that you haven't seen yet, so don't worry too much about it.
Instead, go down a bit further to the operator part. In there, you can see all of the math operations, like x +
y, x - y, and then you get all of the other operations as well. The only things that you need for now are these
operations, everything else is going to be a bit confusing. But it is still super useful to at least
have a look at this page and see what you can be doing. By the end of this course, all of this
is going to make sense. Now, using this information is really important, so I want you to do an exercise right away.
I want you to calculate Pythagoras' theorem, where side A is 10 and side B is 20.
Calculate the output using GDScript. Just in case you don't know what Pythagoras' theorem is, you can go to
Google and then look for Pythagoras' theorem calculator,
then Google is giving you the formula that you have to write inside of GDScript.
You are taking the square root of the square of A plus the square of B. By that formula, you can calculate a
side C inside of a triangle simply from knowing side A and side B. So in our case, we know side A is 10 and
side B is 20. The result should be around 22. This is what you should be getting.
So effectively, what I want you to do is to put this formula into GDScript. For all of that, you want to look at
these couple of lines inside of the documentation and figure out how to combine them. Pause the video now and
see how far you get. Back inside of Godot, I want to print the result, like we have
seen before. Although before that, I want to add a hashtag and then add exercise.
If you add a hashtag, then Godot knows this is going to be a comment, meaning the code is going to entirely ignore
whatever you write in here. Which makes it much easier to document your code.
Not something you have to do, but I think in this case, it does make things a bit easier to read. Once we have that,
we have to write the actual formula. You can see it in the bottom right at the moment. First of all, we want to get A
squared, which in our case is 10 and then squared. Which you do by adding two asterisks and
then two. That way, you are squaring the number 10.
Then we want to add something, which is the value for B, which in our case is 20. Which we also want to square.
So two asterisks and then a two. If we run the project now, we are getting 500.
That is because the square of 10 is 100, and the square of 20 is 400. If you add both of them together, you're
getting 500. But now, we have to take the square root of all of this.
Now, getting the square root might have been one part that is a bit more complicated, because there's no square
root in any of this. However, what you can do is use the power once again.
If you take half the power of any value, you are taking the square root. Or in other words, let me demonstrate it
really quickly. We can print nine asterisk asterisk, so the power of 0.5.
That way, we are taking the square root of nine. The result is going to be three, or at least I hope it is, and it
is, 3.0. However, now there's another thing that we do have to worry about. If I simply add
asterisk asterisk and 0.5, we are not going to get 22. If I run the entire thing,
we are getting 120. And to only focus on the value, let me get
rid of this one. This value should return 22. Whatever we have seen down here with 22.
The reason why we don't see it is because this square root only applies to this value. But we want to apply it to
the entire thing. To do that, you want to wrap them inside of parentheses, like so.
And let me add a bit more spacing to this, that way it's going to be a bit more visible.
We first of all want to do this operation, and then take the square root of the entire thing.
Via these parentheses, we can control the order of operation. If I now run the entire thing, we should
be getting 22.something, and we do. This looks really good. So, I hope this part wasn't too overwhelming.
But effectively, we have used different kind of equations and put them together to create a bit more advanced logic. And
this logic you can control via parentheses, and that way, with a bit of practice, this should become fairly
straightforward. But now, what if we want to make all of this more dynamic, where the numbers aren't always going to
be 10 or 20? For that, we have to learn about variables. Variables are basically buckets that
store data. You can either read them, or you can change the value.
This is super useful to keep things organized. And once again, if you look at the
GDScript reference, at the top, we have a whole bunch of variables. Let's create some of those.
Those you can create outside of a function, and they are just about the only thing that you can create outside
of a function. To create a variable, you always start with var. That way Godot knows you want
to create a variable. Then you need a variable name. This could, for example, just be A.
After that, you want to assign a value to this variable, which you do via equal, and then the value you want to
assign. Like, for example, a 10. Next up, we can create another variable, B,
and this one can be 20. And now you have two variables, which you can use inside of this
equation. All you have to do is replace the 10 with A, and the 20 with B. If you run the code now, we are still
getting 22.something. But if I change these variables to, let's say, 20 and 30,
then we are getting something else, whatever the output is. Via that system, you can be much more
descriptive in terms of what your code can do. So, I think just looking at this, it
makes quite a bit more sense instead of just having random numbers in here. Although, when you're naming variables,
you do want to be careful. There are a couple of things that you have to do. Number one,
variable names cannot start with a number, have a space in them, or use special symbols,
like the dollar and the ampersand symbol. Those are reserved by Godot.
Other than that, you are basically good to go. And by the way, these rules also apply to functions.
They basically have the same kind of naming scheme. Besides that, variable names are usually
written in the snake case convention, meaning you only use lowercase letters, and if there's a space, use an
underscore. That's what most people use, but it's just a convention. You don't have to follow it.
That being said, it is recommended that you do. For example, instead of simply using A,
you might want to go with side_a. And for B, you want to have side_b.
Once you're doing that, Godot is complaining because now variable A and variable B don't exist
anymore. Instead, they have been renamed to side_a and side_b.
Once you're doing that, Godot is happy again, and we are good to go. That way, the variable naming is also a lot more
descriptive. Most of the time, you do want to be quite careful how you name variables.
If you mess this up, and your code becomes more complex, this can be incredibly confusing.
Other than that, though, this is basically how you create variables. You create them in the first few lines of
the code, and then inside of any function, you can use them as a stand-in for any other number.
So, at the moment, we are simply reading a variable. Besides that, what you can also do is override the value. So, for
example, side_a can be, instead of 20, a 100. After the line, I can print side_a again,
run the code, and now as an output, we are getting a 100. And I think now it's important to understand how Godot is
executing the code. It goes through it line by line. It first does this line,
then it does this line, and then it does this line. Because of that, for this formula, the value of side_a is 20. But
on the next line, we are changing that value to 100. And just to demonstrate, let me run the project. The current
output of the formula is 36.something. This is what we're getting from this statement. But if we move side_a being
100 one line before that, and run the thing again, then we are getting a different number,
104. That is because now side_a is 100. So, inside of this formula, side_a is 100.
But if we update value A afterwards, then this side_a is what we're getting up here,
20 in my case. So, it's really important to understand how this code is executed. Godot goes
through it line by line, and then simply goes through all of these operations. Really important to understand,
sometimes this can give you some weird results. Besides that, along with variables, we
have to learn about data types. Now, inside of Godot, there are a ton of different kinds of data types. So, for
now, I am only going to focus on the most common ones. First of all, we have text.
These, inside of Godot, and really any kind of programming language, are called strings. You are creating them via
double or single quotation marks, and then whatever kind of text you want to have inside of them. Besides that, we
have numbers. And those are actually two data types. We have integers and floating point values, or simply floats.
The difference between them is that integers are full numbers, meaning 1, 2, 3, 20, and so on. Could also be
negative, like -100. Floating point values have decimal points, like 1.0 would be a floating
point value. Could also be 1.5 or -2.4. Then we have true and false values.
Those are called booleans. They can only be true or false. Once we get to if statements, those are becoming
incredibly useful. Finally, we have different kinds of lists. Those can store multiple values inside
of a single variable. Now, those I am not really going to touch yet. There's going to be a
separate part on them. But there you have arrays, dictionaries, and vectors. I do want to mention them now because
they are incredibly important, really, really common. Variables and data types.
You can force a variable to only accept a certain data type. For example, you can tell a variable to
only hold integers or floating point values. That way, it would be impossible to assign text to it,
which is generally a good idea. It's a good safeguard to make sure a variable doesn't get the wrong kind of data.
Although, if you don't do that, variables by default can hold any kind of data. But let's play around with all
of that. Back inside of Godot, let's say I want to create a new variable.
And this can just be called test. Test should only hold strings. Like, for example, some
test string. This value I want to print. And this we can do all the way at the
end, inside of the ready function. I want to print test. If I now run the project,
we're getting some test string. That works pretty well. We are printing this piece of text, or
this string. However, before this final line, we can assign a different value to test. Like, for example, 1 2 and 3.
If I now run the code, as an output, we're getting 1 2 and 3, which would be an integer, because now
we have a full number. If we want to avoid this kind of behavior,
what you can do, after naming this variable test, you can add a colon,
and then tell it to always be a certain kind of data type. For example, a string.
If we have that set up, then Godot, on this line, is going to throw an error that we cannot assign a
value of type integer as a string. We are telling Godot that this variable always has to be a string, meaning we
cannot assign an integer to it. If we change this to some other string,
Godot would be perfectly happy because we still have a string. Besides string, we also have integer.
And if I do that, Godot is going to complain on these two lines that we are trying to assign a string to
a variable that can only hold integers. Which means now, this has to be numbers. So, 1 2 3 or really any
other that you can be very explicit in terms of what kind of value you are working with, which usually is a good
idea. Especially once projects become more complex, you want to be very very
explicit in terms of what values you have. Without that, you can very easily get
some random errors that you don't understand. And always having the right data type is a good way to avoid that.
Now, this can be sped up quite a bit. If you simply add colon and equal to a certain kind of
value, then you're forcing this variable to only hold the data type that is first
assigned to it. In this case, an integer, meaning now if I try to add a different kind of
value to test, like for example, a string, then Godot is going to complain because
this variable can only hold a type integer because that's what we first assigned to
it. Or in other words, this has to be a string. So, with that, we have
different kinds of data types. We have integers and we have strings. Besides that, you
can also add floating-point values, like 30.0 or let's say 30.2. Now, both of those are numbers and if
you use them inside of an equation, they would still work. So, if I run the code, Godot is still going to execute all of
this and we are good to go. But sometimes, this difference between an integer and a floating-point value
does become apparent. We have actually seen this earlier. If we have 2 / 3, so the first operation
we did, in the beginning, we have gotten a zero because we are dividing an integer by
another integer. And the result is also going to be an integer, which has to be a full number.
Godot is actually giving us a warning about that. If you look at the debugger down here, we are getting errors.
Although in there, we have errors and warnings. Yellow ones are warnings. We have an integer division, where the
decimal part will be discarded. That happens on this line. To avoid that, to get an actual value, you want to have
2.0 divided by 3.0. That way, if I run the thing again, we are getting an actual value, 0.666
and so on. So, sometimes using different data types is incredibly important
even for basic math equations. And without knowing the different data types, this kind of behavior would be
very confusing. So, always make sure when you want to have very precise results, you want to
use floating-point values, anything with a decimal. The next important part are properties and methods.
And those you kind of actually already understand. But let's go through it step by step. So
far, we have covered variables and functions. Variables store values and functions are
blocks of code that you can execute. I hope at this point this is reasonably straightforward.
But besides that, we have properties and methods. These are also basically variables and functions, but they belong
to an object, like a Sprite2D for example. Or in other words, inside of a Sprite2D,
we have a position, which is just storing the position of that Sprite2D. Besides that, the Sprite2D has functions
that are part of it, like for example, look at. And that way, you are rotating the Sprite2D to look at a certain point.
In practice, position and look at are just a variable and a function. But to emphasize that they are part of an
object, we are calling them a property and a method. There isn't really that much of a difference. The only thing
that you really have to be careful about is that you're adding a dot after the object and then you can use
the property or the method. Once you understand that system, you can actually dynamically change nodes inside of
GDScript, which gets you a lot closer to an actual game. So, let's have a look. Back inside of Godot, I want to create a
new scene where once again, we have a 2D scene as a root node, which I want to rename to coding two.
Maybe not the best name, but it's good enough for now. This I want to save right away as coding two.
After that, I want to assign a script to it called coding two. That way, once again, we have another
script and we still have coding one and the first scene. Now, in here, I want to work with a Sprite2D, which at the
moment is difficult because inside of this scene, we don't have a Sprite2D. That, however, we can change by simply
clicking on plus and then adding a Sprite2D. Which once again, needs to have the
texture, so let's drag it in there and then we have the Godot logo. As a reminder,
inside of the inspector, we can see all of the properties of this object. For example, there we have position, we
have rotation, we have scale and so on. And to be a bit more explicit, this Sprite2D is an object. Or to be fully
precise, it's an instance of an object, which is a fancy way of saying it's one object that we can use inside of our
game. That means, inside of GDScript, we can access all of the properties and methods of the Sprite2D.
This once again has to happen inside of a function. So, let's work with function ready.
Once again, we don't need this void part. To avoid confusion, let me remove it. I'll talk about later what it
actually means. To actually work with this Sprite2D, you can simply drag it into the code, like
so. And then you can see what Godot actually does. It adds a dollar sign and then the
name of the node that you want to work with. That way, you are getting the object. And on this object, you can add
a dot and then get all of the properties. For example, somewhere we should be having a
position. This should give us the same position that we can see inside of the inspector,
which at the moment is 251 and 169. This value we want to print. So, we want to put it inside of the
print statement and then run the current scene. Really important,
coding one is the main scene at the moment. But we want to run coding two. So, you
don't want to click on this button, you want to click on this run current scene button.
If you're doing that, you can see the Godot logo, that looks good, and you can see the position.
Inside of output, we're getting 251 and 169. Exactly what we can see inside of the
inspector. Besides that, we can also get the rotation
of the Sprite2D. Let me run the current scene again. We should be getting 0.0 and we do. That
looks really good. So, fundamentally, this rotation is a variable. It stores a certain kind of value, whatever we are
getting inside of rotation. But it is called a property because it is part of a Sprite2D.
That being said, it behaves just like a variable, which means we can assign a value to it. For
example, the rotation could be 20. If I now run the current scene again, then we're getting an output of 20 and
on top of that, the Godot logo is rotated by 20°. By that system, you can update all of
the nodes inside of Godot in real time, which is how you get an actually dynamic game. This would be properties.
Besides that, we have methods, which are basically functions that are part of an object. So, once
again, I want to have the Sprite2D. For that, you can either write the dollar sign and then Sprite2D
or you can simply drag and drop the node in there, like so. Whatever you prefer. If you now add a dot, Godot is giving
you all of the properties and methods of this object. And if you scroll around, you can see there are, well, a lot.
The most important ones are usually at the top. If the left thing says dot P, you're
getting a property. If it says F, you're getting a method. There are a few more. I'll talk about
those later. They aren't too important for now. Most of those are properties and functions.
One method that is very easy to use is rotate. This is a method that kind of does the
same thing that we have done up here. It rotates the node by a certain amount. Let's say 90° and I want to comment out
this line by adding a hashtag in front of it. If I now run the current scene,
then you can see the Godot logo is rotated by a certain amount, 90°. And on top of that,
we are printing 90° because we are using this print statement. Once you have all of that, you can
actually start moving this Node2D inside of the scene. For that though, first of all, I want to get rid of all of the
stuff that we have done so far and instead introduce another function that Godot calls automatically. It is called
underscore process. This one is slightly more advanced. Now we have one parameter that we can
actually entirely ignore. So don't worry about this part. On top of that, we can get rid of this void
but don't forget the colon. This process is called constantly. Every time Godot generates a frame, it is
calling process. In other words, if I now print something, this something is going to be
printed multiple times per second. So if I run this current scene, we get something a lot. So there you can
see the outputs we have, they are increasing very very fast which is totally fine. In fact, this is
what we want because now I can grab the Sprite 2D and then rotate it by a certain amount.
Let's say something very slow, 0.5. If I now run the current scene, then the Godot logo is going to rotate.
It is going to rotate quite fast but that we can control. Let's say 0.1 in here.
That way this feels a bit better. Besides that, we can also move this Sprite 2D in any
direction. Although for that, we have to target the position which if you have a hover it inside of
the inspector has a data type of a vector two, this value here.
I cover this kind of value in the next part but basically via a vector two, we get a list that has two values for X and
Y. Those we can target via dot X and dot Y. Let's say for now I only want to have
dot X and this value should get the current position
of the node. Let me add a bit more space so we can see this properly.
I want to assign a new X position to the node that is the current value plus some kind of addition. Let's say plus one.
And then if I run the script again, the Godot logo is going to be very slowly moving to the right.
If I increase this value to let's say 10 and try this again, it's going to be more visible. Now Godot is moving to the
right. So with very few lines of code, we can move stuff around inside of the game. By
the way, this kind of operation is really common and there's a shorthand to make it easier to write.
Instead of writing all of this, you can simply write plus equal 10. That way we're getting
the current value and adding something to it. In other words, these two statements
are doing the same thing except that the second one is much easier to read. As a consequence, let me comment out the
first one. If I now run the game again, we are getting the same result. Most of the time you are going to use
this kind of line. It's just much easier to write. All of this we should be practicing. So
I want you guys to create another moving Sprite 2D. This one should move from the top left to the bottom right and while
it is doing that, it should also scale up. Pause the video now and try to implement this kind of logic.
I want to add another Sprite 2D to the scene and make sure this Sprite 2D 2 is not a child of the first Sprite 2D.
In fact, let me rename it to exercise Sprite. That way it's a bit easier to read.
This exercise Sprite once again will need a texture inside of the inspector otherwise we can't see it. Drag the
Godot icon into it and there we go. In the top left, we have the Godot icon. After that,
inside of the script in the process function, I want to add another for the exercise.
Now in here, I want to get the exercise Sprite and do a couple of things. First of all,
I want to get the position dot X plus equal let's say five. That way this Sprite is going to move to
the right. And to make them a bit easier to distinguish,
this exercise Sprite under visibility and modulate is going to get a different color. Let's make it really blue,
something like so. Doesn't really matter but it makes it a bit easier to understand. Now we have
both of the Godot logos moving to the right. Good start.
Besides that, I want to duplicate this line which I can do by pressing control or
command shift and D. Besides X of the position, I also want to update position dot Y
and increase this value. Remember, if you want to go down, you have to increase the Y value.
If I now run the project again, the Godot logo is moving to the bottom right.
We could reduce the speed here just a bit to let's say three. That way we are going a bit more towards
the actual bottom right of the window. Also in just a bit, we're going to find a better way to update the position so
you don't always have to target X and Y separately. But for now,
I want to press control shift and D again because besides the position, I also want to get the scale. Now for this
one, you do want to be careful. If you add plus three in here and run the thing, then you get some weird behavior.
We are scaling this thing up very very fast. A better way would be to multiply the
current value with something like 1.1. Like we have seen with plus equal, multiply equal takes the current value
and multiplies it with whatever you write in here. That way this scaling becomes well,
still quite fast but a lot slower than before. Let's set this to 1.001. That way it doesn't grow that fast.
I guess you can still kind of see it. Once again, control or command shift and D
and then scale dot X. And now we are scaling the Godot logo in all directions.
A bit hard to see. Let's do this with 1.005. That way it should be more visible.
And there we go. This is definitely scaling up. With that, we have learned about
properties and methods which are basically variables and functions but they are part of an object
like for example a Sprite 2D. Once we have that, we can actually do dynamic things inside of the game which
is a massive upgrade. And to get really good at Godot, you want to be able to use as many properties and functions of
an object as you can. The best way to learn about them is to go to help and then to search
help. That gives you once again the Godot documentation. In there for example, you can look for Sprite 2D,
double click on it and then inside of the script view, you are getting the documentation for a
Sprite 2D. There you can see all of the properties and all of the methods or at least some
of them. If you go a bit further down, you are getting a lot of descriptions in terms
of what you can do. Being able to read through here and understand what's going on is incredibly helpful to really get
good at Godot. With that, really quickly before we finish, back inside of coding two. At
the moment, we have a script attached to the parent node coding two of type node 2D
and from there we are influencing a Sprite 2D or the exercise Sprite here and here.
But what if you want to influence the node itself with the script? In our case, this node 2D.
Let's say for example, once the scene is ready, func underscore ready,
then we want to move this node or in other words, the entire scene to the right.
Well, for that all you have to do is grab the property of this current node and you can do that right away. For
example, if you want to update the position, you just have to type position without any of the dollar sign stuff
before it. Once again, you just want to look at the inspector and then find the property
that you want to change like position at the moment. This once again is a vector two so in
there we have position dot X and this we could set for example to a value of
200. If I now run the script, everything is going to be 200 pixels
further to the right. A bit hard to see. I guess if I change this to 600, it's going to be much more visible.
Here you can see now everything starts much further to the right. And that's basically the system. If you
have the node itself with the script, you simply target the property or you can call the method and if you have a
child, you target that child with the dollar sign and then the name of the node. After that, you can call any kind
of method or use any property that you want. The next important topic is going to be
booleans and logic flow. Via that, we are going to learn about if and while statements. These allow you to
control what code gets run and how often it gets run. Using an if statement, you can run a
code once if a certain condition is true. With the while statement, you can run
code forever as long as a condition is true. Both of these are really easy to
implement, but we have to figure out what is true inside of code. And for that, we have to look at the
data types again. Up to this point, we basically only worked with text and numbers.
Those at this point, I hope, are at least reasonably straightforward. Next up,
we are going to look at booleans, which can only be true or false. That's the only two options that you have.
So, let's talk about how to create these kind of values. And most of the time, you are creating them via logical
operators. We have smaller than, greater than, is equal to,
is smaller than or is equal to, and is greater than or is equal to. All of these operations are either true
or false, which is a boolean value. Now, there are other ways to create
boolean values in Godot, but those aren't that important yet. Although, what is important to mention
that you can also combine multiple conditions. Like, for example, A is greater than five and B is equal to two.
And by the way, if you're wondering why we are using two equal signs for the comparison here,
that happens because when you are creating a variable and you assign a value to it.
For that, we are using the equal sign already, and we can't use it here and here at the same time.
For all of this, I want to work in Godot once again, create a new scene where the root node is a 2D node.
Let's call this coding free boolean to add a bit more detail. Then I can zoom in a bit and add a
sprite to the scene. Like so. After that, I want to attach a script to the scene like we have done
before. All the defaults here are totally fine, and then create. Just for testing purposes, I want to
create a func underscore ready. In there, for a really, really basic if statement, you first of all want to type
the if keyword, and then the condition that you want to check. For example, 10 is greater than five,
which is going to be true. If that is the case, add a colon and press enter.
Then, once again, we have an indented line. Via that, you know that any code that
comes afterwards is part of this if statement. Just like for the if statement, we have one level of
indentation, and that way we know that the if statement belongs to the ready function.
Same system, really. Now, if this statement is true, I want to print,
let's say 10 is greater than five. Now, I want to save the entire scene. coding free boolean.tscn is totally
fine. Click on save, and then run all of this. In the output, we are getting 10 is
greater than five, which is perfect. If, however, I change this condition to four is greater than five and run this
again, then we are not getting any kind of output.
This line only gets run if this condition is true. If it is not, then Godot is going to ignore all of this.
And to go into a bit more detail, let me get rid of all of this and then print the comparison operator right away.
Let's say four is greater than five, which we know is not true. But, if I run the script,
then Godot is telling me that this is false, and this is a boolean data type. If I make this a true statement, let's
say seven is greater than five, and run this again, then we're getting true.
Other comparison operators would be an equal comparison, for which you need two equal signs.
And for this, let's check if five is equal to five, which it should be. And it is.
Perfect. If I change this number to a two, then this is going to be false.
And besides that, we have smaller or equal to and greater or equal to. Besides that, one more that I forgot to
mention is this one, which checks if two values are different from each other.
So, at the moment, we are checking if two is different from five, which is. So, if I run this, then we are
getting true. However, if I check five is different from five, then we're getting false because, well,
five is five. So, with that, we have basic boolean values and we can use them inside of an
if statement. Once again, as a reminder, all you need is if, and then let's say four is equal
to four, a colon, and after that, you can run any kind of logic. Let's say print
four. Besides that, what you can also do is via and expand the if statement.
So, for example, we only want to run this if statement if four is equal to four and if 10
is greater than three. Both of these statements are true. That way, we are getting four.
However, if one of them is wrong, then this if statement is not going to run. So, if I change the three to an 11,
then this if statement is not going to run. Both of these statements need to be
correct. If you only care about one of them, you can use the or keyword.
That way, only one of those has to be true. So, if I run it now, since four is equal four, that part is
true, the entire thing is still going to be run even though 10 is not greater than
11. And that's pretty much it for basic if statements.
Although, there's one more thing that you can do. Two more things, actually. For a basic if statement, let's say if,
and I want to have a false statement, four is greater than 10.
If that is the case, I want to print A. This condition, obviously, is not going
to run. However, if it is not running, I want to do something else instead. That I can do via the else statement.
In which case, I want to print B. What is going to happen now is that Godot checks this if statement first. If
it is correct, it's going to run this line. However, if this doesn't run, so it's
false, then Godot is going to run the else statement and will print B. In other words, if I run this now, we
should be seeing B, and we do. However, if this statement was to be true,
then it would only run the first line, in which case we would get A. You only ever get one of these. They
can't run at the same time. And you can be even more detailed in here via the elif statement.
This is going to run if this one is false and you want to attach another condition to it.
Let's say one is equal to one. If that is the case, I want to print C. And let's make sure the first
condition is going to be false, so eight is greater than 10. They can run the thing again, and now we
should be seeing C, and we do. So, at the moment, Godot starts on this line and checks if it's true, which at
the moment, it's not. Because of that, it's going to the elif condition and then checks the boolean
value. In this case, this one is true, so it runs C and then discards anything that comes
afterwards. However, if this condition wasn't true, let's say two is equal to one,
then Godot is going to print B. So, it checks this condition, it's
false, it goes to the next one, it's still false, so it goes to else and we're getting B.
Obviously, these conditions aren't really that useful yet. But, once we start using properties and things like
node positions or health values, this becomes incredibly powerful. If statements are being used all the
time. You see them constantly. So, something we are definitely going to practice in just a bit.
First of all, though, there's one more way to execute code that you don't see that often, and that is a while loop.
This while loop runs code as long as a condition is true, which means you do have to be really,
really careful. If you do something like while one is equal to one,
and then you run any kind of code in here. Let's say print A. This while loop is never going to stop,
meaning any code that comes afterwards is not going to be executed. The code would simply stop working. In fact, if I
run this now, we would get a ton of output. So, if you look at the console,
you can see a ton of stuff, but well, Godot doesn't run well anymore, simply because this line destroys everything.
And now Godot has crashed. So, when you're using while loops, you do want to be careful.
Here we are again, and let's create a while loop that doesn't crash Godot. For that, you want to create a condition
that doesn't stay true forever. I think the best way to approach that is by first of all creating a variable.
Let's say var A, and this has to be an integer with a default value of zero. This we can make a bit shorter by simply
doing this. That way, we have a variable with the name A, and we're assigning an integer
to it, and because of this colon, this variable can only have integers. This we want to use inside of this while
loop. Let's say I want to check while A is smaller than 10.
While that is the case, I want to print the value of A, and then also print while loop is
running. This would still crash Godot. Because A doesn't change. It would
always be below 10, because the current value is zero. However, what we can do is A plus equal
one. That way, this condition is going to be false eventually.
Let's try to run the scene. We are getting the scene running perfectly fine. Godot doesn't crash.
That's a good start. And inside of the output, we are getting zero, while loop is
running, one, two, three, and so on. We're getting up to nine. And then the while loop has stopped.
That way, we could run code multiple times. Which occasionally can be super useful.
Although in practice, you don't really see while loops. Simply because if anything goes wrong,
you are crashing the entire game. And there are better ways to run code multiple times.
But once in a while, it does come up, and you do want to know what it's doing. That being said, what you really want to
practice is the if statement. So, let's do that. I want you guys to bounce the sprite that we have created left and
right. Or in other words, make the sprite move left and right, and whenever it hits the window border, make
it bounce in the other direction. There are a couple of ways of doing that. I guess just get started and see
how far you get. First of all, we want to move this icon. I guess we can start that by moving it
to the right. For that, we will need the func_process. I want to grab the icon,
update the position.x. And let's say plus equal two.
If I run the scene, the icon should move to the right. It's a bit slow. I guess we can go with
10. And that looks reasonably all right. Although this number has to change. So,
if we hit the right side of the window, this 10 should become a negative 10. I think the best way to approach that is
to create a var direction. Which once again is going to be an integer, and the default value should be
one. After that, I want to multiply this 10 with the direction.
That way, by default, with this value being one, this value keeps on being a 10. Or in
other words, we are still moving to the right. That looks good.
But if we change this one to a negative one, and run the whole thing again, then we are going left. And we do.
Perfect. In fact, what we can do is replace this 10 with a proper variable. Like for example, speed.
This once again could just be an integer with a default value of let's say 15. This 10 was still a bit slow.
And instead of this 10 now, I want to have speed. That way, we can control the speed and
the direction of this Sprite2D. And this kind of logic you see a lot, where you have a speed and a direction,
and this you apply to some kind of node. We are getting really close to having actual games.
But anyway, for now, the start direction should be one. So, we are going to the right.
However, on every single frame of the game, I want to check if
the icon.position.x is smaller than or equal to the right side of the window. Which in this
project is under display and window, 1152. If you change this number, go with
whatever's in here. In my case, I want to check if the icon.position.x is greater than 1152.
If that is the case, direction should be negative one.
That way, if I run the scene, we are going to the left. And I realized this should be
greater than or equal to 1152. That way, this should actually work. And now,
we are going to the right by default, and then we are bouncing and going to the left. Although we never go back.
That we can address via another if statement. Where we want to check Let me copy all of this. If the current
position.x is smaller or equal to zero. If that is the case,
direction should be one again. And if I now run all of this again,
the Sprite2D should bounce left and right. And it does. That looks pretty good.
And all right, with that, we have if statements and while loops, but most importantly, if statements.
Next up, we're going to work with data. Once again, here are the most common data types I have talked about earlier.
At this point, we have covered the first three, so we should be good on those. So, finally, we can work on arrays,
dictionaries, and vectors. Vectors is what we're going to start with, because those you are going to use
the most. Vectors are basically a better way to store numbers.
We have vector twos and vector threes. Now, technically, there are also vector fours, fives, sixes, and so on, but we
only really use vector twos and vector threes. For a vector two, it just stores two
numbers. Vector2.x and Vector2.y. If you have a vector three, then you
have X, Y, and Z. Other than that, they work in exactly the same way. By that system, you can
store, for example, positions incredibly easily. On top of that, vectors are really
useful because of vector math. The most common example is when you multiply a vector two with a integer. Or
float, doesn't really matter. In that case, you are multiplying both values. So, the five becomes a 10, and the two
becomes a four. Both were multiplied with two. Besides that, you can add two vectors to
each other. That way, you are adding the X part, so in this case, the 10 and the one together, and the Y part, the three
and the two. The end result would be 11 and five. There are a few more examples of vector math, but we get to those when
we make the actual game. Finally, vectors have a ton of methods that are incredibly useful.
And I guess let's have a look at all of those in practice. Once again, back inside of Godot, I want
to create a new scene with a 2D root node. Coding for data.
This I want to save right away in the usual folder. And also attach
a sprite to this scene. So, we can work with something. Finally, I want to attach a script to
the entire thing. Create all the defaults here are fine. And then, I want to work inside of the
ready function. And for now, print the position of this icon.
Drag it in there, and then look for the position. If I now run this script,
as an output, we are getting the values 327 and 310. This is a vector two.
Or in other words, if you look at this icon, the Sprite2D, under transform, you can find the
position. And if you hover over it, Godot is telling you the data type. It is a vector two.
Which means on this vector two, we have two values that we can access via X and Y.
If we go with X, then we are going to get the first value, 327. Let's just try that, and there we go.
327. And of course, you can also create new vector twos via a variable. For that, you want to create a new variable.
Let's call it pos for position. And then, you simply assign it a vector
two. And inside of Godot, we have vector two and vector two I. The I means that you're only getting
integers as a value. By default, you're getting floating point values. Most of the time, you are simply going
to go with vector two, three, or four, depending on how many values you need. The integer version isn't really that
common. It's very specific, and we are not going to use it. You want to have parentheses, and then
you can set the X and the Y value. Let's say 200 and 300. This would be a very simple vector two
that we can use to, for example, update the position of the icon. icon.position is going to be the pos
variable. If I now run all of this again, then we have moved this logo around.
So, if I change the number from 200 to 500, run all of this again, then the Godot logo should be roughly
here. And it is. Perfect. And that's pretty much all you have to know for the absolute basics of it.
You can create a vector two by simply writing vector two, and then you assign the values to.
Besides assigning values, you can also add dot, and then you have, for example, down,
left, one, right, up, or zero. Those are simply pointing in different directions.
If you, for example, have right, you would get a vector two with one and zero. Meaning, in a 2D space, you'd be
going to the right by one unit. And remember, in the last part, when we tried to move the icon around, we could
do that on the x-axis quite easily. But now, via vector two, we can do it in any direction.
For that, and this is something you see all the time, you want to use the process function.
Add icon.position, and then add the position. Although, a better name
for that would be the direction, because this is what this thing is effectively. Then we can get rid of the ready
function. We don't need it anymore. And instead of position, this is going to be direction.
This at the moment would move the Godot logo, but it's also going to be very, very slow.
But let's try. There we have the Godot logo moving to the right.
If I change this vector two to, let's say, one and one, we're going to the right, and we're
going down. Remember, to go down, you have to increase the Y values. And there we go. We are going down and
right. On top of that, what we can do, because of vector math, we can create another variable. Let's call it speed.
And this can be a basic number like 20. This I can multiply with the direction, and then we are still going in this
direction, but now at a much higher speed. Inside of the game,
that is looking pretty good. And just to demonstrate how this would be working, if I print another vector two, so vector
two right away, with the values of two and three, I can multiply the entire vector with,
let's say, three. Then we're going to multiply this two and this three both by three. As a
result, we would get six and nine. Let's try. There we go.
We are getting six and nine, both of which are floating point values, because a vector two always stores floating
point values, unless you add vector two.i, then you would get integers, which you
usually don't want. And well, that's pretty much it for the basics of vector twos.
Especially for positioning, they are incredibly common. We have two more data types, and the
easier one is arrays. This is just a list that stores values. It would look something like this.
You can have any kind of data type in here. Any kind of number, strings, booleans. You can even have an array
inside of another array. By that, you can store any number of data points. And if you want to get one value, you are
doing an indexing operation, which simply means that you are adding square brackets afterwards, and then you define
the index that you want to grab. The index always starts at zero, and then goes up.
The first value would be index zero, then you have one, two, and so on. Which means, if you have square bracket
zero, you're getting the first value. If this was a one, you'd be getting this value.
And that's pretty much it. You can also loop over all of the values inside of an array. For that, you would need a for
loop. You start with the keyword for, and then you define a variable. Very often this is called I, but you can call
it whatever you want, as long as it's a valid variable name. And then you need some kind of array.
Now, inside of the code that has to be indented, we are running the code for every single value inside of the array,
and we are storing that value inside of the variable while we are running it. That way you can grab every value and
work with it. But let's do all of this in practice. And for that, I want to create a func
ready once again. To create an array, you simply want to,
let's say for now, print, then square brackets, and then any kind of value. Let's say one, two, and three.
We can have a string. We can have a boolean value that you can create directly. All you have to type is
true or false. And finally, you can add another array into an array with values inside of it.
One, two, and three. If I now run the script, we are getting, inside of output, all
the way in the beginning, the array. And that's really all we need.
And I guess while we're doing this, let me comment out this line, so we only see one output. I hope the system here
makes sense. You simply have square brackets, and then values separated by a comma.
There's no limitation on data types or number of items in here. It's a really flexible system.
And if you want to grab one item after the array, you are adding square brackets, and then the index. For
example, zero would give you the first item. You always start counting from zero,
which sometimes can be a bit confusing, but you get used to it. Pretty much all programming languages work like this.
But now, if I run all of this again, we are getting one, which is this integer here.
If I set this to three, we're getting zero, one, two, and three. Meaning, we would get the string.
At least if I can count right. And we do. That looks good. Once again, I think this operation is pretty
straightforward. I guess one thing that you can do here is count from the back via negative
numbers. Negative one would be this last item. Negative two
would be false. Negative three would be the string, and so on. You basically go backwards.
We're getting the array as an output. Or, to be a bit more specific, the array inside of the larger array.
That works pretty well. Besides that, what you can do is a for loop. We're for I in, and then I want to
grab this array. Let's actually store it inside of a variable.
var, let's call it test array, and then this value. Or any kind of array, it doesn't really
matter. This we can replace here, test array.
Makes all of this a lot more readable. And also, for I in test array. Don't forget the colon.
And now, Godot is going to go for every single value inside of this array, and it's
going to store it inside of this I variable. Which means, inside of the for loop, we
can print I, and we would be getting every single one of these values. Let me run it again.
Inside of the output, we're getting this one, two, and three because of this print statement. But
after that, we're getting one, two, three, string, false, and the array one, two, and three.
We went for every single value inside of this array. By that system, you can loop over the array and do pretty much
anything you want in here. Which is a fairly common operation. And besides arrays, we have
dictionaries, which are pretty much arrays, except now we have key-value pairs.
This system looks like this. We have curly brackets, and then we always have a key, a colon, and a value. With the
key-value pairs being separated by commas. On top of that, both the keys and the values can have any data type.
Our first key-value pair is this one, where the key is the string A, and the value is the integer one. The same
system applies to the second key-value pair. But for the third key-value pair, the key is the string C, and the value
is another string called test. Finally, for the last one, the key is the integer four, and the value is an array.
All of which would be totally fine. Like for the array, you can still do indexing.
Although, this starts to get a bit messy to observe, but effectively, we have the dictionary here, and then we
have square brackets with the key that you are looking for, which currently is this key here.
The output is then going to be the associated value to it, the one here. And this is what we're getting.
Also, like for an array, you can use a for loop. We're for, then the variable name, in,
and then the dictionary. Then you cycle over the dictionary. Although, for that, you do have to be a bit careful, but
let's do all of this in practice. I am inside of the code, and I want to create another variable.
test dictionary To create a dictionary, you want curly
brackets, and then the key-value pairs. Let's say, A could get a value of one. Then I can have a key called one, two,
and three with the associated value being an array with one, two, and three.
And finally, you can even have a key like true, the Boolean value where the associated key is
I know, a string. Let's just call it string. For keys and values inside of a
dictionary, any data type is fine. Although, I guess what I haven't mentioned is that these keys need to be
unique. You cannot have duplicates in there. Which means using something like a
Boolean value is usually a pretty bad idea, but you could do it. Once you have that, and let me comment
out the stuff that we have done for the array. Oh, and by the way if you select multiple lines of code you
can press control or command and then the forward slash. That way, you're commenting out multiple
lines of code. Super handy. I want to print the test dictionary. If I now run the current scene, we are
getting the dictionary that we have just created. And this stuff should have been commented out.
You get the idea. We have a dictionary where we have key-value pairs. And these keys you can access via
indexing. For example, if I add square brackets and then the key one, two, and three.
That's this key here, and the associated value is the array one, two, and three. So, if I now run all of this
the value that we are getting is one, two, and three. With that system, you can store data and
be much more explicit what it's about. Having too many values inside of an array can be a bit confusing. So,
sometimes using a dictionary is much more elegant and much easier to understand.
Besides that like for a dictionary, you can use a for loop with for I in test dictionary
and then for now, I just want to print I. And let's see what we get. And to not make this confusing, I want to comment
out the earlier print statement as well. So, the only output that we are getting is
from this for loop. Let's run it. There we go. As an output, we're getting
A, one, two, and three, and true. If you compare this to the actual dictionary that we have created
you can see that we are only getting the keys. We're getting A one, two, and three, and the Boolean
value true. If you use a for loop with a dictionary, you will only getting the keys returned.
Which sometimes can be what you want, but very often not really ideal. To customize that every dictionary has a
couple of methods that let you customize how the for loop is going to work. By default you're getting the keys.
If you don't want that, you can use values. That way, this for loop is going to cycle over the values inside of this
dictionary. Let's try. And there we go. Now, as an output, we are getting
one, the array one, two, and three, and string. Which is the values inside of this
dictionary. So, that is something you do want to be careful about. Using a for loop with a
dictionary can either get you the keys or the values. Now, most of the time, we are not going
to work that much with data. So, arrays and dictionaries aren't going to be a common thing that we will work with. But
once in a while, they are very handy. The most important thing that you want to practice though are vectors. Those
come up all the time. For that, I want you guys to make a sprite bounce in all directions.
The sprite should move via a vector two, and it should bounce on every single window border.
Pause the video now and try to implement this one. You will need a vector two and if statements for all of this.
Back inside of Godot, I think just to keep things organized, I want to add another Sprite 2D to the scene and
rename it to exercise sprite. After that
inside of the process function I want to create another variable, and all of this is for the exercise.
I want to have an exercise direction which is going to be a vector two. That let's say by default is pointing
to the right. So, X is going to be one and it's going to point up. Y is going to be negative one.
This variable should only hold vector twos. Which you can do by defining
the vector two as the data type or simply do this operation. That way, the first value assigned to
this variable is a vector two, and afterwards, it cannot change the data type.
Besides that, I want to have an exercise speed which is going to be an integer with
let's say 30. After that inside of the process function
I want to get the exercise sprite and update the position. To this value, I want to add the
exercise direction multiplied with the exercise speed. And now, this line is getting quite
long. Which makes it a bit hard to read. If that's an issue for you, you can click
on this button. That way, you are expanding the code window. Quite handy sometimes.
Let me try to run the code. The Godot logo should move to the top and to the right.
And there we go. We are moving in the right direction. Although, we are not bouncing.
Which is the whole point of the exercise. We can check if and I want to get the exercise sprite
position .y is smaller or equal to zero. If that is the case I want to get the exercise direction and update the Y
value. This one should now be one. That way, and let me reduce the speed
just a bit to 20 we should be bouncing. There we go. We are bouncing once at the
top of the window. And effectively now, we have to duplicate this thing once
and check if the logo is exceeding the value 648 48 or whatever you have set as the
window height. The default is 648 if you haven't touched this value. If that is the case
exercise direction.y should be negative one. Then we can duplicate all of this
and then change position.y to position.x. If position.x is smaller than zero, we
are on the left side of the window. Which means exercise direction.x should be one.
If the position is greater than 1152, then we are on the right side of the window. So, the direction.x
should be negative, meaning we are going left again. And with that, we should be done.
There we go. This looks like a pretty good bouncing. It is time to talk about functions in a
bit more detail. Along the way, we are also going to talk about scope and return.
Really important concepts that you have to understand to actually understand functions.
But let's go through it step by step. We have already seen that you can create and call functions.
Creating functions looks like this. You start with the func keyword, then you add the name of the function.
Afterwards, you add parentheses with the parameters that we haven't done yet. Then you have to add a colon, after
which you have the indented code with all of the logic. That way, you are creating a function.
To actually use the function, you have to call it. Which basically means you want to write the function name along
with parentheses, and inside of the parentheses, you can add all of the arguments.
That way, the function actually does something. We haven't actually created any parameters. So, let's have a look at
that. As always, here we are back in Godot, and I want to create a new scene. Just as before, this is going to be a 2D
scene that I want to rename to coding five functions. Let me expand this just a bit, like so,
and then save the entire thing. The location doesn't really matter, so click on save, and then we have a scene that
we can work in. All I want is some code, so I want to attach a script to the node. Click on
create with one of the defaults. And then we can write some code. For now, I want to create a function.
That we can just call test func. That would be the name of the function,
and afterwards, you need parentheses and a colon. Then inside of the function, you have to
write the logic that you want to execute. Let's do something simple. I want to print test function.
And that's all that this function does. With that, we have created a function. And this we have done a couple of times
by now. However, if I execute this one scene nothing is going to happen. We don't get
any output. That is because this function does not get executed. Or in other words, it's
not being called. The functions that do get called automatically are functions that start
with an underscore. Like for example, func_ready. This function gets called by Godot once
the scene is ready. Which means what we can do inside of this function, we want to call
this function. We simply have to do test funk, then parentheses, opening and closing ones,
and then we are calling all of this code. Which means if I run this one scene,
instead of the output, we are getting test function. This part should still be super
straightforward. We have done this a couple of times already. But all of this we can expand.
Most importantly, by adding parameters. That means inside of the parentheses, you can have parameters. For example,
parameter underscore one. Simply by doing that, Godot is already going to complain. That Let me expand
this. There are too few arguments for the test function call. Godot expected at least
one, but received zero. Or in other words, there's now one slot that we have to fill when we are calling
this function. This at the moment could be any kind of data type. I could for example write
one, two, and three, and Godot would be happy once again. Also, let me fix my typo. This should be parameter one.
This parameter one becomes a variable inside of the test function. The value assigned to this variable is
what we have added as an argument when we are calling the function. Or in other words, I can print
parameter one, run the scene once again, and as an output, we are getting 1 2 3.
The value that we have added when we called the function. With that system, you can make your
functions much more flexible. And you can also force a certain kind of data type. All you have to do is add a colon
after the parameter, and then define the data type. For example, right now, I only want to allow integers for this
data type. That way, if I change this to, let's say, a string that says something,
doesn't really matter, then Godot is going to complain. You cannot pass a value of type string as an integer. This
function only accepts a single parameter that has to be an integer. Let's change this back to 1 2 and 3. Although, you
can also add multiple parameters. Let's call this one parameter two,
which can be a string. And then Godot is going to complain once again. So, now we have to add a second
argument, which now has to be a string. And once again, Godot is happy. And to actually use parameter two,
what I haven't covered yet is that when you're calling the print statement, you can add multiple arguments as well.
For example, we can add parameter one and parameter two. Then, if I run all of this again, we're
getting 1 2 3 and string all combined. If you want to have a space between the two, simply add one more argument with a
string that has one space inside of it. That way, this looks just a bit cleaner. And
effectively, those are parameters and arguments. Parameters are slots inside of a
function that you can fill with arguments, and that way, you are giving them a value that you can use inside of
the function. Super handy. Finally, you can give a parameter a default value. Let's say for parameter
two, we want to have a default value, and that you do right after a default value of test.
That way, if we don't give an argument here, then Godot is going to use this value.
Or in other words, I can run the entire thing again. We're getting 1 2 3 and test.
Godot used this value for parameter one and this value for parameter two. The one thing that you always want to be
careful about is that these parameters are organized by their position. This is the first parameter, so the first
argument is going to go to this parameter. Then you have the second parameter, and
the second value would be for that one. So, second would be here. Always be careful about that one. The
position of these parameters and their arguments are really important. It's the only way to really link them.
But other than that, this is basically as complicated as it gets. If you understand it, you understand functions
reasonably well. That being said, there are two concepts that are really important that can be
quite confusing. The first concept is scope. Or more specifically, you have a global
and a local scope. What that means is inside of a function, you can create variables. But if you create a variable
inside of a function, it only exists in that function. Or to be a bit more technical, the variable exists in the
local scope of the function. Variables created at the beginning of the script are in the global scope,
meaning they are accessible everywhere. Inside of this test function, you can create variables.
This happens in a normal way. You type var, and then the name of the variable. Let's call this one the local variable.
This could be any kind of data type. For now, let's go with local var. Once you have that, you can
use this local variable like any other variable. You can print it, you can change it. Let me just print it
and run the script. We are getting local var. So, that looks good.
We have a variable like any other. However, inside of the ready function, this variable does not exist.
If I try to print it here, print local underscore variable,
Godot is already going to complain that the identifier local variable is not declared in the current scope.
What that means is that this function has a scope, and this function has a scope.
And local variable only exists inside of this test function. It does not exist inside of the ready function.
I guess an easier way to think about it is that every single function is its own box.
Inside of this box, you have a ton of logic, and you can create variables. But these variables only exist inside of
this box. If you create another function, this function would be another box with its
own content. That's really all that local scope means. Variables created inside of a function are only available
in that function. However, what you can do in the beginning of the script is create a
variable, and this is what you have already seen. Let's call this one global variable
with the value global var. And this global variable is available everywhere. We can print it inside of the ready
function, and we can print it inside of the test function. It would work in both of them. So, we're
getting global var twice. First from this print statement, and then from this print statement. The
reason why the system exists is that functions should be self-contained. All of the logic in here shouldn't connect
too much to stuff outside of the function. It really helps to have modular logic, where a function does its
own thing, and simply gets its data via the parameters. If you get too much data from other
sources, things can get really complicated and confusing. So, be careful here. And with that, we have
covered scope. Next up, we have to talk about return values. This is how data is moved around. And
also, you can specify what kind of data a function returns. Something that I haven't talked about
yet is this arrow and then void. This defines what kind of data this function returns, and void means it
returns nothing. This part actually is necessary. If you get rid of it, nothing would happen. But you can make it
useful. For that, I want to create another function. Let's call it function return
something. No need for any parameters, but I do want to return an integer once
we are calling this return something function. After that, you need to colon, then we
can print return something function was run. However, now Godot is still complaining
that not all code paths return a value. Effectively now, Godot expects when this function is run, it returns a value,
specifically an integer. To get that, we need the return keyword, and then some kind of value that we want
to return. For now, let's go with 100. And then Godot is happy again. If I print
return something, really importantly with the parentheses, so we are calling the function,
I can run this script, and we are getting 100. And I think it's important to understand
what happened here. Let's go through it step by step. Inside of this print statement, we have
called return something, which means Godot is looking at this function. First of all, it is going to print some kind
of string. Doesn't really matter what it is. After that, we are returning the integer
100. Or in other words, this function is replaced with 100, or whatever was
returned in here. This 100 is then being picked up by the print statement, and Godot prints out
the value. Effectively, this return something function, after that is called gets the value of this 100.
We could even change the value. For example, you could multiply it with two, rerun the script, and now we're getting
200. Programming languages, when it comes to this kind of system, are super flexible.
And generally, understanding how return works is really, really important. It pretty much defines how data is sent
across your code. For example, here is a slightly longer line of code.
First of all, we are creating a vector two that has an X value of three and a Y
value of four. This will be the first value that gets returned. After that, we're calling a method
on this vector, where we're getting the length of the vector, which means the returned value from the
vector gets changed to something else. After that, we are multiplying the entire value by a
factor of two. Or in other words, the thing that was just returned, this value here, gets
changed once again, and we're getting something else. After that, all of this
gets passed into the STR function, which turns any value into a string. Which means this becomes, once again,
another kind of value. Finally, we are at the print function, we are printing this final value.
This does look a bit complicated, but once you play around with it, it becomes really straightforward.
You always have to go from the innermost part to the outermost part, and then work through it step by step. Getting
used to all of this will take you some time, but not that much time. You'll be fine.
For now, the one thing that you really have to understand is that when we have this arrow at the end of the function,
we are defining some kind of return value. If that is the case, inside of the
function, you have to return some kind of value at the end of it.
And all of this should be practiced. So, let's do an exercise. I want you to create a calculate
function. It should look something like this, where you can add two numbers and then
the operation as a string. It should be plus, minus, divide, and multiply. The correct answer should be returned,
which means inside of calculate, you shouldn't use any kind of print statement. You simply want to return the
final value, and then print that return value. Pause the video now and see how far you
get. I want to create a funk calculate, where we have three parameters.
Let's call it number one, number two, and the operator.
All of those should only accept a certain kind of data. For number one and number two,
let's say, to keep it simple, they should only be integers. Whereas for the operator, this should
always be a string. The return value, once again, to keep things simple, should also be an
integer. And just to test if things are working, I want to check if the operator is equal
to plus. If that is the case, I want to return number one plus number two.
And if that is not the case, else, I want to return, let's say, zero.
That way, inside of the ready function, and let's comment out all the other
stuff, so this doesn't get confusing, I only want to print the return value from the calculate
function, where for now, we are doing one plus two, like so,
and then we should be getting as an output the number three. And we do. That looks good.
Although this logic here doesn't work terribly well yet. That we have to work on. First of all,
I want to create a local variable called result. This is going to be an integer with a
default value of zero. And this is the only thing that we are going to return at the end of the
function. In between that, via if statements, we are going to do the actual math.
So, let me copy and paste this in there. First of all, I want to check if the operator is plus,
then the value of result should be number one plus number two. Elif operator
is equal to minus, then result should be number one minus number two.
And I think you get the pattern. If operator is equal to multiply, then result
should be number one times number two. And finally, else,
this has to be divide, so result is going to be number one divided by number two.
And that is pretty much all we need. We have a couple of parameters inside of the function,
then we create a local variable, and we're adding a whole bunch of logic that assigns a value to the result. At the
end of the function, we are returning one value, and that one value is being printed out.
This should still give us a three. Let's try. That looks good. We're getting a three,
and if I do 10 minus three, then we should be getting seven. And we do. That looks really good.
I suppose one thing that you can do is give the operator a default value of plus.
That way, if we only give it two numbers, like so, then we're going to add them together by
default. Let's try. We should be getting 13, and that looks good.
All right, perfect. With that, we have basically all you need to know about functions. And by the way, inside of
Godot, the default style guide tells you that there should be two spaces between
functions. Not something you have to do, but something that you usually see. It's
just to keep your code a bit more readable. Anyway, with that, we have another super
important concept. All righty, let's get started with the first project, where we are going to
create a Frogga style game. Obviously, this isn't going to be the most sophisticated game. However, it is
going to teach you all of the important parts of Godot, like using scenes and nodes, using GDScript, and using all of
this to create logic. By the end of it, you should already have a pretty decent idea how Godot works on a basic level.
Now, to get started for the first part in this project, we are going to create a very basic outline, where we have a
player and the background. Or to go into a bit more detail, we want to create a basic game scene,
and then place the player inside of it. On top of that, we want to move the player by just a bit.
Although for now, this is going to happen without input. That's going to be the next part.
Here we are in Godot, and at the moment, we don't have any kind of scene inside of the engine.
That being said, if you look at the file system, we have a couple of folders. Most importantly, we have graphics. In
there, we have, for example, the player, a simple version and the tile set. We're going to come to that later.
Then we have a whole bunch of objects and so on. We also have fonts and audio, but those
aren't too important. Now, to get this project, you want to look at the video description. In there, you can find a
link to a Google Drive folder, which is going to look like this. In there, you have the project files for every single
game. For example, right now, we are working on the Frogga game, and
in there, you have the Frogga project setup and the Frogga start files. The second one you want to download, so
download, and then your computer should be downloading the entire thing.
Inside of the project stages, you're going to find this, by the way, the finished code for every single part
of the game. If you get stuck somewhere, you can use that to figure out what went wrong. Should be quite helpful.
But much more importantly, the file you just downloaded is going to look like this, and you want to extract it
in the usual way. Then you're getting the Godot starting files. Right now, this is just a folder.
To import the entire thing into Godot, you want to open the editor, and then you can simply drag and drop the files.
From the folder, the one you have just downloaded with all of the stuff inside, just drag it in there, and then you're
good to go. Open this one, and you should be seeing the project. Alternatively, you can go
to import, and then navigate to where you have to be, which in my case is going to be the
downloads folder. In there, you have the Frogga start files. Open this one, and then you want to open this project file
inside of the folder. You're going to get the same result that you are seeing in here.
Double click on that, and then you get exactly what I have started with.
Other than that, this project does not contain any kind of script. All of this we have to create ourselves. And well,
for that, first of all, I want to create a 2D scene, which I want to rename right away to
game. Then save the entire thing with control S or scene and save scene.
And I want to save it inside of the scenes folder. Game.tscn is totally fine.
And now we have our first scene for the game and this is going to contain all of the logic.
So for example, attached to this is going to be the player, the background, all of the cars and so on.
Speaking of which, first of all, I want to add the background to it and for that we can look at graphics in
there somewhere we have map.png. This I want to import. Or in other words, I want to create a
sprite 2D which can hold a texture. So in other words, I want to drag map.png into this
texture slot and then we have the background. That is actually already pretty solid. That way we have at least
something to look at. Next up, I want to create the player. For that, I want to create a new scene
and then create another 2D scene. This is going to be for the player and to that I want to add another sprite
2D. This sprite 2D is going to display the player graphic. So let me zoom in a bit
and then go to the folder graphics, player and player symbol. Drag it inside of the texture and then
we have the player. Although if you look closely, this is looking horrible. Also, while I'm
talking about it, if you look at game and you zoom in into this map, this is also not looking great. So what's the
problem here? When you have graphics like for example the player, Godot has to scale it. This original player
graphic for the player is 12 by 14 pixels, a really really small graphic. And Godot, to make it this big, has to
scale it up by a lot. Which is totally fine. The issue is that there are different ways to scale a graphic and
the one that we are currently using is really really not working. To fix that, all we have to do is go to
texture and there we have filter. At the moment it's set to inherit, but if we set this to nearest, then this is
looking significantly better. That being said, this isn't what I actually want to do. So let me undo it
simply because I want to do this operation for every single graphic inside of my graphics folder. Doing it
one by one would be kind of a pain. You can simply go to project, project settings and then look for texture
and then look at textures. In there you have a default texture filter which is set to linear by default, but we want to
set it to nearest. That way by default we are scaling all of the graphics in this filter style and
that is going to look a lot better. Nice improvement. Then I want to save the scene.
Player.tscn is totally fine and then we have the player. And this player we want to add to the
game scene. So with game selected, I want to either instantiate a child scene or press
control shift and A and then we can add the player scene to the game scene. If I now zoom in a bit, we can see the
player. Let's move the player roughly here so it's a bit easier to see.
And then we can try to run the game. For that, click on this button here or press F5 on the keyboard
and then you want to select the current scene to start the game. Select current, then we're getting a
graphic and it does work, but it's really small at the moment. That we're going to fix later. For now, this is
totally fine. I am happy with that. I suppose to see the player a bit better, we can scale the sprite 2D which we do
under transform and then scale it by a factor of six. If I now go back to game, the player
should be much more visible. And that is definitely better. All right, with that we have two scenes
that work together. Next up, we want to move the player in a certain direction. For that, the player scene needs to have
a script. So click on attach a new script. We want to have inherit node 2D and save
it inside of scenes and player.gd. All of this is fine. Click on create
and now we can write a couple of lines of code. Now for the player, first of all, I want
to have a couple of basic variables. I want to have a variable for the direction
and this needs to be a vector 2. If we set this data type, the default value that we are getting is going to be a
vector 2 with X and Y both being zero. Which is exactly what I want. Although if you want it to be a bit more specific
here, you could do vector 2.0. Same thing really, choose whatever you like.
Besides that, for the player, I want to have a speed which should be an integer and for the default value, I want to go
with let's say 200. Once we have that I want to call a function that runs on every single frame.
This could either be func_process or it could be func_physics_process. I am going to use physics process
because later on for collisions, we want to have just a bit of physics. Although at this point it wouldn't
really matter. And in here we want to move the player position. Or in other words, we want to
grab the position of the current node. Remember, when we are attaching a script to a node like for the player at the
moment, we get access to all of the stuff inside of the inspector. So at the moment we are targeting the
position via this position value. If you hover position you can see that this value wants to
have a vector 2. And the way I am going to approach it is I'm going to add a value to it which is going to be our
direction multiplied with the speed. And that's actually all we have to do. Although at the moment this isn't going
to do anything. So if I run the main scene the player is not going to move. But
that happens because our vector 2 for the direction is zero. We have a vector 2 with zero and zero and this we are
multiplying with 200. The end result is going to be a vector with zero and zero, so the position
doesn't change whatsoever. However, what we can do is change this vector 2 to a value that's not zero.
I want to have a vector 2 where X is one and Y is zero. And now if I run this thing again
our player is moving to the right, although it is quite fast. Let's change this to a five.
And there we go. Now the player is moving to the right. If I set this to one and one
then the player is moving right and down and that is working pretty well. Perfect. With that, we have a really
basic setup. Obviously it doesn't do very much, but at the very least we can move things
around. Let's do an exercise. I want you to create a new scene with a few objects like trees, boxes, whatever
you like inside of the graphics folder. Add all of that to the scene and then add the scene to the game scene. So you
are decorating the entire thing a bit effectively. On top of that, use GDScript to scale up the scene over
time. How fast this is going to happen is entirely up to you. Pause the video now and see how far you get.
I want to add another scene which once again is going to be a 2D scene. Let's call this one exercise object. The
name really doesn't matter and then save it. The scenes folder is totally fine, save in here and then we want to attach
a couple of objects from the graphics folder. Let's say I want to start with a basic
tree. You can actually just drag and drop it into the scene. Godot is automatically going to give you
a sprite 2D. Although by default the position is going to be a bit weird.
So let's reset that one and then the tree is right in the center point of the scene. I guess besides that we can add
another tree and let's say we could add a box like so. This I want to save and then inside of the game
I can add via this button or control shift A the exercise object. This we can place somewhere let's say
here. Then run the game and we have another scene inside of the game.
It doesn't look amazing yet, but at the very least we have something. Besides that
I want to add a script to the scene. All of the defaults here are totally fine, then create and like for the
player I want to run a function on every single frame of the game which I am doing via
physics process once again. Now for this thing, I want to target the scale property
which we can target via scale. So hover over the property inside of the inspector and then you are getting some
bits of information that are super useful. Once again, Godot wants to have a vector
2 with X and Y and that determines the scale. So to target it, I want to type scale and then assign a new value to it
where we want to get scale and multiply it with a value of let's say 1.1. Let's try the entire thing and that
might be quite fast and yeah, it definitely is, but you get the idea. Let's change this to 1.001.
Then it's not so strong anymore. Now we can see that the scene that we have just created is growing very, very
slowly. Not something we can use for the actual game, but for an exercise, this is
pretty all right. And with that, we are pretty much good to go for this part. Although there's one thing that is a bit
annoying. If you look at the bottom, Godot is complaining with the debugger, where we have not two errors, but two
warnings, that we are not using the delta parameter. To fix that, I want to add an underscore
to both of them. That way Godot stops complaining. If I run the scene again now,
the debugger doesn't complain, which feels a lot better. Next up, we are going to move the player around using
player input, which is bringing us a lot closer to an actual game. For that, we have to capture user input, which in
Godot is quite easy. We can simply create an input map. Via that, we can capture keyboard, controller, joystick,
and mouse input, which is really all that we need. So, back in Godot, you want to go to
project, project settings, and at the top, we have an input map. The way this thing is working is you define an
action, and associated with this action, you have some kind of input, like a key press on the keyboard, for example.
For example, I can type left and press enter, then we're getting one action for left. And to this action, we
can assign events, which is a fancy way of saying a button on the keyboard, a mouse button, a
joypad button, or whatever you have available in here. Godot is also listening for input, meaning if you
press a button on the keyboard, for example, the left arrow key, then it gives you the right option right
away, which is super handy. So, in my case, I want to click on okay, and now to the left action, we have the
left physical button on the keyboard. Besides that, another action I want to add to it is the A button on the
keyboard. Click on okay, and now we have two key bindings for this action. You could also add a controller, although
for now, I am not too worried about it. What I rather care about is to add other keyboard bindings for up,
right, and down. For all of these, I want to add the
keyboard bindings. So, for up, it's the up arrow on the keyboard, or the W key.
For right, I want to have D on the keyboard, or the right arrow. And finally, for down, I want to have
the S key, or the down arrow. And that is all we need for now. We can close this dialogue,
and then work inside of GDScript. Specifically, I want to work inside of the player. Now, there are a couple of
ways to work with the keyboard bindings. The easiest one, I think, is to use input, and then is action pressed.
This is looking for an action that is being pressed. Let's start with the right action, and
then print the result. If I now run the code, by default, we're getting false, because
the button is not pressed, but if I press right on the keyboard, we are getting true. If I release it, we're
going back to false. The way we could use that, for example, is to only move the player if this value
is true. Let me cut it out, and add it to an if statement. Only if you're pressing the
right button, then we want to move the player. If I run the thing now, the player is
not moving, but if I press to the right, then the player is moving, which is already quite a bit better.
Although this still isn't exactly what we want. To actually move the player in a certain
direction, I want to keep position is equal to direction times speed.
And then, when we're pressing the right button, I want to change the direction to a vector 2.right,
which is the same as a vector with one and zero. Besides that, I want to duplicate all of
this, and then get the action pressed for left. If that is
the case, direction should be vector 2.left. If I now run the code,
I can press to the right, the player is going to the right, and if I press left, we are going left.
And this kind of works, although the player never stops, which isn't ideal. Meaning we have to figure out some kind
of system to organize the input, and then get the right direction. There are a couple of ways of doing it,
and the best way to get started is to look at input. For that,
hold control, and then click on input. Then you get the documentation for input.
If you go down a bit, you can see all of the methods associated with it. There are quite a few. The one that we
care about the most is called get vector. Click on that,
and then we are going to do an exercise. I want you to read the documentation and figure out what input.get_vector
actually does, and how you can use it. Pause the video now, and see how far you get.
I hope you read this entry. I think overall, it's fairly straightforward. Basically, get vector wants to have four
inputs, negative X, positive X, negative Y, and positive Y.
Or in other words, for normal people, left, right, up, and down. These are the directions
that we can add to this method, and as a result, we are getting a vector 2 that organizes all of them super easily.
Or in other words, back inside of the player, I want to get rid of all of this,
and instead, update direction via input and get vector. Now, we need the four different
directions. Negative X is left, positive X is right, negative Y is
up, and positive Y is down. Once we have that,
I can run the game, and now move the player around. Feels like magic. If I stop pressing any of the buttons,
then the player stops as well, which works really, really well. Get vector you see all the time. It's
incredibly useful, and fundamentally, it's not that complicated. All it does is it takes four inputs, and then
returns a vector that we can use right away inside of the direction. And to finish all of this up, I want you
to do another exercise. Create another input, this time for the space key, and then inside of GDScript,
when this one is being pressed, print something. And as an extra challenge, make sure that when the button is
pressed, you're only printing it once, not multiple times. You will definitely have to read the
documentation for all of that one again. Pause the video now, and see how far you get.
Once again, back inside of Godot, I want to go to project, project settings, input map, and then create a new action.
I call this action confirm, because later on from the title screen, this one goes back to the actual game.
Confirm might not be the best name, but it's going to work for our purposes. The actually important part is I want to add
a key binding to this action, with the space button. Click on okay, and now we have space
physical. That's all we need. Next up, inside of the player script, I want to check if input
is action pressed with confirm. If that is the case, I want to print
something. And you might think that this is all we needed. However, if I now run the game,
and I press space, even if I press it once, we're getting something multiple times.
Not ideal. So, what's the problem here? Is action pressed checks if this key is pressed on every single frame of the
game, and physics process always runs at 60 frames per second. Meaning this function checks every 60
milliseconds if this key was pressed or not. Even if you only press it for tenths of a second, for Godot, this is
quite a few inputs. Now, there are a couple of ways to fix it, but the easiest one is to not use is action
pressed, but rather is action just pressed. That way Godot is only checking if the
button is pressed, but not if it is held down. If I now run the thing again,
I can press space, and we only get one output every single time. Much better. With that, we have user input. At the
moment, we do have some basic input, but the game just doesn't look very good. Most importantly, everything is tiny,
and we can only see part of the background. All of this is going to be fixed in this
part, where we are going to add the camera. That way we can zoom in, and actually
follow the player on the map. Unfortunately, cameras in Godot are really, really easy.
You simply create a camera, and then tell the camera to follow the player. That's all we need. The camera could
also follow any other object, really whatever you need. On top of that, you can also set limits
and speeds for the camera. That way, you have a ton of control over how this thing is moving.
First of all, the player shouldn't be scaled up anymore, but the scale should go back to one and one.
On top of that, inside of the exercise object, I want to get rid of this code, so we're
not scaling it up anymore. That way, I can run the whole thing and everything is super super tiny.
To fix that, we want to add a camera and zoom in. On top of that, the camera should follow
the player. Now, for that, through the player scene, I want to add a camera 2D. If I now go out a tiny bit,
you can see this pink purple-ish frame. That is the frame of the camera. And simply by having it attached to the
player, it is already going to follow the player. In other words, if I now run the game and I run around, the camera is
following the player, which is already a lot better. Besides that, if you look at the
inspector, we can modify a couple of things, most importantly the zoom level. If I set this to a factor of four for X
and Y, then the frame has gotten a lot smaller and if I now run the game, we can see the player quite a bit
better. And that is actually already making a pretty big difference.
You can also set the offset and for example move the camera down by quite a bit or up by quite a bit
because the player might want to look a bit more ahead, but I guess for our purposes, we can leave it at zero and
zero. Besides that, if you look a bit further down, we have a few more options.
We can set a limit for the camera. By default, these are basically infinite. Then we have position smoothing and this
you always want to enable. That way the camera follows the player a bit more smoothly. You can actually see
it right away. If I run the game and I move around, the camera takes a little bit of time to
catch up with the player, which right now looks a bit silly because the player is too fast.
But if we increase the speed of the camera to something like 20, then
this is going quite a bit better. Usually, you do want to have position smoothing enabled. It just looks and
feels better. But once again, whatever you think is best. Finally, we can set a limit. For example, for the left side,
we never want to go further than zero pixels. If I now run the game again,
I can go to the right, but the camera stops at position zero. And that is
pretty okay. Obviously, you want to measure this value.
For that, inside of the game, you want to look at where this map starts and ends.
The best way I find for that is to drag the ruler and then you get a pixel measurement.
So, if you hold it there, this is going to be negative 192. Since this thing is symmetrical, the
right side is going to be 192 as well. And for the top, we have negative I think this is going to be 320
and positive 320 because once again, this map is symmetrical.
Now, to get rid of the rulers, you simply want to drag them outside of the screen.
After that, inside of the player for the camera, the left side should be negative 192.
The right side should be 192. The top should be negative 320 and the bottom should be 320.
Top and bottom can be very easily confused, but remember, going up means you are decreasing the values.
But let's try all of this now and I can move in the different directions and we cannot go outside of
the window. And that is working pretty well and makes the game feel quite a bit nicer.
I guess while we're here, what you could also do inside of project and project settings in general,
you can look at display and window. In there, you can set the viewport width and height.
Usually, I set them to 1280 by 720, which is a much more standard resolution. Besides that, you can set
the mode. You can stretch the thing in different ways. You can work with landscape or portrait and do lots of
different things in here. Although, I'm not going to touch them too much.
If I run the thing again, now you can see our resolution is 1280 by 720. And obviously, you can also resize the
entire thing. It works totally fine. And with that, we have cameras. Our game is coming together quite nicely, but
there's one really important thing missing right now, physics or in other words, collisions.
That we're going to fix in this part. And for that, we have to talk about physics in Godot.
We want collisions and for that, Godot has dedicated nodes. There are three that basically do all of
the work. The first one is a static body 2D. This is a well, static physics object.
It doesn't move and it's basically for objects like houses, trees, bins, really whatever doesn't move and needs to be
collided with. Next up, we have a character body 2D. This is a physics object that can be moved via code.
Pretty much any kind of character is going to be a character body 2D. This could be the main player, this
could be enemies, this could also be a car, really anything that moves and doesn't have to be physically accurate
while moving. More or less, anything that moves and needs to collide with something is going to be a character
body 2D with some minor exception. The most important one is for rigid body 2Ds.
These are physics objects that can be moved via physics. These are going to be used for arrows, cannon bolts and things
like that. And just to be explicit, the difference between a rigid body 2D and a character body 2D is that a rigid body
2D gets some code in the beginning to determine the direction of the movement
and then everything else is covered by physics. Whereas a character body 2D is going to
continuously get directions from the code, meaning these objects can be updated constantly. Besides these three
nodes, there's one more node that you see very often and that is an area 2D. This one simply checks if a body is in
an area and that's all it does. On its own, it doesn't do any kind of physics, but it works very similar compared to
the others. As a consequence, they are usually grouped together. And before we get started, there's one more super
important thing and that is that physics objects are not moved via their position.
Instead, we're giving them a velocity and then Godot calculates the position. By that system, Godot can account for
physics right away. First of all, I want to create a static physics object. We can actually use the exercise object for
that. Now, at the moment, we have a node 2D at the root node. This I want to change.
For that, I want to right click on it and then change the type.
If you now look at all of the nodes, we can go to node 2D and in there, we have a collision object 2D.
If you expand that, we have an area 2D and we have physics body 2Ds, but we have a static body 2D, a character body
2D and a rigid body 2D. The nodes I just talked about. These are the main physics objects.
Although, they're not the only ones. If you expand static body 2D, you also have an animatable body 2D, which is
basically a static body 2D that can be moved a bit. And if you expand rigid body, we have
physical bone 2D, which is going to be useful for skeleton animation, but not something we need at the moment. So,
instead, I want to work with a static body 2D. Click on change
and now Godot is going to complain that this node has no shape. As a consequence, it cannot collide or
interact with anything. To fix that, we have to add another node. Either a collision shape 2D or a
collision polygon 2D. To get started, I want to add a collision shape 2D.
If we add that, Godot is going to give us another warning that a shape must be provided.
With the node selected, you want to look at the inspector and there we can add a shape. Loads of options in here. Choose
what you think is best. Usually, a rectangular shape 2D is working the best.
And I guess just to keep things simple, we can get rid of the box and of the second tree
and then change the shape of this thing so it fits the tree reasonably well. And by the way, if you hold command or alt,
then you can scale this thing while mirroring it around the axis. This works on X and Y.
And let's create the box like so. Cool. With that, we have one physics object. If you now look inside of the
game, we have a tree, basically. That being said, at the moment, we are
still not getting collisions and if I run the game, the tree just doesn't do anything.
For actual collisions, both the player and the tree need to be physics objects. At the moment, the player is simply a
graphic that can move around. No collision yet. Now, before we start working on the
player inside of the tree, in the script, you want to make sure that you are extending the right node.
At the moment, Node2D is incorrect because this is a static body 2D. Meaning, this should be static body 2D
as well. Without that, the code would start doing weird things.
Now, that being said, this exercise object doesn't need to do anything anymore. We can remove the
script entirely. And close the script, we can simply discard it.
That way, we simply have a tree. And I guess while we are here, we can rename it to tree.
And just to be consistent, inside of the scenes folder, this shouldn't be exercise object, this
should be tree. And the script, so exercise object.gd,
we can delete. Remove it. And then, the game is going to be a bit
cleaner. Now that we have that, we can start working on the player.
First of all, the player root node needs to change the type.
We want to have a character body 2D. Once again, Godot is going to complain that we have
no collision shape. This we can change by adding a collision shape 2D and then giving it a shape.
For the player, I want to go with a rectangular shape and then scale it so we are hitting most
of the player. You want to leave a bit of space at the top and at the bottom
because these parts should overlap with other objects. That way, you get a fake kind of 3D effect. Looks really nice.
You'll see later what I mean. Besides that, what's really important to do inside of the script, we want to
extend a character body 2D. And now that we have that, inside of the game,
I can move the player around and we still don't have collisions. That is because, at the moment, we are
changing the position of the player via the position property, which you can do. You wouldn't get an error, but you also
wouldn't get collisions. The way you are supposed to approach it is you are supposed to override the velocity,
which is a property of a character body 2D. This needs to be moved in a certain direction, which we are getting via
direction multiplied with the speed. Once we have that, you want to call move and slide.
That way, it applies this velocity and actually moves the character body 2D. As an outcome,
the player is going to move a lot slower. That we can fix by changing the speed back to 200. Might actually be a
bit too fast. But now, the important bit is we have a collision with the tree.
So, I cannot go further than this tree and that is working really, really well. That is all we needed for collisions.
For the player, we have a character body 2D, which we are moving via the velocity and move and slide.
Besides that, we have a tree, which is simply going to be a static object with a collision shape.
We also have an image, but that isn't actually necessary. At least for the collision. For the
actual game, this is important. So, with that, we have a pretty good system.
To finish up this part, let's do an exercise. I want you guys to restrict the player
to the map. Or in other words, use static bodies that ensure that the player is not able to leave the screen.
Pause the video now and see how far you get. Back inside of the game,
in the main game scene, I want to add a new child node, which is going to be a Node2D.
Let's call this one borders. To this node, I want to add a static body 2D
along with a collision shape 2D. For the shape, I want to add a rectangular shape.
That way, once again, we're getting the shape and the player is not able to move past that. So, here, we cannot go
further up. And this shape, I want to move to the right.
So, we are here on the right border of the map. And then, I want to scale this thing up
by a lot. So, the player cannot go further to the left and leave the screen. Let's try
this one now and the player is not able to leave. This we have to do for all of the four
sides. Although, you do have to be careful. If I simply duplicated this static body 2D
by clicking on duplicate or control D, then we would get another static body 2D that we can move to this point here and
that would work. I can now run the game and the player cannot go further to the right than this border. The issue is
if I wanted to change this collision shape, I would also change the other one.
If you duplicate a static body 2D with a collision shape, these collision shapes
are going to be linked, which sometimes can be useful, like in this case where we do want to have the
same shape. And this one should be a bit further here.
But for the top and bottom bit, this would not work. So, do be careful here. Instead, I want to add another static
body 2D with another collision shape. And for this collision shape, I want to
create a new rectangular shape that is going to be all the way at the top here.
And let me move it to the right position. Here and here is fine. Finally, I want to duplicate this shape
and then move it all the way down so we are covering the final part of the map. And now,
the player is not able to leave the screen in any direction.
Perfect. Next up, we're going to animate the player, which is going to make the
entire thing feel much more dynamic. In Godot, there are a lot of ways to animate things. The easiest one is to
use an animated sprite 2D, which is a sprite 2D that's, well, animated. Inside of this node, you can create animations
and then select them. That's pretty much it. Let's have a look. Back in Godot, I want to work
inside of the player and then get rid of the sprite 2D. Instead, I want to add an animated
sprite 2D. Which at the moment is going to give us a warning
that we have to add sprite frames to it. For that, you want to look at animation and then inside of sprite frames, create
new sprite frames. This right now doesn't really do anything, but if you click on it again,
then you're getting a sprite frames editor. In there, on the left side, you can see
the animation that you want to play. Let's say for now, I simply want to play the left walking animation for the
player. Then, inside of this main field, you can play the actual animation. This you can create in basically two
ways. Number one is you could simply direct graphics in here. For example, if I grab a couple of these random objects
and drag them in there, I can play the animation and then Godot is going to play one frame after
another. Which would work, but for our purposes, this isn't ideal. Let's undo all of
this. Instead, for the player, we have a player tile set. If I drag it in there,
you can see that we have all of the player frames in this kind of setup. And from this, we want to select
specific frames. Like for example, this graphic here. To work with that, inside of the sprite frames, you want to click
on this symbol where you can add frames from a sprite sheet. We want to go to graphics, player and
then select the tile set or the sprite sheet. And then, we can zoom in by holding control and using the mouse
wheel. Godot wants to separate this graphic into specific cells.
We have four horizontal cells, but only three vertical ones. The size lines up pretty well. So, this looks pretty good.
And now, we have to select the right kind of frames for the animation. At the moment, we want to get the left
animation, which is the left one. And if you click on it, you're getting a number. This would be frame zero,
then we have frame one and then frame two. These are the three frames that I want
to add to it. And now, we can play this animation.
Although, at the moment, it doesn't look great. This animation is actually supposed to
have this frame, then this frame, then this frame again and then the final frame.
To get that, you can simply have the first frame selected, then press control C and control V. And now we have
duplicated the frame. And to move this frame, you can either move it in the right position or use these arrow keys.
That way, we can move frames around quite easily. We are getting a much nicer walking
animation. You can also set the frame rate, if this thing is looping and if it's auto
playing. You can also set the frame duration, but I don't really care about any of those values.
Just make sure that you are looping the animation. Otherwise, it would simply stop on this frame. Also, for now, I
want to auto play this animation. And that way, if I run the game, we are getting a very basic animation.
That is looking pretty all right. And now to work with this, we want to use GDScript. And to keep things
organized, I'm going to create another function for the animation. No need for parameters.
I basically want to check if we have a direction, then we want to actually play the animation. If we don't have a
direction, then the player should be static, or in other words, we only want to get the first frame. That way it
looks like the player is idling. If we have a direction, I want to play the animation.
Which for now means we are simply not doing anything because we already have an animation, it's just not doing the
right thing. However, if we don't have a direction, so we are not moving, then I want to get
the animated sprite and update the frame property. This one should always be zero.
Now, by default, this value increases. So, we are selecting different frames. But if you set it to zero, we always
taking on the first frame, so this one here. That way, at the very least, we can play
the animation or not play the animation. Really important, don't forget to actually call this animation function.
Which I want to do before we are doing move and slide animation. Although, the actual position of
animation doesn't matter. Anyway, let's try this now. If I am not moving, the player is also
not animating. But if I start moving, then we are getting the walking animation.
And that is working pretty well. Next up, I want to get the right walking animation. For that, you could add
another animation in here. So, simply add another animation with right, and then select the player and the right
movement. So, these frames here. However, we don't actually have to do that. We
can approach this much more elegantly. So, let's get rid of the right animation.
Instead, all that we have to do, if the player is moving to the right, we want to flip this animated sprite
on the horizontal axis. Which we can actually do super easily. With the animated sprite selected, we
have offset, and there we can flip H. And if you hover it, the property is called flip {underscore} H. Inside of
GDScript, what we can do, if direction {dot} X is greater than zero, then the animated sprite 2D {dot}
flip H property should be true. Let's try that. If I go left, we're looking left, and if I go right, we are
looking to the right. Now, if I look left again, we're not going back to the left side. So, that's
not great, but at the very least, we are making progress. To fix this part, all we have to do is
add an else statement, and then copy all of this with the difference that flip H should
be false. Let's try this again. And now, we're getting the left animation and the right
animation, and that is working really well. Cool. Definitely progress.
Although, we are trying to do something very simple, and we are using four lines of code for it. This could be more
elegant. The way to approach that is to first get the animated sprite 2D,
and then flip H. The value we want to assign to it is going to be direction {dot} X being
greater than zero. And then we are done. This line is doing the same thing as these four lines.
And I think it's much easier to read as well. So, let me get rid of these four lines.
Try this again. And we are getting the same result. Doing this kind of stuff comes with
experience. If you work inside of an engine for long enough, then at some point, you find ways to make your code
more efficient. So, for now, if you work with more if statements, that's totally fine, but this would be more elegant and
much easier to read. With that covered, let's do another exercise. I want you to finish the animated
sprite. Which means you should be adding the logic for going up and down. So, in
other words, select the right animation depending on the player movement. Pause the video now and see how far you
get. Back inside of Godot, I want to work with the sprite frames and then add two
more animations for up and down. These, unfortunately, we cannot mirror.
I guess let's start with up. I want to click on this button again, select the player tile set, zoom in, and at the
moment, we are looking at up, which is this animation. Add the three frames,
and then, once again, I want to duplicate the first frame and place it between these two walking frames. All I
have to do is press Ctrl C and Ctrl V, and then drag this frame in the right position.
Just to double-check, let's play the animation, and that looks pretty all right. Cool.
Besides that, for down, we want to do the same thing. So, grid, player, get the down walking animation, add the
three frames, duplicate the first one, and drag the frame in the right position.
Then we are getting the down walking animation. Perfect. With that, we have the right animations
that we can work with. We just have to figure out when to play which using GDScript. I first checked if
direction {dot} X is different from zero. If that is the case, I want to play
animated sprite 2D and update the animation. This one should be left. We are still
flipping the sprite on the horizontal axis. So, if the player is going to the right, then left is automatically going
to become right. Besides that, else, if we are only going up and down, then I want to get the animated sprite
2D and update the animation again. Let's say for now, this one could be up.
Let's try this one. I can go left, I can go right, and I can go up.
Although, I cannot go down, at least not with the right animation. But we are making progress.
Now, at this point, you could approach this in two ways. You could either check if direction {dot} Y
is smaller than zero, and if that is the case, we want to do all of this. If that is not the case, let me duplicate all of
this. Direction {dot} Y is greater than zero,
then the animation should be down. Let's try this one now. I can go left, right, up, and down.
This, once again, is working, but we are also doing something very simple over four lines of code.
A better way of approaching this would be to get the animated sprite, then the animation,
and assign it up if direction {dot} Y is smaller than zero, and if it is not
the case, else, we want to assign the down animation. That way, we can get rid of all of this,
and we would have the same result. Much more elegant. Let's try all of that, and now I can go
in all of the four directions, and the player is animating or static when we are not moving.
At this point, we have basically finished the player. Which means we can start working on the cars.
For those, we have to do a couple of things. Number one, cars should spawn
automatically in a specific interval. For that, we are going to create a timer in just a
second. On top of that, they should start in a set position and move in a certain
direction. There are a couple of things that we have to go through. So, let's go through
it step by step. Number one, we have to learn about signals.
These are a vital component of Godot. And basically, any node can emit a signal. For example, a node can trigger
when there's a collision or when a timer triggers. Every node has its own signals,
depending on what they are supposed to be doing. This is a super important concept. Let's have a look at it. Back
inside of Godot, let's say I want to look at the player, specifically the root node, so the character body 2D.
On the right, we have the inspector, and there we can also see the node. This one contains signals and groups.
The thing that matters for us are the signals. In here, you can check all of the signals that this node can emit. For
a character body 2D, there aren't many because this node, in general, is just supposed to collide with things and not
do that much more. So, we can check some general things, but they're not really that useful.
Instead, a much more interesting node that's added to the main game is going to be a timer.
This is, well, a timer. If you look at the inspector, you can get a wait time, if this is supposed to trigger once or
multiple times, if it's auto starting, and that's kind of all you need. Let's say I want this timer to auto start and
then run for 4 seconds. This right now is not going to do anything. If I run the scene, at some
point the timer is going to trigger, but it doesn't really do anything once it triggers. So, this is no good.
But, what we can do, inside of node, we have the timeout signal. This one is going to be triggered when
this timer times out. The way you're going to use it is you double click on it, and then you have to
connect it to a script. At the moment, the only node that we have with a script inside of the scene is the player.
So, what I want to do is to add a script to the game scene. Add script, the default CR fine, create.
And now, with the timer selected again, double click on timeout again, and then add the signal to the game
script. Connect. And then, inside of this script, we can run a function. Let's say I want to print
timer has triggered. If I now run the entire thing again, every 4 seconds we should be getting
timer has triggered. There we go. This should happen multiple times. There we go. This looks pretty good.
If we never one shot, this would only happen once. This system I want you to practice right away as well.
So, I want you to create an area 2D node. This should be at the top of the map,
and when the player enters, it should print player entered. An area 2D node works like the other
physics objects. Meaning you have the node, and then you need a collision shape.
After that, look at the signals and see what you can work with. Pause the video now and see how far you
get. I want to add an area 2D node. Once again, Godot is giving us a warning
that this has no shape. This we can fix by adding a collision shape 2D or collision polygon 2D. In
your case, you could just add a collision shape 2D with a rectangle, it would be totally fine.
But, just to illustrate what you can do with a collision polygon, let me add this one. So, create, and now,
nothing has happened. But, if you look at the top, we can create a bunch of points with this thing is selected. Once
you have that, you can simply draw a couple of points vaguely at the top of the screen,
like so, and to close the shape, you want to click on the origin point again. Now, we have another shape for this area
2D. For the area 2D, the inspector doesn't matter that much, but if you look at the signals, we are getting a
ton of stuff to work with. Most importantly, we have body entered. This one checks if a physical body has
entered this area. Which is what we are looking for, so double click on it and connect it to the
game script. On area 2D body entered would be a decent name.
Although what you could also do is rename this area 2D to finish area 2D, and then the name here would also
change. It's usually a good idea to have descriptive names in here. Since our game is going to be quite
small, this doesn't matter so much, but for more complex game, you really really want to have precise names. Anyway,
click on connect. And now, we have another function that is going to be called whenever a
physical body enters this area 2D. Once that happens, we can print the body that we are getting, and we can print
as entered. Let's run the entire thing. And if I move up, at some point we are
getting, inside of output, the player character and has entered. So, this function here did trigger. So, with
that, we have signals. Those are incredibly useful inside of Godot. They make any kind of node much more
interactive and give you a ton of options. Before we finish, there's one more thing that I want to do, and that
is to organize the game scene a bit better. Inside of game, I want to add another
child node, which is going to be a plain node, which I want to rename to timer, and then add the timer that we have just
created to it. And that way, I can also remove timer two. Godot added the two because you cannot have the same name
for two nodes. The timer that we have created should be called the car timer. And for now,
I want to disconnect this signal, which you can do by right clicking on it and then disconnect.
Also, inside of the script, this timer function should disappear. We're going to replace it in just a
second. For now, I just want to have a clean start. On top of that,
the finish area 2D can go inside of borders. I think they kind of work together.
And finally, this exercise object should just be a tree. That's the better name for it.
On top of that, the sprite 2D is simply going to be the BG or the background. That way, all of this feels much more
organized. This is something you are going to learn really, really fast. A scene tree can become cluttered
incredibly fast, and you want to keep it as organized as possible. Now that we can create a working timer, we can start
working on spawning the cars. For that, we have to go through a couple of steps. And along the way, we are
going to learn how to spawn scenes via code. In other words, we want to create
instances of a car whenever a timer triggers. For that, number one, we have to create
a basic car scene. This is going to happen in the normal way. We are just going to create a new scene with a
sprite and an area 2D. After that, we're going to store the car scene in
the main game. Next up, when the timer triggers, we are going to
create one instance of that car scene. And finally, we can attach the car scene to the
current game scene. That way, we can actually see it. First of all, inside of Godot, I want to
create a car scene. Add a new scene, and the root node is going to be an area 2D. This area 2D, by
the way, I have used because there are no actual collisions between the player and the car. Whenever there's any kind
of collision between the two, the game is ending right away. So, an area 2D here is totally fine.
To this area 2D, I want to add a sprite 2D so we can see something. The graphics for that are going to come
from cars. Select one of them and then assign it to the texture of the sprite 2D.
Then we are getting one car. After that, for the area 2D, I want to add a collision shape 2D.
Which for this one can simply be a rectangle shape. Make sure you cover the whole car, like so and so, I guess, kind
of like this. Doesn't have to be too precise for our purposes, but obviously for real game,
do spend some time on it. All of this I want to save as car.tscn. Click on save, and now we have one car.
That actually should be renamed to car. And then, inside of scenes, I should have done that before, it shouldn't be
area2d.tscn, it should be renamed to car.tscn. Much better.
Now, we have a car scene. This I want to spawn inside of Godot whenever this car timer triggers.
Speaking of which, for this one, wait time should be 1 second for now, and it should auto start.
After that, for node, I want to go to timeout once again, and then connect on car timeout timer to the game script.
And now we get on car timer timeout. Whenever this thing triggers, we want to create one instance of the car scene and
attach it to the game. For that, we already have a car scene. So, next up, we have to store the car
scene inside of the game scene, which we do all the way at the top. I want to create a variable car_scene.
The data type for this one is always going to be a packed scene. You are getting it by preloading
a car scene. Godot is now giving you all of the options of data that you could preload.
In my case, I want to get scenes and car.tscn. That way, let me add just a bit more
space. We have the car scene ready inside of the game scene, which means we have
covered the second part. Next up, we have to create one instance of this car scene.
Which is going to happen every time the timer triggers. To create one instance of the car scene,
we have to call instantiate. That way, we are creating an instance of it, which we want to store in another
variable. Let's call it car. That way, we have one instance, so we have covered the third step. Finally, to
actually see the car, we have to attach it to the current scene. This happens via add child.
I want to add the car, and then I can run the game, and we should be seeing the car
somewhere around the origin point. So, there we are getting the car. On top of that,
with the game still running, you can look at the scene tree, and there we have remote,
where you can see the nodes in real time as the game is running. And there you can see Godot keeps on adding area 2D to
it every time the timer triggers. Besides that, you can see the nodes that we have added ourselves.
So, this is a real-time view of the game. And well, you can see quite well that we
are adding more and more cars. Inside of the game, you can't see them because they're on the same position, but that
we can work on. Inside of the car scene, I want to add a script to it. The
defaults here are fine as they are. And then, for the car, I want to add var direction,
which is going to be a vector two that at the moment points to the left. Besides that, I want to have var speed,
which is going to be 100. After that, I want to call func underscore process,
in which we are updating the position of this area 2D node. So, once again, inside of transform, we
can update the position of this node. Like we have done in the beginning of this project, I want to get the
direction multiplied with the speed. And you might be wondering now, why do I use process for the car, while for the
player I used physics process? And well, for the player, we have collisions, so we want to include
physics. Whereas for the car, we don't actually have collisions. Once again, as soon as
there's a collision between the player and the car, the game ends right away. So, we don't actually have collisions,
we are simply checking for an overlap. In practice, you could also use physics process. It doesn't really matter for
our purposes. But anyway, with that, we should have the car movement, although I think 100
is a bit too much. Let's go with two. Let's try out of this now, and there should be a car going to the left. And
that is looking pretty good. Perfect. Once again, if you look at remote in the
game, you can see we are adding more and more car scenes to the game. That being said,
there is a bit of a problem. Number one, adding the cars to the game scene is going to clutter the scene tree a lot,
which is going to make it difficult to work with. So, what we can do at this point is add another node 2D
that we can call objects. All of the objects in the game are going to be inside of this node 2D, including
the player and the tree. Add them in there, and then, inside of the script,
I want to add the cars to this objects as well. You can simply drag and drop objects in
the right position. Don't forget the dot. And now we're adding the car to the
objects node. If I run the game inside of remote, all of the cars are going to be inside
of objects. If you minimize it, this looks a lot cleaner. Once again, not something you have to
do, but it's going to make your life quite a bit easier. Besides that, it's actually not a great idea to spawn cars
indefinitely. So, at the moment, we keep on adding more and more cars, and this goes on forever. It never
stops, which isn't great for performance, because once a car leaves the screen, it
shouldn't be there anymore. You can't see it, you can't interact with it, it should just disappear.
And think of a more complex game. The more objects you have, the slower the game is going to run. So, you want
to keep the amount of objects as low as possible, which is generally a good idea.
In other words, for the car, as soon as the car leaves the screen, we want to destroy it.
That you can do by adding another node, which is called a visibility screen notifier 2D. This can check if
node is entering or exiting the screen. It should roughly fit the texture. That looks all right. It doesn't have to be
too precise. And then, inside of the signals, you can check if the screen was entered
or exited. We care about exited. If I connect this to the car scene, we want to destroy the instance of the
car scene as soon as it leaves the screen, or when this function is triggered.
This in Godot, you are doing via queue free. This destroys the current instance of
the node. Or in other words, if I run the game again and go to remote, inside of objects, we only ever have
maybe two cars. As soon as the car leaves the screen, we are destroying it. So, we only ever have
that many cars. And inside of the game, you can see we only have two cars on the screen, maybe three cars sometimes.
That's why we are making sure that we only ever have so many cars on the screen, which is going to be really good
for performance. Now, obviously, for our game, since it's really simple, it doesn't really matter,
but it's generally good practice. Besides that, I want to set start positions for the
cars. At the moment, the car always starts in the origin point, which obviously isn't
great. To fix that, I want to add another node 2D to the
scene tree that I called car start positions.
In here, we want to store a couple of nodes that have the start position for the car.
For that, you could use a node 2D. It would work, but Godot also has a marker 2D that works a little bit
better. So, with this marker 2D, if you move it,
you can see that we have the origin point along with this cross around it. So, it's a little bit easier to see.
But aside of that, we only really care about the position of this node, and this we are getting by a transform and
position. These marker 2Ds, I want to move all of the car lane start positions.
Left or right doesn't matter so much. You can alternate, or you can stay on one side, whatever you think is best.
So, let's do this again, like so and like so. And then, we have a start position for
every lane. Once we have that, as soon as we have a new car, we want to update the position of that car. For
that, first of all, I want to get a random marker from the car start positions.
Let's store that in a new variable, position marker. The way you're getting that is first of
all, you want to get the car start positions, and then get children.
This is going to return an array with all of the child nodes. On an array, you can call the method
pick random. That way, you're picking one random child of car start positions.
And once we have that, we can get the current car and update the position
of that car. Now, right now, you don't get position as a suggestion.
That is because Godot doesn't know what kind of node this car is that you have just instantiated.
If you want all of that, you can add S, and then the type of node that you want to create. So, in my case, an area 2D.
That way, if you have car, you can get all of the suggestions again, which can be super helpful.
And generally, being really picky about the right data type is a good idea. It can make your
life much easier. Anyway, for the car position, I want to have the position marker, and don't
forget, position marker is just a node. On this, we want to have the position as well.
If you want to be super precise here, this could be S marker 2D. If I now run all of this, we should be
seeing a car coming from the right. And that is working pretty well. If you go further down,
there are also some cars that can also disappear, and that looks pretty good. The issue now is on the left side, we
can't see any of the cars, simply because if a car starts here, for example, it only goes left.
Not great for our purposes. But that we can work on. Inside of the script for the car,
once the car is ready, or in other words, func underscore ready, we can simply check if zero.
If that is the case, we know we are on the left side. If that is the case, direction.x
should be one. That way, we're turning the vector left to a vector right.
Although, if I run the game now, this is not going to work. We are still getting the cars on the right side,
but we have no cars coming from the left side. The issue is that this ready function
only runs before we are updating the position. Or in other words,
the ready function, this one here, is called when you're adding a node to a scene,
which currently happens on this line when we are calling add child. Which at the moment is a bit of a
problem because we are adding the car here and the current position of the car is zero and zero. And then we are
running this line here, which is never going to trigger because the position is zero and zero.
Only after we are doing all of that, we are setting the position of the car. As a consequence, this if statement is
never going to trigger. I can actually demonstrate. I want to print
car direction. Let's run it and this function is never going to run.
So, this doesn't do anything. Fixing that, fortunately, is very simple.
We want to update the position of the car before we are adding it as a child to
the scene, which is totally fine to do. When we are calling this ready function, the car already has the right position.
And that way we should be getting cars coming from the left as well. So, there we get car
direction. I just have to find it. There we have the car. This can be kind of annoying in Godot.
Understanding when these inbuilt functions are being called sometimes can be a little bit tricky. Always remember,
ready is called when you adding the node to the scene tree. And while we are here,
I don't want to print something when it happens. Instead, I want to get the Sprite 2D and flip H
should be activated. That way the car is pointing in the right direction.
And with that, we should be having cars that go reasonably well in both directions.
At some point there should be one coming from the right as well. Let's look up here. That definitely works.
This we can refine, but I think for now this is working reasonably well. Now, before we continue, there's one
important topic that we do have to cover that does get a bit more technical. Frame rates and delta time.
So far, we did not care about the frame rate at all. The game simply worked and that's totally fine. However, in some
instances, this can be an issue. That is because the frame rate is affecting the movement of objects.
Not always, but in some circumstances and that we have to talk about. And while we are here, inside of Godot
for the car, when we are calling process, we are getting delta. Same for the player
inside of physics process, there we also have a delta. And so far, I just didn't talk about it, but it's a really
important parameter. But let's go for it step by step. Now, the main issue is that a frame rate
determined movement can be inconsistent. Here's a table with the same movement but different frame rates.
The actual speed is the first column where we always want to move at 10 pixels per frame.
Or in other words, inside of our game, for the car for example, we are moving the car by a certain direction
multiplied with a speed. In our case, for example, this would be a speed of two on the horizontal axis.
This change in position is applied on every single frame. So, effectively, we are moving at pixels per frame.
Besides that, we have the amount of frames per second. This number is going to vary on the
computer. If you have a really slow one, you might only get 10 frames per second. If you have a really good computer, you
might get 500 or more frames per second. This also depends on what happens inside of the game. If you have a lot of
objects, the game is going to be more difficult to run. Generally, you want to have 30 or more frames, that way your
game is going to feel smooth. But for this example, it doesn't really matter what the number is. What does matter is
the final column where we get the pixel movement per second. This is simply the multiplication of
these two numbers. For example, if we are moving at 10 pixels per frame and we have 10 frames
per second, we are moving at 100 pixels per second. Which on its own would be totally fine.
But the issue is, depending on different frame rates, we are getting a different speed because we are applying a change
in position multiple times per second. And this number varies. If we apply the change in position 10 times a second or
500 times a second, it's obviously going to be different. Which for our game is going to be a
problem because, well, you can see it here. If our pixel movement is 100 pixels per second or 5,000 pixels per
second, the game is going to feel significantly different. Or in other words, the movement speed of your game
will change depending on the computer. And this is really, really not good. Just imagine any game where the movement
speed could either be 100 or 5,000. No game would work like that. And as a consequence, we have to account
for it. Which we are doing via delta time. All that this concept describes is the
difference between the current frame and the previous frame. Or in other words, it tells you how long it took your
computer to render the current frame. Doesn't sound that important, but it's actually super useful
because imagine you have a game that runs at 30 frames per second, then delta time is simply 1 / 30 or 33
milliseconds. If you have different frame rates, then you get different numbers, obviously.
The specific number here doesn't actually matter. What matters is that the higher the frame rate becomes, the
smaller delta time will be. Which is incredibly useful because let's look at the table again with delta time.
The first three columns are what you have seen before. The only addition now is that we have delta time.
For example, if our frames per second are 10, then delta time is 1 / 10 or 0.1.
If our frame rate is 30, then delta time is going to be 1 over 30 or 33 milliseconds. All of that is useful
because delta time and the frames per second effectively cancel each other out. Imagine this formula here written
in a slightly different way where we have 10 pixels per frame from here multiplied
with the frame rate, in this case that's 30 frames per second, this number, and this we are multiplying with delta
time. This number here, 1 / 30 or 1 over 30. The end result has to be 10. For the
simple reason that 30 and 1 / 30 are simply going to be 1. The only thing that's left is the 10
that we are getting at the end. And this works with all of these numbers. So, if we have 60,
we would have 60 multiplied with 1 over 60, 500 multiplied with 1 over 500 and so on.
Frames per second and delta time cancel each other out. The only thing left are the pixels per frame. And that is really
all we want. That way it doesn't matter what the frame rate is, you always getting
constant movement. And this you should use whenever you change the position or rotation of any
node. The one place where you don't have to use it is with physics bodies because
for those Godot automatically applies delta time. And finally, let's do all of this in
Godot. That way all of this can also be a lot more practical.
We want to work inside of the car where at the moment we are updating the position
by getting the direction and multiplying it with the speed. Which on its own works totally fine. If
I run the game, the cars are going to move. Let me find one. There we go. We have movement.
However, this movement depends on the frame rate. In other words, if I go to project, project settings,
and then toggle advanced settings, then under run, we have a maximum frame rate, which right now is set to zero,
which means we have no maximum frame rate. Godot will try to run the game as fast as possible.
Let's say I want to limit the frame rate to 12. That way we get at least a little bit of movement.
If I now run the game, it's going to feel really rough, but the important thing is the cars are moving
very, very slowly. If we increase the number to 30, then they should be moving a lot faster.
And there we go. Now the taxis are quite a bit faster. And this is a problem.
The frame rate shouldn't affect the movement inside of the game. Let's set it to zero for now. That way
Godot will try to run the game as fast as possible. Now, to actually fix this, all you have
to do is multiply this value with delta time and then you are done. That's all you have to do.
So, if I run the game now, the cars are going to move quite a bit slower because delta time is a very low number. So,
there you can see the cars are not fast at all. Simply change the speed to a larger
number, let's say 200. And now the cars are a good bit too fast. Let's
go with 100 here. And then we have a car that is moving at a much nicer pace.
Really importantly now, if I go back to limit the frame rate to 12,
the game is going to be much choppier, but the speed of the car itself is not going to change. And that's the
important part. That is the point of delta time. It makes sure that you can change the
position independent of the frame rate. A super important concept that you have to use whenever you're changing the
position or the rotation or any of these basic properties of a sprite to default example to make sure that the frame rate
doesn't affect the speed of it. However, if you have a physics object that you move by the velocity and move
and slide, you don't have to do that. You do a place delta time scene automatically. Next up, we are going to
work on the player car collisions. Or in other words, we have to add the signal to the car that is going to be
emitted whenever there's a collision between the two. However, this has to happen inside of
the game scene because there is all of the logic for the actual game. Or in other words, we have to connect
the signal once the car is spawned via GDScript. Here we are back in the game and the issue we have at the moment is
that we want to check if the player overlaps with this car and for that we can use a signal.
Body entered would be best. The problem is we can connect this to the car, but then we have a script
inside of the car, so in here. I guess that would do something, but it wouldn't really be that helpful. All of the logic
for the actual game is inside of game.gd. So in here, I want to run the script for the collisions.
Fortunately, what we can do once the car has spawned, we can connect the signal via GDScript. All you need is the car
that we have created. Really important, we want the car instance, not the car scene. On that thing, we can run a
method called connect. Then we need the name of the signal, which in our case is called body entered. Simply type the
string of it, body_entered. The second argument is then the function that you want to call,
which in my case is going to be go to title because that's what we later on want to do once there is a collision.
Also, really important, I want to pass this function as an argument in here, but I do not want to call it, meaning
there shouldn't be parentheses afterwards. We only want to have the word go to title without anything else.
After that, I want to create this function. So funk go to
title. No need for parameters and now, once that is the case, I want to print player
car collision. And that should be it. Let's try. Inside of the game,
I am getting a lot of errors. You can see in the bottom, Godot is really really unhappy with us. Under
errors, we are getting an issue and let's read it out. Godot has an error calling from signal
body entered to callable go to title, the one that we have just created here. And the issue is the method expected
zero arguments, but was called with one. Understanding these error messages is incredibly important, so let's go
through it. Go to title expected zero arguments because there's no parameter. However,
because of connect and body entered, we are calling this function with one argument. This number here at the end.
Effectively, when Godot is calling this function, it passes an argument into it, but inside of the function, we don't
have a parameter and as a consequence, we are getting an error message. This happened because when you look at
the signal body entered, we are getting the body as an argument passed into it and this is what Godot
wants to do. To fix that, all you have to do is add one parameter, which would be the body. Although in our case, we
don't really care about it. But just to demonstrate what is happening, let's print the body that we are getting.
And if I now rerun the entire thing, we are getting a whole bunch of collisions actually.
Let's have a look at the output. The first collision that we are getting is a static body 2D collision.
Then we have another static body collision, another one, and then we have the actual player collision.
We are going to work on that in just a second, but for now, the important thing that you have to understand is if you
want to connect a signal via GDScript, you get the node or the scene you want to connect, then you call connect with
the signal name and then the function you want to call. And always make sure that you are counting for all of the
arguments that Godot is passing into this function. And once you have that, you can connect signals via GDScript.
Now, besides that, we were expecting the player body and player car collision, simply the string.
However, besides that, we got a whole bunch of additional collisions. What happened here?
When we are looking at body entered for the area 2D, it looks at any body. This would include these borders around
the screen. Static bodies are still bodies. So whenever a car is being spawned, it will collide with this
border. A car could also collide with the tree that we have created and it could also
collide with any other object that we might create, which at the moment isn't really the
desired behavior. So how can we fix that? For that, we have collision layers.
Effectively, every physics body has a layer and a mask. A mask is determining what physics object a node can see.
And a layer determines what other physics objects can see the node. That way, for every single physics object,
you can determine which objects can see each other. So with that, back in Godot. If you look
at any physics object, like for example the player, in the inspector under collision, we have layer and mask. All
of these are just numbers and this determines what layer and what mask the player is on. If you have all of these
numbers at the moment, you only get layer one, but what you can do under project, project settings, and if you
scroll down a bit, somewhere we have 2D physics. And let me disable advanced settings. We don't need it anymore.
In here, you can name all of the various layers. For example, we could have layer one being terrain,
layer two being the player, layer three could be the cars and layer four could be the walls.
And by walls, I mean these walls around the screen. And to get started with the player, the player should be on layer
two, which is only for the player. So this determines what other objects
can see the player. And on the flip side, for the mask, the player should be able to see the
terrain. He should not be able to see itself. The player should be able to see the cars
and the player should see the walls. Then for the tree, for collision,
the tree should be on the terrain layer and for mask, we can disable everything simply because the tree doesn't have to
see anything else. And just to demonstrate, if I now run the game and go to the tree, we are still getting a
collision and that is working pretty well. However, once I put the tree on a
different layer, let's say layer five that we are not using, then the player can walk right through
it. There's no collision anymore. The only layers that the player can see are
determined by the mask 1, 3, and 4. If the tree is not on any of them, the player is going to ignore it entirely.
All of this you should really practice. For that, set up the layers and the masks for the cars and the walls.
Really important, the cars should not see the walls or each other, but they should see the player. Pause the video
now and see how far you get. I want to start working with the car, specifically the area 2D node.
For collision, the layer should not be on terrain, it should be on cars. That way the player can't see it. Next
up, for the mask, the car should only be able to see the player itself and nothing else.
That way a car should already not see the walls around the screen anymore. Let's try this and now we should only
get a collision between the car and the player and that looks pretty good. Finally then, for these static bodies
around the screen, you could leave them on the terrain layer. It would kind of be possible, but
I would rather have this organized, so they should be on walls and they should not see anything else. This I want to do
for all of them, so this should be only four. Same for this one.
And same for the final wall, only on layer four. That way the player should still see them. There we go. This works.
But the cars are going to ignore it entirely in two different ways actually. With that system, we can control a lot
better what is colliding with each other. Finally, all the way at the top, we have
the finish area 2D. This one should not be on any layer. Whatever words, no other physics node
should be able to see it. However, it itself should be able to see the player.
That way, if I run the game again, the player should still be getting up here and that works, but no other physics
object can interact with it. At this point, we have covered all of the basic concepts to create a level. If you added
lots more stuff to it, you would have a pretty decent basic game. And this is what we are going to do in
this part. However, before we get to it, there's one important concept that I still have to cover.
At the moment, the player can either be behind an object or in front of it. But, this system is static. The player
couldn't dynamically change the position. Back inside of Godot,
the position of the player relative to the tree, these two objects, is determined by the node tree.
So, at the moment, the player comes first, and then we have the tree. And as a consequence, if I move the
player around, the player is always behind the tree. Inside of the game,
you can see that the player right now is in the right position, behind the tree. But, if we go around,
now the player is, well, still behind the tree, but the player should be in front of the tree.
That we have to fix. The system for that is called Y sorting. All that it does is it decides which
object is going to be on top depending on their Y position. Just imagine that this line up here is Y
being zero. The player position in this case is, let's say, 10 pixels, and for this
player it's going to be 20 pixels. While the car is always going to be on pixel position 15. Same for this one. If
all that Y sorting is doing is it compares these two numbers. Whichever has the higher Y number is
going to be drawn on top. That way, if the car is further down, it's going to be on top of the player.
If the player is further down, it's going to be on top of the car. And that's literally it. It's a really
simple concept, and you can apply it to Godot super easily. All you have to do is grab the parent node, objects in this
case, and then go to ordering inside of the inspector. There we have Y sort enabled. This
should be enabled, and then all of this is going to work. So, the player can be behind the tree,
like so, and the player can be in front of the tree, like so. And that is feeling a lot more
realistic. And by the way, it's really important for this system that the collision
shapes for the player and the tree don't cover the entire height of the object.
For the tree, we have a bit of space at the top and the bottom, and same for the player. We have a bit of stuff below and
above the player. That way, these two can overlap a bit, which makes the game feel much more
three-dimensional. And well, with that, we have the basic system in place. Now we can add lots of
objects. To place all of these elements, you want to organize your project so the entire
thing is reasonably streamlined. Let's do some examples. We already have one object, the tree,
where we have a static body 2D, a sprite, and a collision shape. We could, for example, copy this tree,
and then place it here and here and here. Run the game.
We would have more trees. Pretty straightforward. If you wanted other objects,
all you would need to do is create another static body 2D node. Let's say for this one, I want to create
a box. For which, I want to go to graphics, and then inside of objects, we have a couple
of boxes. I want to choose one of those. To add it to the scene, I want to add a sprite 2D, and then box.png is going to
be the texture. After that, zoom in quite a bit, add the collision shape 2D.
For this one, we definitely want to have a rectangle that we then want to scale down quite a
bit to something like this. Afterwards, save the entire thing inside of scenes, box.tscn,
and then we have a box. That once again, we want to attach to objects,
which means in there, box.tscn, and then in the origin point, we have a box.
And by the way, if you try to move it, and you move something else, like for example, right now the car's start
positions, you can avoid that by having the box selected inside of the scene tree, and
then hold command or alt. That way, you're only moving the node that you have selected inside of the scene tree.
Can sometimes be super handy. But anyway, once we have that, we have a box, and then inside of the game,
we can collide with it. That being said though, for something as simple as a box, this is kind of
overkill, because a box is, well, really, really simple. We don't need a separate scene for that.
What we could also do, inside of objects, is simply create another static body 2D
that we could rename to, let's say, bench. To this bench, we can add a sprite 2D
right away. And for that, I want to use bench.png for the texture.
Then we have a bench, and after that, we can add a collision shape 2D with a rectangular shape that we then
want to scale like so and so. And then we have another object that we
can work with, and we didn't have to create another scene. Although, you do want to be careful.
Moving this bench around right now can be kind of annoying. There's a good chance that you accidentally only drag
the collision shape or only the sprite 2D, which would, well, cause a ton of
problems. So, this I don't want to do. To avoid that, you want to click on this symbol.
If you activate it, you're getting this symbol next to the node. That means you can only move the parent node.
So now, we're always moving the entire bench as one object. Super handy. That way, we can move it,
let's say, here. And once again, inside of the game, we are getting another object that we
can collide with. There are lots of useful icons at the top. The other one that's super useful is
locking it. That way, this node cannot be worked with anymore,
which, for example, we really want to do for the background, because this one really isn't supposed
to move. Same with the borders, actually, and with the car's start positions.
None of those should ever really move. Although, the bench shouldn't be locked, but it should be grouped. This would be
another way to create an object inside of a scene. Once you have that, you can simply
duplicate this bench, and then you can create as many benches as you like. Which is also a way to approach it.
Although, if you want to create a lot of objects, this might still not be ideal. For that, we can approach these kind of
objects in a different way. Let me add another node 2D,
where I want to have a whole bunch of, let's just call it stuff. Doesn't really matter what you call it.
To this node, I want to add lots of random sprites. I can simply drag them in there, like
so. There we have a bin. We can put a box here, a box there. A third box here.
Let's say we can put a car in this position, and a light here-ish. The specific shape does not matter. I
just want to have a whole bunch of sprites inside of the stuff node. And make sure
that for this stuff node, you have ordering Y sort enabled. Now we have a whole bunch of objects.
The problem is, inside of the game, we have no collisions whatsoever. For that, we will need a static body 2D.
Now, what you can do to a static body 2D is add multiple collision shapes, which means I can add a collision shape
2D with a rectangle for now, and let's say this one is just for the car.
So, I can resize it to something like this. And then, to the same static body 2D, I
can add another collision shape or collision polygon. Let's say collision polygon, and then I
can draw a rough shape for these objects. So, something vaguely here, here, here,
here. Here. Here, and nearly done.
Like so. And to refine this a bit, you can have this symbol selected, and then move
these points. There we go. Now we have a collision shape, and inside of the game,
if I go to this position, we have a collision with the car. That works, and with these boxes as
well. And that is working pretty well. The same thing we can then do for these
objects and for this object, and you simply go through it step by step. That way, you can very easily add lots of
objects with one collision shape, which I think is the best way to approach it when you have a lot of stuff to add to a
scene. With that part covered, we can do an exercise.
I want you to place a lot of elements, so that by the end of it, you have a proper-looking level.
Place a whole bunch of static bodies and Sprite 2Ds. How you're doing this is entirely up to
you. You can create separate scenes or a few nodes inside of the game scene. It really doesn't matter for our game. Just
choose what you think is best. Pause the video now and see how you get. I went ahead and created a whole bunch
of objects. Most of those I placed inside of the stuff node where we now have a ton of
sprites and on top of that somewhere in there is a static body 2D. Which holds a whole bunch of collision
shapes. Inside of the game, all we see though is that we have a ton
of collisions with different objects. Let's go here, here. Always have collisions and that is
working pretty well. Now obviously to create a level, you have to have some patience and place a
ton of elements. Which sometimes can simply take a bit of time. Especially doing all of the collision
shapes manually can be quite annoying. And later on, we are going to learn ways to make this more efficient. But for
now, this is the easiest way to create a level. On top of that, for this bit up here, we
don't actually need collision shapes because once the player gets to this bit, the game should be over.
I guess one thing that we can do to finish up this part is at the moment, we don't really get that many cars,
which does look a bit weird. To make that work much better, let me minimize borders and objects and then
look at the car timer. At the moment, we're creating one car every 1 second. If I change this to 0.1,
then we're getting a lot more cars already. So now, this feels a lot more like a
game. This number you can tweak. I think I went with 0.15 for the actual project.
But obviously just test this and see what feels good for your purposes. Also, while looking at this, I think we
should vary the cars just a bit more. At the moment, our car is always going to be a taxi.
That being said, inside of cars, we have three different kinds of cars. And those we want to select randomly.
For that, we have to work inside of car.gd. First of all, we have to load these
three cars into memory. That we do first of all by creating a variable.
Let's call it colors. Inside of this variable, I want to store an array
that stores the green, red, and yellow car. To load them, we want to preload
and then the name of the file that we want to preload. Which in my case is graphics, cars, and green.png first of
all. Besides that, and let me write this over multiple lines so it's more readable. I want to duplicate this line
by pressing control, shift, and D. Besides the green car, I want to have the red car and I want to have the
yellow car. That way we can use these graphics inside of the game right away.
And effectively what we want to do once the scene is ready, I want to get the Sprite 2D.
The Sprite 2D here and then update the texture. Which I can simply grab via the texture
and then assign one of the images that we are storing inside of this colors array.
Now to pick a random value from it, all we need is pick random. That way we are picking one item at random.
If I now run the game, we are getting very unlucky. But now, this looks much
better. We have three different cars and that makes the
game feel significantly more interesting. All right. At this point, we have a
basic game where a player can move around. We have static obstacles, we have moving cars,
and we can accept player input. However, what we don't have is a way to communicate with the player directly via
text. That we're going to work on now. Where we are creating a timer on top of the window while the game is running and
we're going to create a title screen. So let's talk about creating layouts. Up to this point, we have placed nodes
using absolute positioning. Which is a fancy way of saying that every node get an XY position that is
independent from the window. That means back inside of Godot, let me create a new scene, which is just going to be a
2D scene. Inside of this 2D scene, we have the origin point up here. This is position
zero and zero. If I now place any kind of object via a Sprite 2D,
then this object is going to get a position that we can see inside of transform.
We can have some cleaner numbers. Let's say 100 pixels and 120 pixels. This number tells us the XY distance
from the origin point. This number does not care about the window size, the blue frame we have
right here. In other words, if I save this scene, let's say inside of the main folder
right now, and run it, we have the car here and if I resize the window, the car doesn't really care.
It's always in the same position relative to this top left point. Which is fine for 2D nodes. They are supposed
to work like that. But layouts work differently. They are placed using relative
positions. Which in effect means that instead of giving them an XY
position, we are placing them 10% from the left side of the window or 20% from the top of the window.
Things like that. That is really important. For example, if this is the game window,
a UI should always be in the same top left position. For example, for health bar up here or for some indicator in the
bottom left. Even if the window becomes smaller, let's say the new window is something
like this because it's resized. Then the UI should still be down here. And maybe scale down a bit, but it
shouldn't fundamentally change the position. Let me close the scene that I have just
created and delete it entirely. So node2d.tscn, we can delete.
Instead, I want to create another new scene. Which this time is going to be a user interface.
Once we have that, we are getting something that looks a little bit different. We are getting a
red frame and we're getting green needles around it. I'll talk about those in just a second.
If I add a new node to the scene, so far, we basically only work with node2ds, the blue ones.
Now we are going to work with the green ones. Those are control nodes, which you're using entirely for UIs.
In there for example, you have a label that gives you text. You have a panel that is a basic panel that you can
style. There's also texture rectangle. That way you can display an image. We are going
to work with these nodes in just a second. Although for now, the node that I actually want to work with is called a
color rectangle. This one is, well, a rectangle that displays a color.
If you look at the inspector, we can select any kind of color in here. Let's go with a reddish value for now so we
can see what's going on. And then we can resize this thing like any node2d.
That part is fairly straightforward, I think. That being said though, that's not the
system you are supposed to be using. Instead, if you look on the right in the inspector, we have layout and in there,
we get a whole bunch of options. The most important one is the layout mode. There we have position and
anchors. If you have position selected, then you can treat this thing basically like a
node2d where we can work with transform and give it an XY size, a position, a rotation, and a scale. All of the basic
things. This can be useful if you want to display text inside of a game. So for
example, later on inside of the game, we want to display some text and for that, we do want to use the position so we can
integrate a layout node in a 2D scene. However, purely for the layouts, we want to work with anchors.
And for those, we don't really need transform. Instead, we're getting anchor presets. Loads of options here, but I
want to work with custom. We're getting three options. Anchor points, anchor offsets, and grow
direction. The really important part for now is anchor points.
In there, we have left, top, right, and bottom. Via those points, we define the distance from the node to the side of
the screen that we are talking about here. Just for an example, let's leave left
and top at zero and zero. But right, we can set to 0.4 and bottom to 0.2. If I then zoom out just a bit, yeah, we
can see things better. And now let's talk about it. At the moment, we have this blue
rectangle. That is our screen. At the moment, in my case, the screen
dimension is 1280 by 720. You might have different numbers. It really doesn't matter because Godot for
layout nodes changes these numbers to a scale from zero to one. So, only for the X axis
from here here we are going from zero to one.
Same for the Y axis. We are starting up here with zero and then we are going all the way down to
one. That's the bottom border. Because of that, for example, for the right side
when we are defining 0.4 we are talking about 40% of the screen width. At the moment for the left side,
we have defined a value of 0.0. That means the left side of the node is on the left side of the screen.
However, for the right side we have set a value of 0.4. That means the right side of the node
gets 40% of the width of the screen. In other words, we have another 60%
that the node is not using. Afterwards, we get to the end of the screen.
The same system we are using for top, where we start on the top of the window. In other words, the top of the node has
a distance of zero from the top of the screen. But the bottom side
is 20% of the screen height from the top of the window. That is how you have to think
about layouts. You don't define an XY position. Instead, you define a distance to the screen borders.
Anchor points for that are the most important part. Besides that, the one that I do want to talk about in this bit
is anchor offsets. Those are in pixels and they give you an offset. For example, for left, we can add, let's
say, 20 pixels. And that way besides the anchors, we're getting 20
pixels from the left side. By that, you can also see what the green needles are for. They tell you the
anchor points. Besides that, right now for the top, I also want to have 20 pixels.
And then I can save the entire scene inside of scenes and let's call it title.tscn,
which would also be the name of the root node. title.tscn
If I now run the scene in the top left, we are getting the node that we have just created and this thing
grows or shrinks with the screen. Which can be really handy. That way, if
your game runs on a really small screen and if you have a really large screen, then it still works.
Even more importantly, what you can do is place this thing in the bottom right, down here.
Where, for example, the left side can have a value of 0.7 the top can be 0.6
the right can be one and the bottom can be one. Then we don't need any offsets. And now, if I run the current scene
again I can resize the window and the node is always going to be in
the bottom right, regardless of the window size. And that can be incredibly useful.
So, I hope the system makes sense. You basically, at least for now, want to work with layout mode anchors and then
for the anchor preset, you want to have custom. That way, you get the anchor points and the anchor offsets.
Besides that, if you look at the top, you have this button. By that, you can set anchor presets. For
example, you can place the node right in the middle, in the top left, in the bottom right
or you can make it cover the entire available space. This is usually just a starting
position. Once you have clicked on any of those buttons, you can still go to anchor
preset and go from the one you have selected to custom and then change whatever you like.
With that covered, let's create the actual title screen that I want to use for the game.
For that, first of all, this color rectangle is going to be the background. I have a custom color, 633C65
which is a purpleish color. After that I want to add another node, which is going to be a label.
If you now look at the inspector for label, we basically have text where we can write, let's call this one the car
game. Then, in the top left, you can see car game.
Although, the font is really really not ideal. It should also be quite a bit larger.
The way we can change that is inside of the inspector, we have theme and theme override.
Basically, you can apply a theme to multiple layout nodes, which we are going to do later. But for this project,
we only want to apply custom styling to this particular node, which we can do via theme overrides.
We can change, for example, the color and give it a different font color, which I don't want to do.
We can also give it a custom font and a custom font size. For the font size, I want to have 140.
That way, at the very least, this thing is quite a bit larger. For the font, we will need a font file
that I have inside of the folder fonts. In there, we have Better VCR and Crackman.otf.
Crackman.otf is what I want to use, so simply drag and drop it in there. Then we have a much nicer looking font.
This I want to center. Which I can do by going to this symbol up here and then placing it in the
center. That way it's right in the center, which is a decent start
but not perfectly yet. So, to customize that and move this text up just a bit I want to go to layout and then change
the anchor preset to custom. That way I can use anchor points and anchor offsets once again.
The only thing that I really want to do is inside of anchor offsets, I want to change the bottom.
And then move the entire thing up by some amount. Let's say negative 250.
If I now test this one scene then we have
a bit of text that is slightly on top of the center. This looks good. Besides that
I want to add another layout node, which is a texture rectangle. By that, we can add a picture.
I want to go to graphics, then to player and use player simple.png. Simply drag it in the texture
and then we have the player. This player should be right in the center of the window, which means anchor
presets, center. And then we have the player. That looks good.
We can also scale the entire thing. Go to layout, transform and then for the size
we can change this to, let's say 100 and 100 and then once again, you want to apply
the center preset so it is right in the center. Finally, I want to add another label.
This is going to be for the score. For now, let's simply write high score with some kind of number, 123.
This once again, I want to have right in the center of the window and then move it down a bit.
Which we can do by going to layout, anchor presets, custom and then anchor points
we want to move the top down by a bit. Let's say something like so. After that, I want to go to theme
override, fonts and font sizes. For the font, I want to use fonts and Better VCR.
Simply drag it in there. Then we have a nicer looking font and for the font size, let's go with 50.
Maybe a bit large. 30 is better, I think. Once again, play around and see what you
like. Anyway, with that, we have the basic title screen. That looks good.
This is all we need in here for now. Besides that inside of the game let me run it.
At the top of the window, I want to have a bit of text. And now, you do have to be careful.
You can add a layout node to a node 2D, like our game, for example. I could simply add a label to it
with, for now, let's say, some text and then move it to the center top of the screen.
Like we have done before for the title. The issue is, if I now try to run the game
I can't see it in the top, but if I move up, there we have some text. And this text is entirely static, so not great
yet. Effectively, we have to tell Godot that this label should be relative to the
camera that we have selected, which in our case is the camera of the player. The way you are doing that is by adding
another node that is called canvas layer. If we add the label to this node as a child
and run the game again then we have in the top left some text. A bit hard to see. We have to basically
redo the anchor preset. Then you can see, if I zoom out we have it up here.
Which still looks a bit confusing, but if I now run the game again at the top of the screen, we have some
text. And that looks pretty good. With that, we can do an exercise. I want you to customize the label on top
of the window, the one for the score. Number one, it should count the time since the start of the game. For that,
you can use a timer. Besides that, give it a custom font and an offset from the top of the window, so
it looks a bit nicer. If you want to experiment, you can also give it a custom size and a custom color
and just see what you can change. Pause the video now and see how far you get.
The most important thing is that this text displays some actually useful information.
Or in other words, it should display the elapsed time since the start of the game.
The way I approach that is, first of all, I created another timer. That should be the score timer, like so.
This one should auto start and have a wait time of 1 second. After that, I want to connect the
timeout signal to the game scene. Connect. Then, inside of the game scene, I want
to create another variable for the score, which has to be an integer with a
default value of zero, which is what we're getting by default. So, score int is totally fine here.<
