Game Development Essentials in Godot! | Thomas Yanuziello | Skillshare
Search

Playback Speed


1.0x


  • 0.5x
  • 0.75x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 1.75x
  • 2x

Game Development Essentials in Godot!

teacher avatar Thomas Yanuziello, Indie Game Developer

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

    • 1.

      Intro

      1:56

    • 2.

      Pause

      17:42

    • 3.

      Title

      15:59

    • 4.

      Transition

      14:18

    • 5.

      Autoload

      14:06

    • 6.

      Music

      15:09

    • 7.

      Settings

      18:34

    • 8.

      Exit

      13:20

    • 9.

      Enter

      15:57

    • 10.

      Save

      11:47

    • 11.

      Credits

      11:41

    • 12.

      What's Next?

      1:40

  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.

71

Students

1

Projects

About This Class

This course is a continuation of Introduction to 3D Game Development in Godot.

Click on my website link in my profile to join our discord server!

In this course, we will cover essential elements that are common to almost any game of any genre; pausing, menus, changing scenes, data persistence, music, settings, and moving a character between different areas of your game.

You'll also learn useful skills for working with the Godot game engine, organizing, and designing your projects to be more scalable.  You will be learning how to code with GDscript, with everything explained in detail.  Our scripts will be written to be highly customizable and reusable.  All of the project files will also be available on GitHub if you need to review the project as it was after completing each lesson.  These videos were recorded using Godot version 4.2.2.

This course will be part of a series designed to teach bite-sized pieces of game development that can all be used interchangeably with each other.  So let me know what types of games you're interesting in learning how to make and I'll try to include them in future courses in this series.

Meet Your Teacher

Teacher Profile Image

Thomas Yanuziello

Indie Game Developer

Teacher
Level: All Levels

Class Ratings

Expectations Met?
    Exceeded!
  • 0%
  • Yes
  • 0%
  • Somewhat
  • 0%
  • Not really
  • 0%

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.

Transcripts

1. Intro: Welcome to my course on the essentials of game development and Gado. This course is a continuation of introduction to three D game development and Gado but can be followed and applied to any project that contains a character the player can control to move through multiple levels. You're welcome to join our discord server to work on this course alongside your peers. In this course, we will cover essential elements that are common to almost any game of any genre. Building a title scene, menus, smoothly transitioning between scenes, moving a character between different levels of your game, background music, settings, and data persistence between scenes, levels, and play sessions. When you're done, you'll have a good basic structure of a game that you can further develop into something of your own design of any genre. You'll also learn useful skills for working with the Gada game engine, organizing and designing your projects to be more scalable. You will be learning how to code with GD script with everything explained in detail. We will apply object oriented design principles in our scripts, inheritance, encapsulation and abstraction, to keep them organized, customizable, and reusable for a project of any size. All of the project files will also be available on GitHub, if you need to review the project as it was after completing each lesson. These videos were recorded using Gadot version 4.2 0.2. The project starts with assets from Ka Kits Character and Dungeon remastered Packs made by Kay Lauberg. In this course, I'll also be adding assets from Basic Guy Bundle made by Penzilla, and music in the Barns Music pack made by Eric the Funny Baron. All are available to download for free on H dot IO. 2. Pause: Hello, friends. Before we get started, you should have a game scene in your project, which contains a character that the player can control and a level they can walk around in. You should have at least two or three different level scenes ready to connect together when the player walks past a threshold. Throughout this course, we will add elements that are essential to any type of game you can think of, including menus, scene and level transitions, fading both visuals and audio, settings, credits, and data persistence. You can use your own project to follow along with this course or download a starter project from my Github titled Godot Essentials course Main branch. Your project can be two D or three D and almost any game genre that involves moving a character between different scenes. Let's start by allowing the player to pause the game. Opening the project settings and switching to the input Map tab, we can add a new action for pause and click on the Add button. Scrolling down, finding our new pause action, we can add events which will trigger this pause action by clicking on the Plus button. I'll use the Escape key and the start button on my controller. We've been using the player node to handle our game's input through the attached players script and relaying the appropriate information to move the character or the spring arm and camera. Like we did with the run and jump buttons, we can check if the pause button was pressed. But we don't want to pause the character or the camera. We want to pause the entire scene. We can grab a reference to the scenes root node by exporting another variable. Let's call it underscore GM, short for game manager. But the value of this variable shouldn't ever really need to be changed. It should always be the root node of the game scene. Instead of at export, we could use at on ready to set the value of our GM variable to get parent, since the player node is a child of the game node. But we may not want to rely on this exact structure in order for our script to work properly. We may, for instance, want the player node to be a child of the character node for other reasons. So to make this reference always point directly to the Scenes root node, we can use the dollar sign annotation. Starting the node path with slash root slash, we'll start at the Scene trees root. But it's important to note that this is not yet the game scene node. We also need to add the name of the root node to this node path root slash gain. If we run our current scene, then switch to the remote view in the scene panel, we can see that the Scene trees root node is named a root, and currently the roots only child node is the game node. Now that our player node has a direct reference to the scenes root node, let's call a function on it that we haven't written yet, Toggle pause. Attaching a new script to our game node. This script will be responsible for managing the scene as a whole. We'll call it game manager. Much like a manager in a workplace, this scripts job will be to open the scene when it first starts. Make sure all the employees or child nodes have everything that they need to do their individual jobs, then close the scene when it's finished. Since our simple game only has one mode of play, we only need one game manager. But a more complex game with multiple game scenes might have an exploration manager, battle manager, puzzle manager, and so on, for different gameplay scenes. In our new game manager script, we can add the toggle pause function we called from the player script. Pausing the game is actually quite simple. We will start by getting a reference to the entire scene tree with a built in function, get tree. The return type of this method is a scene tree, which contains a variable named paused that we can access with p. The type of the paused variable is a Boolean, which has a default value of false. Setting the value to true pauses to gain. We can switch the value back and forth between true and false every time this toggle pause function is called using the naught logic operator, represented with an exclamation point. Setting the value of paused to naught false the first time and then not true the second and repeating. If we test it out, we can pause the game, but we can't unpause yet. This is because the player node, which is trying to receive the input to unpause the game, is also paused and can't receive or process input. Some specific nodes we might not want to pause while the game is paused. Selecting the player node in the scene tree, look in the inspector under node and expand the process section. The mode property is currently set to inherit, which means that it will inherit the same process mode as its parent, the game node. Since the game node is paused, the player node will also pause. We can change this value to always, so the player node will always process even when the game is paused. Note that we can also make nodes pai have some nodes only process while the game is paused or disable processing from certain nodes altogether. Now when we run the scene, we can pause and unpause the game since the player node is always running regardless. But this creates a new problem. If we pause the game and press the jump button, then unpause, the character jumps. If we do not want this behavior, we need to return to the player's script. Let's first move the check for the pause button to the top of the input function. Then if the tree is paused, ignore any further inputs by returning and do the same in the process function to ignore the movement and camera controls too. Now when the game is paused, the only input the player can give is to unpause the game. Everything else will be ignored. Lastly, I would like to display a menu on the screen with some buttons while the game is paused. But before we do anything involving the user interface, we should configure the game's window size. Open the project settings and switch to the general tab. Selecting window, we can set the size property to set the window size of our game. Optimal window size will depend on your target platform. I'll use 12 80 by 720 pixels. So far, everything in our scene tree is being observed by the camera to produce a two D image, which is what we see in our window when we play the game. This two D image being rendered by our camera is layer zero of the two D display. We can add additional layers to our games display after the camera has finished its rendering using a new node type, a Canvas layer node. The default layer of a Canvas layer node is one, so it will be drawn over layer zero. If we want, we can add any number of layers to draw in front of or behind our game. Let's rename the Canvas layer node to UY, short for user interface. Right clicking on the UI node and selecting Add child node. Let's add a label node to the Canvass. This switches our view to two D. So far we've only been working with default nodes like the player node and three D nodes for everything else. Our Canvas will use a different family of nodes called Control nodes, which have green icons. I'll rename this node to title and set its property to say pause. Next, let's repeat the process to add a button. And name the button continue. Then edit the buttons text to say the same. Zoom and pan, so you can see the blue rectangle to the right of the green y axis and below the red x axis. This is the viewport of the game window. Our nodes were added at the scene origin, so they will be rendered in the top left corner of the screen if we play the game, but they are overlapping. Let's organize these nodes using another control node, a vertical box container. A vertical box container doesn't actually draw anything, but we'll organize its children to align vertically, making organization faster than if we were to manually position each node. Selecting both title and continued nodes, we can click and drag to re parent them to the vertical box node and see that they are automatically reorganized. Let's also duplicate the continued button to create another button and name this one exit. Then edit the text property to match. The vertical box automatically adjusted itself to accommodate the extra button. Let's rename the vertical box to pause menu. With the pause menu node selected, expand the layout section. The anchors preset value is currently set to top left. We can easily anchor the pause menu to any corner edge or the center of the screen. The anchors are represented in the preview by these four green pins, which we can individually click and drag around the screen. The anchors determine the notes position or size, in relation to the window size we set in the project settings, expressed as a percentage. We can also use custom anchors if we want to, for example, use only the upper 10% of the screen for a menu bar, or maybe use the middle third of the screen to display a scoreboard. I'll anchor my pause menu to the center of the screen, and also set the titles horizontal alignment to be centered to match the buttons. With the pause menu created, let's set its visible property to false by default by clicking on the icon beside it in the scene tree. Then in the game manager script, we can use a ready to get a reference to the Pause menu. Using $1 sign to specify a node path, using quotation marks because the name contains a space, going through the UI node to access the pause menu node. When the game is paused or unpaused, we can set the visible property of the pause menu to match the paused value of the tree. Now we have a pause menu with buttons, but how do we know when the buttons are pressed, and what do we do when they are pressed? If we select the exit button in the scene tree, we can switch the inspector tab to the node tab, which will display signals by default. If groups are displayed, you can switch to signals by clicking here. Here we can see a variety of signals that this node will emit under different conditions. The button node will emit a signal when it is pressed. All we have to do is connect this signal to a function, either by double clicking on it or right clicking and selecting connect. In the window, we can select any node in our scene tree, which we'll listen for the signal to be emitted. If we select the game manager node, the receiver method field will say on Exit pressed, which is the name of the function which will be created for us when we click Connect. Our view will automatically switch to script and display the game manager script, which now contains the on exit pressed function. This function will now be called automatically when the exit button is pressed by the player. A green connection icon is displayed next to the function definition to tell us that this function is being called by a signal, and the exit button in the scene tree has a signal icon to tell us that this node can emit a signal which is connected to a receiver. For now, let's just print to the output, a message saying, return to Title scene. Both so we know it works and to remind us to implement this feature later. Selecting the continued button, we can also connect its pressed signal to the game manager node. But this time, click on the pick button and pick the toggle pause function we wrote earlier. Lastly, we need this node to process while the game is paused. So let's change its process mode to when paused. Let's try it out. We can pause the game, clicking the exit button displays our message and pressing the continued button, pauses the game. Once the menu buttons have focus, we can also use the arrow keys to navigate between the buttons and the space bar to press them. Let's make this work with our game controller as well with just a couple more simple steps. Opening the project settings, the input Map tab, click on the show built in actions toggle to see the actions that were used. The Controllers DP is already listed under UI left, right up and down for navigating menus. But we need to add a controller input to the UI accept action to be able to press the buttons. I'll use the bottom action button, which is A on my Controller. Now we just need the menu to grab focus when it is opened. Adding a script to the pause menu node, we'll just name it menu. We'll export a variable to hold the menu item, which should grab focus by default when the menu is opened of type control. I'll assign the continued button to be the default focus item in the inspector by clicking and dragging it into the field. Creating a public function, let's call it open. We can set the visible property to true and also tell the default focus item to grab focus. And another function close, will set the visible property back to falls. Back in the game manager script. Instead of setting the visible property of the pause many directly, we can call either open or closed based on the value of paused, using an if statement. Running the scene, using only a controller, we can pause the game, navigate the menu, and press the buttons. We now have a pause menu that is presented to the player when they press the pause. In the next lesson, we'll build a title scene for our game. I'll see you in the next lesson. 3. Title: Hello, friends. In the previous lesson, we created a pause menu for our game scene. In this lesson, we'll build a title scene that connects to the game scene. For that, we'll need a background image and some basic UI assets. I'll be using basic Guy bundle made by Penzila on it shot IO. Let's start by creating a new scene. You can select scene from the menu bar, then new scene. Use the shortcut Control N or Command N or right click in the File System tab and select Create New Scene. Right clicking on a specific folder will create the scene in that folder and allow us to give it a name right away. It doesn't matter if this scene is two D or three D, since we're only interested in UY for this lesson. Let's make this scenes root node a Control node by picking User Interface. And the root node is automatically renamed to match the name of the scene title. If we create the scene through the menu, we will be asked to select the root node type first. Then name it and sort it into a folder the first time it is saved. Selecting the root node, we can see that this is a control node with its anchor presets set to full wreck, covering the entire game window, but not actually drawing anything. Like in the previous lesson, let's add a label node and some buttons. L et's name the label note title and set the text property to the title of our game. Then likewise, name our buttons and edit their text properties to new game. Continue. Settings, credits, and exit or any other buttons you would like to have on your game's title screen. Let's also organize these buttons using a vertical box container like we did with the Pause menu and rename it to menu buttons. We can quickly and easily organize these items on our screen using anchors. For example, I would like the title to be centered horizontally on the screen and one third down from the top of the screen. With the title label note selected, expanding the layout section, I'll change the anchor presets to custom. Anchors are defined as numbers 0-1, representing the percentage of the parents width or height. Positioning the title in the middle of the screen horizontally can be done by setting the left anchor to 0.5, and the right anchor will automatically update to match since the right anchor can't be less than the left. Likewise, positioning the title one third from the top of the screen would mean setting the top anchor to 0.333. This isn't quite position the way I want yet because the anchors are in the top left corner of the label. The text just is played to the right and below the anchor point. Expanding the grow direction subsection, we can set the horizontal and vertical growth directions to both. Epending the anchor offset subsection, we can reset them all to zero, and now the anchors are centered within the label. I'll also position the button container in the same manner. But with its vertical anchor at two thirds down, so it appears below the game title. You can also position any of your control nodes manually, but remember that using anchors will make your layouts more flexible and fit different screen resolutions. Let's add a manuscript to the Mini buttons node and assign a default focus item in the inspector. Like our game scene has a game manager script attached to its root node, we likewise need a title manager script attached to the Title scenes root node. And here we can grab a reference to the menu buttons script during the ready phase using add on ready. Then tell the menu buttons to open in the ready function. The menu was already visible, but telling it to open, we'll also tell the default focus item to grab focus. Selecting each of the button nodes, we can add an pressed function call to our title manager script for all of them. For now, we'll only be concerned with the new game button. The rest can just print strings to tell us to implement these features later. The purpose of the new game button will be to switch our game from the title scene to the game scene. We can accomplish this by getting a reference to the scene tree, then accessing a method called change scene to file. This method takes a string argument, which is a file path to the scene we want to load. The suggestions contain a list of all the scenes in our project, so we can select the game scene from here. Alternatively, looking in the file system tab, we can find the game scene and right click, then select Copy path, and paste it as text. But remember that strings must be enclosed in quotation marks. So far, we've been using the run current scene button to test our game. But you've probably accidentally pressed the run project button at least once by now, which will prompt the setting of our project's main scene. This is the first scene that will be loaded when we start the game, which should be this scene, the title scene. If you haven't set this yet, you can click on the select current button to set the title scene as the game's main scene. The new game button grabs focus when the game starts. Clicking each of the buttons prints out our statements, and clicking on the new game button immediately switches to the game scene. We can also edit the project's main scene anytime from the project settings in the general tab under application run Min scene. Our title scene is now functional, but it doesn't look very good. First, we can add a splash background using a text node. Let's name it background. In the layout section, setting the anchors preset to full wreck, will ensure that the background covers the entire window. We can edit the texture property to display whatever two D image we want. Using the properties in the inspector, we can alter how the image is displayed from keeping its native size or fitting inside the anchor points either by width or height. We can also specify that the image should maintain its aspect ratio to avoid the image being stretched to fit the window. Lastly, we'll sort it at the top of the scenes children, so it is drawn first, behind everything else. Next, let's take a look at the title label nodes properties. Most of the label settings have to do with justification and wrapping, which isn't really relevant for our title. The settings we want to change are under the properties inherited from control in the theme override section. Here we can adjust the font color. Add a shadow or an outline which can also be adjusted in the constants subsection. We can change the font size, and also the font itself. I've downloaded a couple of free fonts from dafont.com. Make sure any fonts you use in your games are free. Da font displays the licensing for their fonts above the download button. This works fine for our game title, which is meant to stand out, but editing individual properties in this way for everything in our project would be tedious. For editing our menu buttons, we should instead create a common theme to use throughout the game project. Selecting the button container node. This time, expand the theme section. The theme field is empty. Clicking on it, we can select new theme to create a new theme resource for our project. Clicking on the theme resource will add a new tab to the bottom panel of our window, a theme editor. The theme editor contains a preview of a variety of different control nodes, a panel, playable, different types of buttons, toggles, drop down, color picker, text fields, scroll bars, separators, tabs, and a tree. All using the default theme that is provided by Gadot. Looking back at our theme resource in the inspector panel, we can edit the default font and font size for everything in our theme. Let's change the font and adjust the size. We can see the effects both in the preview and in our buttons of our title menu. This doesn't affect the game title label since the theme has not been applied to that node. It has only been applied to the menu buttons container. Even if the theme were applied to the title node, the theme overrides we just applied would be used instead. The buttons inherit their theme from their parent in the scene tree. In the theme editor, we can add new settings for any control node by clicking on the Plus button. Since our menu contains only button nodes, let's add settings for button nodes. There are a lot of different settings for adjusting the font and icon colors during different states of the button. Default, disabled, focused, hovered, hovered pressed, and pressed, as well as an outline color. Before we can adjust any of these settings, we need to add them to the theme by clicking on the plus button beside them. Adjusting any of these settings, we can see their effects in the preview, including the hover, focus, and press states by clicking on the buttons. There are additional settings and other tabs for adjusting constants, fonts and font size. The font and font size have already been set by the theme resource itself. We don't need to adjust them here. We can also change the look of the button itself using style boxes. Each of the button states can be assigned to different style box. Let's start with normal. Clicking on the plus button, we can use a flat style box to just create a flat colored rectangle for the button, or we can use a texture style box to use an imported two D image. Clicking on the style box resource will open it in the inspector panel where we can populate the texture field with a two D image file. You may want to add some padding to the edges of the button, so the button text doesn't overlap with the edges of the image. Expanding the content margin section, we can adjust the size of the margins to better fit the text inside the image. Adding a pressed style box, we can switch the texture that is used to draw the button. Copying the same settings weed for the normal style box, but increasing the top padding to make the text move down when pressed. Adding more style boxes for disabled hover and focused states. You may not have different textures for all your different button states. But we can still create new style boxes for these states. Use the same normal texture and settings, but add color modulation to create a different appearance for the button in this state. We can multiply the textures colors by something like yellow to make it look noticeably different while being covered. Or we can just use another image in a different color to emphasize focus. When disabled, we can multiply the colors Alpha to add some transparency. We can test all of these different style boxes easily from the preview in the theme editor. Now the remain menu looks better, let's also edit the Pause menu in the game scene to match. Instead of adding a new theme to the Pause menu and redoing all of the edits, we can instead return to the title scene, find the resource, and click on the Dropdown. Select Save and save the theme in our projects resource folder. Now, in the game scene, we can assign this theme to the pause menu, and the buttons will automatically be updated to match the new theme. Opening the game manager script. When the player presses the exit button, we can also change to the title scene. Running our game, we start in the title scene. The new game button switches to the game scene. Pausing the game and selecting exit returns to the title scene. We now have a title scene and can switch back and forth between our two scenes. In the next lesson, we'll smooth the scene transition by fading to black. I'll see you in the next lesson. 4. Transition: Hello, friends. In the previous lesson, we created a title scene and connected to the game scene. In this lesson, we make the transition smoother with a visual fade. Most games start with a black screen. Let's add a new node to our title scene, a color wrecked node. Let's call it Fade. In the Inspector, we can set the color property to black. Then set the anchor precets to full wreck to cover the entire window. When the game starts, we can gently fade this object to be fully transparent, revealing the title scene behind it. Even when an object in our scene is transparent, mouse events will only be triggered on the first thing they hit, which means moving the mouse or clicking on our buttons has been blocked by the fade. In the properties inherited from control, in the mouse section, we can change the filter settings of our fade to ignore, which will allow the mouse events to pass through the fade to the objects behind it. Now the buttons work with the mouse again. While we're working on our scene in the editor, it would be better to be able to see everything else. I'd like to have the fade being visible by default. Before we attach a script, let's start organizing our scripts into more specific folders by creating a subfolder named UI. We can move the manuscript into the subfolder since it is used to control UI elements. But when moving resources around like this, make sure the scenes that use it are open first. Otherwise, the scene files might lose track of them. If that happens, just move the resource back to where it was originally and make sure that the scenes using the resource are open before moving it. Now we can attach a script to the Fad node and use the browser to sort it into the UI scripts folder. Unlike our manuscript, which could be relevant to any control node, since it was only affecting the visible property, which is inherited from control. This FAD script will be altering the color property of the color wrecked node, so it will only be usable by color nodes or its inheritors. Let's start in the ready function. Setting the visible property of the fa true when the scene first starts, making the window completely black. Then we can declare a public function called to clear. Unlike most functions in most scripts, this is something that will need to happen gradually over time, spanning several frames. We can accomplish this with a new variable type, a tween. This can be a private variable, only applicable to this script locally, and I'll just name it tween for simplicity. The name of this class comes from the English words in between, since it is most often used to find points in between a starting point and an end point. We can create a tween anytime by calling a built in method, create tween. This method returns a tween object, which we can assign to our variable to store it. A tween is a complex class with a variety of methods, but the one we want to use is called tween property, which requires several arguments. The first argument is the node that this tween will be affecting, which is the same node that this script is attached to. We can get a reference to this node using the keyword self. The next is the node property we want to change, a property path as a string. We will be changing the color property of this node. If you're unsure of the property path, we can look in the inspector. Hovering over any property will show us the property path to access it, or we can right click to copy the property path and paste it as text. The next argument is the end value we want this property to be set to after the tween is finished. Since the property is a color, we will be setting this to a custom color we will define. Let's call it clear. And the last property is the amount of time that the tween will last, measured in seconds, expressed as a float. Let's set it to 1 second for now. The value of clear will be something that we can define but never changes. Instead of declaring a variable, we can define a constant using the keyword constant. Name it clear of type color. It's conventional to name constants in all uppercase. Then assign the value of this constant as a color. Writing the class name followed by brackets, accesses a constructor method, allowing us to construct the color by specifying all the required properties. A color is defined by four floats, red, green, blue, and Alpha for transparency. A as numbers 0-1. Our clear color will simply be zero, red, zero, green, zero, blue, and zero Alpha, making it black, but also completely transparent. Calling our two clear method will transition the color property from its current value, which is black to clear over the duration of 1 second. We can also write another function to black to do the opposite. However, we don't need to define a constant for black since the color class already has one. We can access it through the class name using a period, and we can see that there are a large number of predefined colors. The one we want right now is black. Black is defined as zero, red, zero, green, zero, blue, but one Alpha. Let's switch over to the title manager script for a moment and grab a reference to the FAD Noe during the ready phase using at ready. When the scene starts, we can tell the note to Fate to clear. Then before switching to the game scene, we can tell it to fade to black. But the process of fading to black takes time, and this function will run in one frame immediately switching to the game scene, so we won't see it happen. We can tell this function to pause and wait for a signal before proceeding, using a new keyword, a weight. A weight requires a signal to wait for, which we can return from the fade to black function. Back in the FAD script, we can specify a return type for our functions before the colon by adding a hyphen an arrow, followed by a type. In this case, we want to return a signal. The tween class contains a signal that is emitted automatically when the tween is finished, so we can return that. Now the title manager will wait for the FAD node to fade to black before changing scenes. Butt's also copy this format into the two clear function. Even though it is returning a signal, the title manager does not need to accept this return or do anything with it. In this case, the tween will be started and the remainder of the function will proceed immediately. We can copy this FAD node into the game scene. Then edit the game manager script to get a reference to the FAD node during the ready phase. Fade to clear when the scene first starts, and await fade to black before switching to the title scene. But this function on exit pressed, is being called while the game is paused. Therefore, the F node is also paused and will not tw its color as a result. We can allow the FAD node to always process to get around. But it would also be a good idea to unpause the game before switching scenes. Let's try it out. Now the game starts from a black screen fading into our title screen, pressing the new game button fades to black, switches to the game scene, which fades back in. Pausing and pressing the exit button, fades to black, switches to the title scene, which fades back in as well. There's a flicker between switching scenes, however. We can edit the project settings under rendering environment, and change the default color to black. This is a much more gentle transition than immediately switching scenes, and if our game gets large enough to require longer loading times, we can change this to a loading screen. However, there may be some problems with starting a tween before the previous one has finished. Back in the FAD script, we can check if the tween exists by comparing it to null. In Godo script, we can do this implicitly with just if tween. If it does exist, also check if it's running. In that case, we should kill the tween before creating a new one. This will prevent any chance of multiple tweens existing and interfering with each other, since the most recent tween will simply take over. Our two clear and two black functions are very similar with only the color value different between them. It will be good practice to instead declare a private function here. Let's name it two color, and accept a color as a parameter. We can then do all this only once. Passing the color to the twin property method, and having the two clear and two black functions called this two color function instead. Passing the return signal through the chain or managers can await it. This way, making any changes to this behavior will require only changing one block of code. You may want to have the script to be more adaptable. Let's export a variable for the duration of the tween and assign it a default value of 1 second. Then replace the 1 second argument with our variable, and now the timing of the can be easily adjusted in the inspector. Let's see how the FAD looks with the duration of 2 seconds. We can make this even more flexible by allowing the two clear and two black functions to accept an optional parameter to override the specified duration. Let's call the parameter duration without an underscore, making it different from the variable which does have an underscore. And assign it a default value of our underscore duration. We then need to pass this value to the two color function. And add it to the list of parameters. Then use the parameter in the tween property method instead of our variable. Our manager scripts can still use these functions without specifying a duration. In that case, the exported value will be. But they can also specify a different duration and use that instead. Let's have the exported de duration be 1 second, but allow the title manager to override that and fade in over a duration of 2 seconds instead. We now have a more gentle visual transition between our two scenes. In the next lesson, we'll pass information between scenes. I'll see you in the next lesson. 5. Autoload: Hello, friends. In the previous lesson, we faded our scenes in and out for a smoother transition. In this lesson, we'll add extra nodes to the scene tree that are accessible from any scene. If we run our game and switch to the remote scene tree. We can see that the scene trees root has only one child, which is the title scene. When switching to the game scene, the title scene is removed from the tree and replaced with the game scene. If we want to pass information between scenes, we can add extra children to the root node of the scene tree, which will remain there as long as the game is running. These are called auto loads, and we can create them by writing scripts. First, let's add a special folder inside the scripts folder for holding our auto load scripts. Then right click on this folder to create a new script. The purpose of the script will be to save load, and provide access to data. I'd like to name this script file. Since this doesn't represent anything that needs to be drawn, it can inherit from node. This script will have two variables containing separate sets of information, the game's current settings, and the player's current progress through the game. You may want to have a third variable for storing progress information associated with a user account, but not tied to a specific save slot, such as unlocking difficulty levels or achievements. These variables will be publicly accessible to any other script in our game in any scene. Opening the project settings, switch to the auto load tab. Click on the folder icon beside the path field to open a browser, then navigate to the file script. The node name field will automatically be populated to match the name of the script. Click the Add button to add this script to the list of auto loads. Now when we run the game, we can see in the remote scene tree that the root node has another child node named file. Clicking on this node, we can see that it has two variables named settings and progress. Switching to the game scene, the title scene is removed and replaced with the game scene, but the file node remains, meaning we can use it to pass information between scenes. But I haven't specified a type for the variables because we will want to create our own types to hold complex collections of information. Let's create another sub folder in the scripts folder and name it custom resources. Then right click to create a new script. Let's name it settings. Instead of inheriting from a node type, this time, the script will inherit from resource. Then we can create another one. Let's call this one progress. In the resource scripts, we can add any number of variables of different types, but they must be built in types, not references to other things. For example, we can store a Boolean variable, which is either true or false to set whether the camera controls on the x axis are inverted and another for the Y axis. Numbers can be stored as floats, which allow decimal points. You might use this to save the game's volume setting as a number between zero, muted or one full volume. Numbers can also be stored as integers, a number that does not contain decimal points, but can be positive or negative. We might use this in the progress script to store the players money or. We can also use strings to store sequences of characters, perhaps giving the player save slot or protagonist a name. Any other built in types like vectors or colors can also be used? Collections of any of these types can also be stored in either an array or a dictionary, such as an array of Booleans to contain whether or not the player has completed each level. Each of these variable types has a default value. Booleans are false, integers and numbers are zero. Strings, arrays, and dictionaries are all empty. When a resource is created, it will automatically call a built in function named in it. Short f initialize. Overriding this function, we can specify whatever default values we want for our variables. Perhaps starting our volume setting as 0.5 for one, or giving the protagonist a default name. To create our resource, we need to specify a class name, which is done at the top of the script. Usually in the same line as the extends keyword. With the keyword class name, we can give this resource class a name that will be used by other scripts to refer to this class as a type. We can name this class settings with a capital S, and this one, progress with a P. Conventionally, classes are named in Pascal case with the first letter of each word capitalized. Back in the file script, we can now specify the types of our variables as settings, and progress. For now, we can just create these resources inside the ready function. Using their class name followed by dot Neu. This will also trigger the init function, initializing the variables inside the resource. Running the game, we can see these variables in the remote scene tree. Click on them, see and edit their property values. Let's change their values around. Switch to the game scene and confirm that the changes remain through the scene transition. Any script in our game can easily access these resources thanks to the file auto load. Let's open the spring arm script that is responsible for rotating the camera. Its current behavior is using inverted x and y axes. But now we have variables in our settings resource which should toggle this on or off. Note that rotating the camera about the x axis is a vertical rotation, which players will understand as the y rotation, and rotating about the Y axis is the horizontal rotation or x rotation. We can write an if statement before each of these calculations to check our file dot settings to see if the appropriate invert variable is true or false. Then multiply the formula by negative one, if it's false, to switch the inverted behavior to not inverted. This means having almost the same formula copied twice with only a minor difference of being multiplied by negative one or not. We can do this more efficiently using an re statement. Returning to the original format first, then multiplying by in brackets, one, if file settings invert else, negative one. And repeating this with the horizontal rotation, changing y to x. Turnary statements are effective anytime you want to change one value based on a simple bullying condition. L et's try it out. Tilting the right analog stick, the cameras x rotation is no longer inverted by default, but the y rotation is inverted. Opening the remote scene tree, we can access and edit the settings. And returning to the simulation, the camera controls are now opposite. We've now created a few of our scripts that inherit from different note types and also from resource. But we can also write scripts that inherit from our own custom classes. Taking a quick look at the FAD script, we combined the behavior of two clear and two black into one combined function. We can combine similar behaviors from different scripts in a similar way, creating a super class and using inheritance to allow different scripts to access the same behavior. Let's use our manager scripts as an example, since they both now use the FAD transition. It would be a good idea to put these in a separate scripts folder. Let's call it managers. Moving both the game manager and title manager into this folder. We can also create a new third script, let's call it scene Manager. In the scene Manager script, we'll give the script a class name in pass bell case. Anytime you give a script a class name, you'll need to save before the engine will recognize it. Then in the game Manager and title Manager scripts, we can have these extend the behavior of the scene Manager class. Now, anything we put in the Scene Manager script will be used by both the game manager and title manager. Let's move the FAD variable into the scene Manager script. Then in the game and title managers, since they inherit the Fad variable from the scene manager class, they are not allowed to declare another variable of the same name. We can delete the variable, since it is now inherited from the scene manager class. But the node path is different between the game scene and the title scene. We can easily get around this by exporting the variable instead of using at on ready. We will need to assign the value of fade in both scenes in the inspector panel. If the variable isn't showing up, you may need to close and reopen Godot to get the class inheritance working. Functions are also inherited, but subclasses can redefine inherited functions overriding their behavior. This is why every class we have written with a re or process function has a blue icon beside it, since it is overriding the inherited definition that already exists in the node class. If our scene manager class has a ready function that tells the fade to fade to clear, this behavior will be inherited by both the game manager and the title manager. We can remove this function from the game manager, but the title manager is also opening the menu. Allowing the title manager to override the ready function definition inherited from Scene Manager, we don't need to override all of it. Our subclasses can access the inherited definition of a function using the keyword super. Since title manager inherits from Scene Manager, Scene Manager is the superclass. By calling super dot ready, we are telling the Fade to fade to clear. But then we also tell the menu to open as well. The structure of superclasses and inheritance will become more useful if we have more scene managers or more common behaviors of all our scene managers. We don't need to rewrite the same code across multiple scripts. We now have an auto loaded node in our scene try that can store information about game settings and progress. In the next lesson, we'll add background music to our game. I'll see you in the next lesson. 6. Music: Hello, friends. In the previous lesson, we created auto loaded nodes that can be used to pass information between different scenes. In this lesson we'll add background music that can change with each scene of our game. For this lesson, I'll be using Barn's music pack made by Eric the Funny Barn on itch dot IO. Whatever background music you choose to use for your game, make sure that it is designed to loop. Since audio files are typically very large, I recommend only importing them into your project as you decide to implement them. Once you have them imported and sorted into a music folder, select one and switch the scam panel to the import panel. You may need to edit the import settings for your audio files before they will be able to loop. Depending on the file type, the loop setting may be a checkbox or a drop down with multiple options. In that case, you'll want to change it to linear looping. Let's start by opening the title scene and adding a new node to it. On audio stream player node. Make sure not to use the two d or three D variants, as these are meant to simulate hearing sounds in two D or three D space. The normal audio stream player node will not be affected by proximity or anything else in the scene, and just play the audio as is. We can set the audio stream property in the inspector to one of our imported songs. Taking a look at the audio stream player notes properties in the inspector, you'll notice that the volume is measured in decibels, afloat with a default value of zero ranging from negative 80 to 24. It's important to note that this number doesn't scale liarly. Increasing from 1 decibel to 2 decibels is not twice as loud. But don't worry if you don't understand how decibels work because we won't be using them directly. We can tell the audio stream player node to autoplay when the game starts. Running the game, the music starts at full volume, and when we transition to the game scene, it stops suddenly. Combining what we've learned in the previous two lessons, we can create a persistent audio player for playing background music, and also fade music in and not smoothly. Since background music is often something games will have in every scene, it would make sense for there to be an auto loaded node which can remain in the scene tree permanently to handle it. So we can delete the audiotrem player node in our scene tree. And create a new script in the auto lodes folder. Let's call it music. This auto loaded node can inherit from audio stream player, giving the music node access to all the properties and methods of an audio stream player node. Since we can't access the properties of an auto loaded node in the inspector, we will have to set its default property values in the scripts ready function. I would like the volume to start at its lowest possible value, which is negative 80 decibels. But we can also use linear volume if we want to, which is easier for most people to understand. Using a built in function, linear to dB, short for decibels, which will convert a linear scale into decibel scale, allowing us to set the volume to zero in linear terms, which means no sound. If you want the music to also play while the game is paused, we will need to change the process mode of this node. Using the suggestions, we can set it to node, dot, process always. Thank you. Okay. Thinking first about how we would want this node to be used, we probably only need two public functions. One to play a music track and another to fade it out. Play track will take a track as a parameter of type audio stream. While fade out doesn't require any parameters. In the Play track function, we can access any properties inherited from audio stream player node, including the stream that is currently playing, which has a default value of null. We can set the value of stream to the track we want to play. Then tell the audio stream player to play. But the volume is currently inaudible. Let's use a tween like we did with the visual fade to gradually adjust the volume over time, declaring a new tween variable at the top of the script. We'll first check if the tween already exists, and if it does exist, check if it is already running. And if so, kill it. We can then create a new tween. And tween a property. Accessing this node itself, the volume property, gradually changing it to file dot setting dot volume over the duration of 1 second. But remember that the volume doesn't scale linearly, since it is measured in decibels. Instead of tweening the volume property directly, we can tween a method instead. Tween method doesn't require a node reference, so we can remove the first argument. The property path is now a callable method. Let's write a function called set linear volume, which takes a float parameter of the linear volume. This function will set the volume property after converting it from linear to decibels. We can use this in our ready function for consistency. And also use this as our callable method in the tween method call. Note that when using a method as a cable, it doesn't have brackets at the end. Method also needs not only a final value, but also a starting value, since this isn't a property of the node anymore. It has no way of knowing what the current value is. The starting and ending values are actually an argument that will be passed to the callable method, the linear volume. Using the opposite built in function, we can convert decibels to linear to change the current decibel volume into a linear volume as the starting value. We can specify that the linear volume of our music will be tweened from whatever the volume currently is up to file that setting stop volume over 1 second. Let's also return the tween finished signal. Then the fade out function will want to do the exact opposite of this. Tweeting the linear volume from whatever it's at to zero. Waiting for the tween to be finished, stopping the node from playing, and setting the track back to null. Like we did with the color Fade, we can combine these into one private function. Let's call it volume. Taking only the target linear volume as a parameter. Twining the volume from whatever it's currently at to the target volume over the duration of 1 second. And now both fading in and fading out use the same function. Opening the project settings, switching to the auto load tab. We can add the music script to the list of auto loaded nodes. In the scene manager script, we can export a variable to hold the background music track for each scene, since every scene manager will inherit the variable and be able to assign its own value to it. Our scene Manager script can now easily access the music auto load node using its node name, telling the music node to play the desired track for this scene. L et's assign a different music track for each of the title and game scenes. And also make sure to fade out the music anytime we're changing scenes. Let's try it out. The title scene music fades in, pressing the new game button fades the music out, and the game scene fades its own music back in. Pausing and pressing exit fades the music out and the title music fades back in. This works fine as long as we are only playing one music track per scene and are diligent at always fading out before requesting a new track. But what if we wanted to tell the music node to play a different track while it is already playing or even the same track? It would be a good idea to add some extra conditions to the play track function. Let's start with checking if the music node is already playing. Then also check if what the node is playing is the same as what we want to play. If that's the case, then we don't need to change the stream or tell it to play. We can just return the tween finished signal that is returned by fading the volume. If a different track is already playing, we should fade out that track before switching to this one. Wait for the twin to finish, then proceed with the rest of this function. Note that this will now be performing two executions of fad volume, each within 1 second duration. It will take 2 seconds to change tracks as a result. Let's make this more flexible by exporting the duration like we did with the FAD and give it a default value of 1 second. Then allow the play track and fade out functions to accept an optional duration parameter with a default value of the exported variable. Passing the duration parameter to the fade volume function. We can use it in the tween method call as an argument. Taking a look at the game and title manager scripts, O on new game pressed and on exit pressed functions are looking pretty similar now. Let's write an inherited method for changing scenes in our scene Manager script. Named change scenes. We can tell the music to fade out. Wait for the Fade to fade to black, unpause the game if it is paused, then change the scene of the tree to a file. Passing the file path as an argument. In order to get the results we are expecting, we will need to make sure that the signal being awaited is the one with the longer duration. The await statement must also be the last one if we want all the tweens to happen in parallel. If for any reason, you need to reorganize the order of these statements so that the signal being awaited is not the one returned, you can also store it in a variable and await it on a different line. Now, the title manager can do all of this by calling its inherited change scene method, passing the game scenes path as an argument. Likewise, the game manager can also do this changing to the title scene. Also, don't forget that subclasses can always override these behaviors if you want a specific scene to behave differently. We now have background music that smoothly fades in and out with each scene in our game. In the next lesson, we'll add a settings menu for changing the game settings. I'll see you in the next lesson. 7. Settings: Hello, friends. In the previous lesson, we added background music that gently fades in and out. In this lesson, we'll add a settings menu to our game. Let's start in the title scene. Unlike the buttons and menus we've created so far, which are just floating in front of everything, I would prefer the game settings to be enclosed inside a panel. There are two different control notes we can add to our scene, which behave differently. A panel is just a basic window that we can resize as we want and rearrange its children in any fashion. A panel container will automatically resize itself to encapsulate its children, similar to a horizontal or vertical box container. Both have advantages and disadvantages. I like to use a panel container to save me the time and effort of sizing and reorganizing child nodes while I'm building out my user interface. But I might switch to a panel if I want more flexibility when it comes to polishing the finished project. Since our settings class has some Boolean variables. We can add either a check box or a check button for each variable, allowing the player to set their value to true or false accordingly. Let's add one for camera invert x and another for camera invert. I'll add one of each, so I can see what they look like and decide which one I like better later. The volume setting is a float variable, which is often controlled in menus by a slider. Since a slider will inherently enforce a minimum and maximum value. Each of these settings will also need a label node to tell the player what they're for. Much like we've used horizontal and vertical box containers to organize nodes automatically. We can also use a grid container to automatically organize the nodes into a grid pattern. The grid nodes only property is the number of columns in the grid. Rows are automatically added to and removed from the grid container to accommodate the number of children it has. Setting this to two, we can easily organize all of the label nodes into the left column and the interactable control nodes on the right side. The grid container will compress all of its children as much as it can. But we can specify minimum sizes for any of them. I'll give the volume slider a minimum x value of 100 pixels, which forces the right column of the grid container to expand. Now I think the check boxes would look better centered within the column. Expanding the layout section and the container sizing subsection, I'll set the horizontal value to shrink center. Now the check box is centered horizontally within the column. And I'll do the same for the check button. Now that we can see our slider, let's take a look at its properties in the inspector. We can set its minimum and maximum values, as well as the step value, which is a distance between values to which the slider can be set. Using our linear volume settings, the minimum value should be zero. A maximum value of one is fine as one in linear terms will equate to 0 decibels. But we can also allow the volume to go above this. Since we know that the maximum decibel value of the audio stream player node is 24 decibels. We can actually type built in functions into this field, using db to linear, passing 24, we get 15.849 is the actual maximum value. But this may cause a decrease in audio quality. Setting the maximum linear volume to one is fine for most cases. Something as fluid as volume can usually be adjusted to a very small degree. Since my slider is 100 pixels, I'll set its step value to 0.01 with each pixel representing a 1% change in volume. We'll also need a title label for this menu. And a button that closes it. But these don't belong as part of the grid. We can sort the title grid container and close button inside a vertical box container. The title label and closed button are stretched to fit the same width as the grid container. I'll center the title using its alignment property. The button can be set to shrink begin to put it in the lower left corner. Shrink center to center it or shrink end to put it in the lower right corner. If you don't want to use these containers or find them too restricting, you can always use a normal panel and manual we position each of the child nodes to get the arrangement you want. We can reuse the theme resource for our settings menu if we want, but you may want to use different button styles for different parts of your game. In that case, you can easily create a new theme resource. I'll just add a panel container setting to the existing them. Change its style box to a texture. And give it some content margins of 16 pixels. The check boxes are inheriting their styles from button, so we can override that by adding a check box to the theme and replace all of its style boxes. I'll just use empty style boxes. Then repeat the process for the check button. Okay. I think the title should have a larger font size than the other labels. I'll override its font size in the theme override section. Now that I've seen both the checkbox and check button and can compare them in the context of the menu. I think I prefer the checkbox and I'll switch the camera invert y to match. With the menu built, let's anchor it to the center of the screen. We've already written a menu script that handles showing and hiding a control node and can also give focus when a menu is opened. Let's attach this to the settings menu node. And set its default focus item to the first menu item, the camera invert X checkbox. But in order to connect the control signals to our script, it will need to be a different script than the ones used by other menu. We can give the manuscript a class name then create a new script in the UI scripts folder, inheriting from menu. Let's call it settings menu. Dragging this script onto the settings menu node, it replaces the manuscript. But we will need to repopulate the default focus item. In our new script, we will need to initialize each of our control nodes to match the values that are already inside the settings resource. So we'll need to grab references to each of our control nodes using At on ready. Then in the ready function, we can set the values to the matching variable in the file settings resource. With our setting controls sorted into the menu and initialized. We can now connect signals from each control node to the settings manuscript. Calling a function anytime a setting has been changed by the player. The check box and check button nodes will connect the toggled signal, telling us whether it's set true or false. And the slider will connect the value changed signal, giving us the new value it was just set to. We can set the values of the variables inside our file dot settings to match any of the values that have been changed using the control nodes. Since the camera controls are reading directly from the settings to determine how it functions. No further actions are necessary to get these settings to work. But the volume setting is not going to affect the music node automatically. We will need to adjust its volume setting manually. When the volume setting changes, we can call linear volume passing new value as an argument. Let's run this scene and try adjusting the volume setting to hear the immediate difference with music playing. A completed game will likely have more audio nodes, each with their own volume setting. We may not want to adjust them all individually from inside the settings menu. To anticipate this need, we can emit a signal here to tell the entire scene that the volume setting has been changed. Then any node that is listening for this signal to be emitted can react to it. At the top of the script, we can declare signals the same way we declare variables, using the keyword signal. Let's name volume changed. It's conventional to name signals in past tense, stating what it is that happened that other scripts should react to. Similar to a function, we can add brackets to the end of the signal declaration to add parameters to it. We can not only emit that the volume was changed, but also emit the new volume value as a float. When connecting this signal to a function, the receiving function should accept a float parameter to match the signal. Next, let's connect the closed buttons pressed signal to the menu classes closed method to close the menu. Most games will allow changing the settings from both title and game scenes. Let's save the settings menu branch as its own scene. Then copy the settings menu node and paste it into the game scenes I. It's always a good idea to make sure the fade node is in front of everything else, so I'll sort the settings menu above it and set its visible property de false. We can easily add a settings button to the pause menu. Since both scenes have the settings menu, much like the Fade, we can export a variable from the scene manager script, so both the title manager and gain manager can use it. And in both scenes, the settings menu is accessed from another menu. Either the Title scenes main menu or the game scenes pause menu. We can create a very simple Breadcrumbs implementation within our manuscript, so anytime a menu is opened from another menu, closing it will return to the previous menu automatically. In our manuscript, we can declare another variable. Let's call it underscore Breadcrumb of type menu. Then add an optional parameter to the open function also called Breadcrumb. If breadcrumb is anything other than null when the menu is opened, then we should save it in the variable, and close that menu before opening this one. Then when the menu is closed, if the breadcrumb is not null, that menu should be opened after closing this one, then it can be set back to null. Both the title manager and game manager scripts can now open the settings menu, passing the menu buttons or pause menu as the bread crumb. Opening the settings menu scene. Let's make sure that the default focus item is set and that these nodes will process always even when the game is paused. Let's try running the game. Changing the game settings, and switching to the game scene. Both the volume and camera controls remain changed, and we can change them again from the pause menu. We now have a settings menu that can change the volume and camera controls in real time. In the next lesson, we'll add transition events for moving our character between different levels. I'll see you in the next lesson. 8. Exit: Hello, friends. In the previous lesson, we added a settings menu. In this lesson, we'll detect when the player enters a doorway and get ready to transition to a different level. Let's start in whichever level is currently loaded into the game scene. For me, that is a room three. There are two doorways leading out of this room. When the player enters either of these doorways, they should transition to a different level of my game. In a similar way that our character body is colliding with the floor static body, we can detect collisions with empty space to trigger something to happen. The node that does this is called an area three D node. And just like a physics body, it requires a collision shape before it can work. Let's add a collision shape three D node and make it a box shape. To make it fit with the size of my floor tiles, I'll make it 4 meters in length width and height. Let's rename the area three D node to transition. Then make it its own scene by clicking and dragging it into the scenes folder in the filesystem tab. Then open the new transition scene for editing. I'd like to have the transitions origin rest clearly on the floor. We'll move the collision shape up along the y axis, half of its height of 4 meters, which is 2 meters. In order to react to collisions with the player, the transition node will need a script. Let's make a new script by clicking on the scroll icon. Okay. Make sure it is saved in the scripts folder. The default name and inheritance are fine. The area three D node has a bunch of different signals for reacting to collisions. Since our character body qualifies as a physics body and we want to react to the character entering this area, the signal we want is body entered. Connecting this signal to the transition node itself creates the on body entered function, which accepts the body that entered this area as a parameter of type node three D. We can see the types of the parameters in the list of signals. For now, let's just print body to see our collision work. Running the game scene, entering the transition area, name of the character body three D note is printed, but also the names of static body nodes in our scene. We don't want just any physics body entering this area to trigger a reaction, only the player character. We can check if the body is of a certain class. Or check the node's name to see if this is the player character. But those solutions aren't very flexible. An easier and cleaner method is to make sure only the player character can actually collide with this area using collision masking. First, let's open the character scene and select the character body three D node. Looking under the properties inherited from collision object three D, expand the collision section. There are two sets of numbers here going all the way up to 32. These are collision layers, which we can use to control which objects in our game can collide with each other and which can't? So far, everything in our game exists in the default Layer one, and masks or collides with only Layer one. Since layer one is the default and everything collides with it by default. Let's have layer one be the game's terrain. The way these layers are displayed in blocks of eight, I like to think of each block as layers that are grouped together. The first eight layers of my game might be reserved for the world or environment layers. Our character can exist on a different unique layer. Let's use layer nine as an example. This way, the entire second block of layers can be reserved for collision layers related to the player. Opening the project settings, in the general tab, under layer names, we can change the names of each of these 32 layers that exist for three D physics. I'll name layer one terrain and layer nine player. Hovering over the layers in the inspector will display their name. In the transition scene, since nothing needs to be able to detect or collide with our area, it actually doesn't need to exist on any layer. Feel free to set aside a collision layer for transitions if it helps you though. The transition only needs to have a collision mask to detect collisions with the player. Turning off layer one and only masking layer nine, the player. We can further enforce this by changing the properties of the area three D node, telling it to monitor for other physics bodies, but not be monitorable by other physics bodies. Now, the only possible way that this area three D can trigger a collision is if it detects a physics body on layer nine. It won't look for any other layers, and it will be invisible to everything else. The transition area can be positioned to cover the empty space beyond the doorway, making it impossible for the player character to exit this room without colliding with it. Opening all of my different level scenes. I can see that this transition is meant to connect to Room one. So let's name it two room one. Duplicating the node will automatically rename the duplicate to two room two, and I can reposition it to the other door. T While my small levels, each only have two transitions. You can imagine how a large complex level might have many more that are hard to keep track of. So we should group these nodes together to sort them inside the scene tree. Let's add a new node, just a normal node, and name it transitions. Then re parent the transition nodes to it. This will make them easier to find and use not only in our scene tree in the editor, but also from our scripts later. We can copy and paste these nodes into our level scenes and reposition them to cover every doorway. Renaming them so that we know where they lead. Opening up the progress script, we can change the variables or add new ones to store the name of the level the player is currently in as a string. I'll initialize it to be Room one. For this method to work is intended, the value of this variable must be the exact spelling of the scene name of the level in the file system tab. In the transition script. We can then set this variable as the player transitions between levels. Let's export a variable to hold the name of the level this transition leads to as a string. Then when the character body enters this area, we can set the value of file dot progress dot level. To be the level name. Next, we'll want to tell the game manager to switch to this level. Like we did in the player script, we can always access the scenes root node by starting our node path with dollar sign slash root, then get the game manager with game. Let's just tell the game manager to call a function we haven't written yet named Load level. Since the name of the level is already stored in the progress resource, there's no need to pass it as an argument. Since the only time we're trying to access the game manager is in this one singular instance, there's no need to store it in a variable or use add on ready. Especially since logically, only one transition event can possibly happen per level loaded into the game. So every transition declaring the variable and accessing the game manager when only one actually needs it would be more wasteful. In the game manager script, let's first grab a reference to the level that already exists in the scene. We can click and drag the node into the script to automatically produce its node path, or even hold down the control or command key while we release the mouse button to automatically store it in a variable. I'll rename the variable to current level. Then declare the load level function we called from the transition script. First, we'll need to know if there is already a level loaded by checking if this variable contains a value or if it is null. If it does contain a value, then we should first await f to black. We can then unload the current level from our game scene using the built in function Q. We'll go overloading the next scene in the next lesson. For now, let's just await Fate to clear and try it out. If the player enters the doorway, the scene fades to black. The current level is removed from the scene tree, and then we fade back in to see our character and free fall since there is no longer any level. Our Debug panel is giving us two warnings. We've declared a variable that was never used in the script, and there's an unused parameter in our collision function. We can prefix unused parameters with an underscore to flag them for the engine so they can be ignored. Switching to the transition script, the body parameter is no longer used. We can add the prefix to the name of the variable to satisfy this warning. In the scene Manager script. We have declared the settings manu variable in this script, but it is not being used inside this script. We have done this on purpose because the settings many variable is inherited and used by all of this class's inheritors. We have no intention of ever actually using the scene manager script directly, but are using it to contain all the similar properties and behaviors of a group of related scripts. In other languages, this would be known as an abstract class. This pattern of using inheritance in this way is known in object oriented programming as abstraction. We can choose to ignore any warning by adding another line before the line that is triggering the warning using at warning ignore. Then specify the warning we want to ignore. In this case, we have declared an unused private variable. With both debug warnings addressed, running the game will no longer present any warnings. We now have the current level unloading when the player enters a doorway. In the next lesson, we'll load the next level and position the player in the corresponding doorway on the other side. I'll see you in the next lesson. 9. Enter: Hello, friends. In the previous lesson, we had the player exiting the level through a doorway. In this lesson, we'll load the next level and position the player inside it. Before loading the next level, we have first checked if there is a current level and if so, we are unloading it. We can then assign a new value to the current level variable since it is now empty. Using a built in function load, we can load any resource from our file system tab, including scenes by specifying a file path as a string. To keep our scenes better organized, let's create a sub folder inside the scenes folder named levels. Then put each of the games levels inside this folder. Selecting any of the level scenes, we can click and dragon into the load functions brackets to populate it with the file path. Since all of our games levels are located in the levels folder, and they all end with the dot TSCN extension, we can separate these parts of the string using the Append operator, the plus sign. Then replace the name of the level scene with the ones stored inside the progress resource. The load function returns a resource. But the current level variable is a node three d. We first need to call a function on the resource to turn it into a node, dot instantiate. Then add it to the scene tree with the function add child. Since this is the game manager script attached to the game scenes root node, the level node will be added as a child of the game node. But what about when the game first starts? Or if the player loads a safe file? We can start our game scene without a level node in it. Deleting the level node from the game scene, We can remove the add on ready from the current level variable. Let's override the ready function inherited from Scene manager and call load level right away. Before running the superclass definition from Scene Manager. This will allow us to load any level in our game, simply by setting its file name inside the progress resource and calling load level. It will cleanly transition between levels by first fading to black and unloading the current scene, then loading the next level and fading back in. If this is the first time a level is being loaded and there is no current level, it will skip that step and immediately load the level. But we will need to position the player inside the new level and also make sure the position is tied to the path they entered the level from. Let's start in the transition scene, adding a new node which does nothing more than simply marking a position in three D space, a marker three D node. The only difference between a marker three D node and a node three D is that the marker will draw a Gizmo and the editor showing where it is. Let's rename this node entrance and move it forward along the Z axis, so it is outside the area node and far enough away that the player character will not collide with the area. In the transition script, we can drag this in and hold control or command to add it as a variable without ready. This will be the position where the player will be spawned into the level when entering through this transition. In our level scenes, we can rotate any of our transitions to point the Z axis and the entrance marker to an appropriate spot inside the level. If for any reason, you need to move an individual entrance marker without affecting other transitions, you can always right click on a transition node and toggle on editable children. This will allow you to move a specific entrance marker to account for obstacles or variations in floor height, for example. Before we can figure out how to position the player, we will need the level scenes to keep track of their transitions with the script. Let's add a new script to the levels root node named level in the scripts folder. If we drag in the transition node, we can store it in a variable with add on ready. But we don't want this node. We want all of its children. Using a built in function get children, we will store a list of all the child nodes to this transition node in an array of nodes. The order of the nodes in the array will be the same as the order in the scene tree. We can access the contents of an array by specifying an index number starting from zero. Let's write a function in our level script that gives the transitions index number and returns coordinates where the player character should be placed. Let's call it get entrance, accepting the transition index as an integer parameter. And returning a vector three, the position in three D space for the character to be placed. We can access the transitions array, putting the index number in square brackets. If the index number is zero, then that will give us the top node, followed by one, two, et cetera. Next, we'll get the entrance marker from the transition and get the global position property of the entrance marker three D node. Since the notes position is relative to its parent. We want to know the global position as it exists within the entire scene, so we can return this. We will need to attach the level script to the root note of every level in our game. There's also a possibility, however, unlikely that when loading the level before repositioning the character, the character just happens to already be inside a transition area. In the transition scene, we should disable the monitoring property by default. Then in the level script, when a level is loaded and the character is positioned properly, we can call a function to activate all the transitions. A very useful feature of arrays is our ability to iterate through each of their elements using a loop. Starting with the keyword four, we can specify an alias, we will use inside the loop to refer to the current element. Followed by the keyword in, then the name of the array and a colon. Anything we put inside the loop block will run on each element of the array, and we can refer to the current element using the alias. For each transition in transitions, we can set its monitoring property to true to activate all of the transitions in this level. In the game manager script, we can grab a reference to the player character. Then when a level is loaded, we can position the player at the levels entrance. Let's use zero as the argument for now. Now that the character has been positioned, we can activate all the transitions in the level, since we know that the character is not touching any of them. Finally, we need to set the values of every transition in every level in the inspector, so each transition knows which level it connects to. Running the game scene, the game now starts in room one, and the player is positioned in front of the doorway. The top child of the transitions node. Enering the any doorway, the level is unloaded, and the game scenes, which is to the correct level. But no matter which doorway we pass through, the player is always positioned in front of the same doorway. Let's add another variable to the progress resource named transition ID of type int. Then also add this variable to the transition script exported. When the player character enters this transition, we can set the value inside the progress resource to match the exported variable. And in the game manager script, use this as the argument to select the transition where the player will be placed. Starting in Room one, let's take a look at the transition to room two, which now has a transition ID variable with a value of zero. This will be the index of the transition node that returns to the scene from room two. We can see that the transition to Room one is the top child node, which is index zero. So that's correct. Taking a look at the transition from room two to Room three. Let's switch to the Room three scene, and we can see that the transition from Room three to room two is Index one. So we will need to change the transition ID of the transition from room two to Room three to one. And the transitions leaving room three will also need to be changed to one. Running the game scene, we can now run between all of our levels, both clockwise and counterclockwise, and the player is positioned correctly every time. If your levels have many transitions, I recommend setting a convention for your game on how you organize your transitions, such as clockwise from North, for example. You may also want to change the index number to a string and organize your transitions into a dictionary instead of an array. I would also like to make sure that both the character and the camera are pointed away from the transition that the player enters a level from. In the level script, just like we returned the entrance global position from a function, let's also return the transitions rotation from another function. Now, the game manager script can access this function to determine which direction they should be facing. We can pass this information to the player script and use it to rotate both the character and the spring holding the camera, calling a fiction, passing the returned rotation as an argument. Pase direction, accepting the y rotation as afloat. Can easily set the spring arms rotation to match. But the spring arm must be rotated 180 degrees to be behind the character. Since the rotation is measured in radians, that means we can either add or subtract Pi from this value to point the camera in the correct direction. We can then pass this rotation value down the chain to the character class. And add another function to rotate the character rig to immediately face the desired direction. Let's try it out. Even if we position the character and camera at weird angles before entering the doorway, they will both be facing away from the doorway on the other side. This will help the player understand which way they came from. We now have the player able to transition between levels and our game scene. In the next lesson, we'll save and load the players progress. I'll see you in the next lesson. 10. Save: Hello, friends. In the previous lesson, we completed our level transition process. In this lesson, we'll save and load the players progress through the game. Our file script has multiple variables containing custom resources we used to keep track of the game settings as well as the players progress. Let's start with the settings resource. In the ready function, we are creating a new settings resource, but we should only do that if one doesn't already exist that we can load instead. The I condition will first check if the ceti resource exists, and if it does, load it, else, create a new one and save it right away. This line will actually be the else block of an IF statement. Godo allows us to save and load any resource using Singleton classes. The resource loader can load our resource, calling the load method, passing a string argument, a file path. Instead of accessing a resource within our project, this time, we want to load something from the user's system. The file path starts with user Colon slash. The Godo engine will use the shortcut to find an appropriate location on any system to save and load files unique to each user. Let's name the file settings and give it an extension of RS for resource. This load function returns a resource, which we can assign to our settings variable. Before loading the settings, we can perform a similar function to first check if the file exists. Since the file path is now written twice, we will also be using it more too, and this is a value that should never change. I would be more efficient to declare it as a constant. If the settings file doesn't exist, then we can create it. And immediately save it using the resource saver class, calling the save method. The save method requires a resource to save, which is our settings resource, and the file path to save it to, which is the settings path. Now when running the game, if the settings exist for the user, then they will be loaded, and if not, they will be created. But we also need to make some changes to the settings menu. All of our settings need to be set to the values that were loaded, which they are in the ready function. We have set the initial slider position of the volume setting using the numbers stored in the settings resource. But we also need to set the volume of the music node and emit the signal here like we did below in response to the slider value being changed. When the player opens the settings menu, adjusts some settings, then it would be a good idea to save those settings when the menu is closed. We can override our menu classes close method, so when the settings menu is closed, we will tell the file auto load to save the settings. Back in the file auto load, we can add the function that saves the settings. The progress resource on the other hand, will not be handled in the ready function. We can separate each of these methods into public functions for accessing the progress resource in a variety of ways. Checking if it exists, starting a new game, and loading. Using the same format as our settings, we can declare a save path constant. The safe file exists function, will return a Boolean, returning the same value returned by resource loader do exists. Passing the save path as an argument. Creating a new progress resource when new game is called. Saving the resource when saved game is called and loading the resource when load game is called. In the title scene, we can now easily create a new progress resource when new game is pressed. And load the existing safe file if continue is pressed. It would be good UI design to have the continued button disabled b and only enable it if there is a safe file to load. Let's grab a reference to the continued button using add on ready. In the ready function, if a safe file exists, we can enable the continued button by setting its disabled property to false Then also tell it to grab focus. That way, the default option will be new game the first time the game is played and continue every time after that. All we need to do is decide when to save the game. Since this file script is an auto load node, you can easily call the save function to do this from the pause menu or save point object in your game. I'll just have my game automatically save every time the game manager unloads a level. Back in the title manager script, let's also complete the exit function. Like we fade in when the game starts, we can await fade to black before exiting. Quitting the game is a built in function of the scene tree, which we can access with get tree, and simply call the Q function. In our custom resource scripts, we will need to add a export to the front of any variable declarations we want to be written to the Safe file. Any variables we don't want to save can just omit the export tag. If, for example, you are using the safe point method common to JRPGs, the variable saved in the safe file would be an ID number associated with the safe point, so that would be exported. But the variables containing the current level and transition ID would not need to be saved in the safe file, since they are not needed to load the game, but are still needed to transition between levels. So they would not need to be exported in that case. In my game, I will need to export these variables, since I am automatically saving my game with every level transition. One final note in the file auto load script. Using the dot RES extension, we'll write a safe file as a binary file, making it difficult for the user to access. Adding a T, making the extension TREs for text resource, we'll write the safe file as a common text file, which can be viewed and edited in any text editing software. Both are acceptable formats. I'll save the settings as text and the progress as a binary file. Let's try it out. Running the game, the continue button is disabled, but we can start a new game. In the game scene, I'll run into a different level, which should save my game. Pausing the game, I'll change some of the game settings. Then exit the game, returning to the title scene. Now the continued button is active, since the safe file exists to load. But let's exit the game first, which fades to black and closes the game window. Now, I'm running the game again. This time, the continued button is enabled, since our safe file persisted between play sessions. Continuing our existing game, we start in the other level, and the game settings are also the same as we left them. A. Now, let's take a look at the files that were created on my hard drive. The settings file can be opened in notepad. We can see the exported variables and their values clearly and even edit them and save the file. Next, let's open the save file containing the players progress. Most of this information is. Even if we were to edit something and save the file, Attempting to load the saf file will crash the game since it is no longer formatted correctly. Let's run the game one more time and see that our settings file, which we manually edited a notepad, is loaded, and the values are correct. So saving resources in binary format is more secure and text resources are very easily edited. In my opinion, it is often more beneficial for ND developers to be able to troubleshoot save file editing with your players than to hide progress data to prevent cheating. We now have the players progress, saving and loading between play sessions. In the next lesson, we'll wrap up with displaying the game's credits. I'll see you in the next lesson. 11. Credits: Hello, friends. In the previous lesson, we saved and loaded the players progress. In this lesson, we'll display the game's credits. Let's start by creating a new scene, the credit scene. Since this is typically just a black background with white text, I think that a user interface node makes the most sense as the root node. Let's give the root note a script and call it credits Manager. Inheriting from Scene Manager and sort it into the manager scripts folder. We can copy the F note from any other scene and paste it into the credit scene. Then assign it in the inspector, along with adding a music track for the credit scene. In the title manager script, we can now set the behavior of the credits button in the main menu to change to the credit scene. We should also save the credit scene in the scenes folder. Then in the credits Manager script, let's add a function that returns back to the title scene. In the input function. We can check if the player has pressed a specific button. I'll just reuse the jump button, and if so, return to the title scene. Our scenes are now connected and can transition back and forth. Most games that are still in development will have the credits accessible from the main menu since the end of the game is yet to be completed. So there will be no way to access the credit scene by completing the game. Having your credit scene included throughout the development of your game also helps keep track of all who make a contribution to it throughout its entire life cycle. Speaking of which, credits are usually just a series of text labels organized vertically, slowly scrolling upward. So adding a vertical box container to the scene, let's name it scroll. And have it anchored to the bottom of the screen. But with the wide setting. Now the left anchors are both in the bottom left of the screen and the right anchors are both in the bottom right of the screen. This is typically where credits will originate from. Credits are often broken down into categories or job titles, followed by a list of names of contributors in that category. So inside our vertical box of all the credits, we can add more vertical boxes to contain each category. I'll call this one game design. Inside the category, there should be a label for the title of the category. And I'll have it say game design. Credits are typically aligned to the center. I'll make the font white. Size 64, and use the fancier of my two fonts for category titles. Let's duplicate this label no to add another label for our name. Then reduce the font size and change the font to one with more emphasis on legibility. We are now listed as the game designer in our games credit scene. But the credits are starting inside the game window. They should start off the bottom of the screen. Let's switch back to the scroll vertical box and change its anchor presets to custom. This will keep the anchors where they are, but allow us to change each setting individually. We want the grow direction of this control element to go down, not up, changing the setting from top to bottom. Let's collapse and duplicate the game design category to create our next category, game development. Since all of the settings are duplicated, we only need to change the names of the nodes and the text properties of the label nodes, and also add any additional names to each category as required. And repeat this process to continue adding as many categories as you need for your game to make sure everyone involved is credited. I'm also going to give credits to the artist who made the character models, animations, and environment models, K Laberg. Penzila, who created the user interface assets, and Eric the Funny Baron, who produced all of the music. And finally, end with a thank you message to the player. I'll also make the thank you message larger. Our credits are all here, but they're all cramped together and difficult to read. Let's add some separation to the vertical box container to separate the categories. I'll set each category 256 pixels apart from each other to give them lots of space. And we can see that the credit scroll will get very long very fast. The last thing I want to do is make sure that the thank you message is displayed on its own at the end. So I'll give it a custom minimum size y value matching the window size setting of my game, 720 pixels, and center the text vertically within this space using the labels vertical alignment property. Back in the credits Manager script, Let's export a variable for the scrolling speed and give it a default value of something like 32 pixels per second. And grab a reference to the scroll using add on ready. Then in the process function, which takes Delta as a float parameter representing the seconds that have passed since the last frame, change the y position of the scroll, subtracting speed times Delta. Since when working in two dimensions, zero is at the top of the screen, and moving something up is moving in the negative direction. We then need to stop the scrolling once the thank you message reaches the screen. Looking in our two d view, selecting the scroll and exposing the transform position value in the inspector, we can move the scroll up until it reaches the desired position, where only the thank you message is displayed. Taking a look in the inspector at the transform, we can see that the y position of the scroll is now equal to the y portion of the size, but is a negative number and plus the height of the screen size 720. Back in the script, we can check if the y position of the scroll has exceeded this value. C hecking if it is less than the negative of size dot y plus the window height of 720 pixels. We can be even more accurate with this calculation by accessing the display server singleton class and asking it for the current window size, then access the y value. If this is true, then the end of the scroll has been reached, and the thank you message is at the center of the screen. At this point, we would like the scroll to stop scrolling. L et's create a Boolean variable called, which will default to false. We can then set it to true when the scroll has met this condition and also set the y position to match this value exactly so it is perfectly centered in case it overshoots the mark. Since we are performing this calculation twice, let's change it to a variable and calculate it using add on ready. Then at the top of the process function, we can check if the scroll is at the end, and if so, return, preventing the scrolling behavior from happening. This works, but instead of just exiting when the player presses the jump button, I would rather have the scrolling speed and only return to the title screen at the end of the scroll. In the input function, if the player presses the jump button, then also check if the end of the scroll has been reached before switching to the title scene. Exporting two new variables, let's call them slow speed and fast speed, both as floats with default values of 32 and 512 pixels per second. The actual scrolling speed no longer needs to be exported, but instead, let's set it to the slow speed using add on ready. We can then set the scroll speed to the fast speed if the player presses the jump button before the scroll has reached its end. And set it to slow speed if they release the button. A Let's try it out. Clicking on the credits button, switches to the credit scene. The credits begin scrolling up from the bottom of the screen slowly. But we can speed it up by holding down the jump button. Once the thank you message has been reached, the game will wait for a new press of the Jump button to switch back to the title scene. And that's it for the essentials of game development. You now have a fully function skeleton project that could be used to develop a game of any genre. 12. What's Next?: Welcome to my course on Dialogue and event Systems in Gado. This course is a continuation of game development essentials in Gado but can be followed and applied to any project that involves a character that the player can control to interact with NPCs or objects by pressing a button and displaying dialogue. You're welcome to join our discord server to work on this course alongside your peers. In this course, we will cover the creation of dialogue boxes, events, and interactions. Then tie them together with progress flags, camera controls, and character animations. When you're done, you'll have a comprehensive dialogue and events system for your game that can be used to produce high quality cut scenes and complex branching narratives that react to players choices and allow them to progress through the game. You'll also learn useful skills for working with the Gada game engine, organizing and designing your projects to be more scalable. You will be learning how to code with GD script with everything explained in detail. We will apply object oriented design principles in our scripts, inheritance, encapsulation and abstraction, alongside other software engineering design patterns like Singleton and Composite pattern, to keep them organized, customizable, and reusable for a project of any size. All of the project files are also available on Github, if you need to review the project as it was after completing each lesson. These videos were recorded using Gadot version 4.2 0.2. The project starts with assets from K Kits Character and Dungeon remastered packs made by K L auberg and basic Guy bundle made by Penzla. All are available to download for free on dot IO.