Build a Complete Pixel Platformer in Godot 4! | Thomas Yanuziello | Skillshare
Search

Playback Speed


1.0x


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

Build a Complete Pixel Platformer in Godot 4!

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:23

    • 2.

      0-1 Introduction to Programming

      8:03

    • 3.

      0-2 Constants & Variables

      9:11

    • 4.

      0-3 If Statements & Conditions

      9:46

    • 5.

      0-4 While Loops & Operators

      9:23

    • 6.

      0-5 Arrays & For Loops

      10:32

    • 7.

      0- 6 Stacks & Functions

      10:53

    • 8.

      0-7 Match & Return

      9:34

    • 9.

      0-8 Scene Tree & Inheritance

      10:21

    • 10.

      0-9 Abstraction & Encapsulation

      10:41

    • 11.

      0-10 Polymorphism

      8:01

    • 12.

      0-11 Dictionary

      8:54

    • 13.

      0-12 Debug

      9:08

    • 14.

      1-0 Setup

      10:21

    • 15.

      1-1 Character

      6:44

    • 16.

      1-2 Input

      8:58

    • 17.

      1-3 Locomotion

      8:32

    • 18.

      1-4 Jump

      6:45

    • 19.

      1-5 Animation

      5:53

    • 20.

      1-6 State Machine

      6:05

    • 21.

      1-7 Effects

      10:21

    • 22.

      2-1 Tilemap

      6:07

    • 23.

      2-2 Decorations

      6:17

    • 24.

      2-3 Camera

      9:04

    • 25.

      2-4 Tween

      7:07

    • 26.

      2-5 Background

      9:55

    • 27.

      2-6 Water

      11:16

    • 28.

      2-7 Boundaries

      9:09

    • 29.

      3-1 Data

      8:07

    • 30.

      3-2 Coins

      8:57

    • 31.

      3-3 User Interface

      9:01

    • 32.

      3-4 Lives

      10:24

    • 33.

      3-5 Chest

      10:20

    • 34.

      3-6 Lock & Key

      10:02

    • 35.

      3-7 Map

      10:10

    • 36.

      4-1 Damage

      9:55

    • 37.

      4-2 Reaction

      9:59

    • 38.

      4-3 Recovery

      9:51

    • 39.

      4-4 Checkpoint

      9:30

    • 40.

      4-5 Death

      10:05

    • 41.

      4-6 Enemies

      10:27

    • 42.

      4-7 Game Over

      13:17

    • 43.

      5-1 Sword

      11:24

    • 44.

      5-2 Attack

      12:03

    • 45.

      5-3 Air Attack

      9:43

    • 46.

      5-4 Patrol

      9:28

    • 47.

      5-5 Aggression

      9:45

    • 48.

      5-6 Projectile

      14:01

    • 49.

      5-7 Boss

      13:52

    • 50.

      6-1 Pause

      8:59

    • 51.

      6-2 Title

      9:49

    • 52.

      6-3 Level Select

      9:19

    • 53.

      6-4 Save

      8:40

    • 54.

      6-5 Unlock

      10:35

    • 55.

      6-6 Music

      9:43

    • 56.

      6-7 Export

      7:33

  • --
  • 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.

371

Students

1

Projects

About This Class

Learn how to build a complete pixel platformer in Godot 4 by following along with this course!  Whether you are new to game development, new to the Godot engine, or want to improve your skills with some high level design principles, you will learn a lot here!  The beginning of the course focuses on how to write scripts and the GDScript language.  If you're already familiar with Godot and GDScript, you can skip over these lessons and jump straight to the Setup lecture.

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

Each section of the course generally focuses on 1 aspect of the game; Character, Levels, Treasure, Enemies, etc.  The sections are further divided into 7 video lessons, each focused on teaching 1 feature of the Godot engine, 1 script, or 1 specific part of game development.  By the end of each section, you will have a template for building the various aspects of your game.

There is an assignment you will need to complete before proceeding on with the rest of the course, repeating many of the lessons taught throughout the section to implement more of the game assets, while also providing extra challenges for those who want to try them.  The challenges are optional and are not required to proceed with the lessons.

This course includes scripting in the Godot scripting language.  If this is your first time using scripting, you're welcome to follow along and I will explain individual items as we go.  To avoid overwhelming new students, I will try not to explain everything all at once, but focus on individual elements that are relevant to each lesson.  If you have experience with scripting in other languages, Godot script is extremely easy to pick up and you will be able to appreciate how well it is optimized for the engine and game development in general.

The assets used in this course are available for free on itch.io and FreeSound.org.

Meet Your Teacher

Teacher Profile Image

Thomas Yanuziello

Indie Game Developer

Teacher
Level: Intermediate

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: You've started learning god. You've taken tutorials and have made smaller projects, but you're ready to take it to the next level and create a full game with professional level, code, structure, and design. This course will teach you how to build a complete pixel platform from the ground up and how to build a scalable game with reusable code that can be applied to games of other genres. You will learn how to build a character that the player can control and design levels, track the player's progress through your game and respond at checkpoints, create a combat system with enemies and a boss fight, and learn scalable design principles for Gadot that you can apply to any Gadot project. When you're done, you'll have a template of a complete game that you can populate with more levels, more mechanics, more items, and more enemies. If you need any help, our discord server is full of other students and game developers who can answer any questions you may have. Click the website link and my profile to join. We will be starting with a blank project in Godot version 4.2 and using free assets from its dot IO. But you're welcome to follow along with your own project using different assets. Additional notes and videos have also been added to update new features in Godot version 4.3. Let's get started building your first complete game. 2. 0-1 Introduction to Programming: Hello friends. If you haven't done so already, you'll need to download the GdoGameEngine from gdongine.org. The engine is free, but you can donate to support the project if you want to. There is no installation process. You can just extract the zipped file and open it. Be sure to relocate the executable to a better location. The initial launch window is a list of your current projects. But if you don't have any projects yet, you'll be prompted to explore demo projects. We can ignore this and just create our own new project either by clicking on this button in the project list or the Create button at the top of the window. Here we can give our project a name, which would typically be the name of your game. I'll just put intro to programming. The project needs to be stored on our computer's hard drive, and we'll create a new folder with the same name of the project. By default, it wants to store everything in the documents folder, but it would be better to create a new subfolder for Godot projects. The renderer changes how certain two D and three D objects are rendered, but we won't be drawing anything, so we can ignore these options. The renderer can also be changed later. And version control compatibility with Github is included by default if you want to use it to backup your project or share it with others. When you're ready to start, click Create and Edit. The GDOEditor window will open our newly created empty project. The editor is divided into five main docks. A preview of our game is in the center. The lower left dock contains a file browser showing the contents of the project folder we just created. It currently only contains the Gadot icon. The upper left dock contains the scene tree, a list of everything that is in our current scene, which is currently empty, so it wants us to create a root for the scene tree. We won't be drawing anything, so we don't need to specify if this scene is two D or three D or a user interface. So we can just select other node. There are a lot of different nodes we can create, but we are only interested in learning how to write scripts, so we will just use a default node. We can rename our new node by clicking on it after it has been selected or right clicking to open its context menu and selecting rename. Let's name this node Lesson one. Selecting any node in the scene tree will reveal its properties in the inspector, which is docked to the right side of the window. We can see the name of the node that is selected and its properties organized into expandable categories, but none of these properties are applicable to what we're doing. Before we do anything else, we should save our new scene, either by selecting Save Scene from the scene menu or using the shortcut Control S or Command S. This opens a dialogue box where we can specify a name for our scene with the TSCNEtension, and a destination folder. Let's create a new folder for Lesson one, then save the scene in this folder. We can now see in the file system tab that our new folder has been created for Lesson one, and it contains the Lesson one scene, which is marked with the Clapperboard icon. Next, we'll attach a script to the root node of our scene, either by selecting the root node and clicking the attached script button or by right clicking on it and selecting attached script. The language is GD Script, which is the programming language we are going to be learning. Every script will inherit from the node type it is attached to by default. Since the root node is a default node type, our script inherits from node. We are not using a template nor a built in script, and we can specify where this script will be stored within the project. Let's put this in the same folder. Lesson one. When naming scripts, it is important to not be arbitrary, but instead describe the type of object or behavior we are creating through the script. So let's name this hello. Scripts have the file extension dotgD. Then click on Create to create the script. This will switch our preview to script view, displaying our newly created hello script. We can also see our script in the file system tab indicated with a cog icon, and the Lesson one root node has the script icon to show us that it has a script attached to it, which when we hover over, will tell us the name of the script. Clicking on this icon also opens the script if it isn't open already. Our script only has one line, which describes its inheritance from the basic node type using the keyword extends. This just means that our script can do everything a node can do plus anything we write here. It also allows us to override the behaviors of the node that already exist with new behaviors of our own. For example, nodes have a function named ready, but it doesn't do anything. So if we want our script to override this behavior of doing nothing, we can declare our own function of the same name using the keyword funk. Funk is then followed by the name of the function, typically written in lower snake case, which means all lowercase letters separating words with underscores. Many of the functions defined by nodes are preceded with an underscore, and the name must be an exact match to override the behavior. The name of the function must be followed by parentheses and a colon. We'll go over why later. Pressing Enter after this line, the next line is automatically indented by one level. This is how GD Script knows which lines are contained within the function and where it ends. The line is highlighted in red because functions are not allowed to be empty. So it is a good idea to write the word pass to give new functions a body that does nothing. Now that the error is gone, we can see this blue arrow icon appear in front of the function declaration, which is the override symbol, indicating that this script is now overriding the ready behavior of our node. Instead of doing nothing, we want our node to say hello, which we can do with a print statement, replacing the line that previously said pass. The print statement looks similar to a function declaration with a name followed by parentheses because it is calling a built in function. This function requires an argument, which is what goes inside the parentheses. And this argument is what will be printed. Using quotation marks, we can write anything we want, and it will be printed out by our script when the node is ready. Since the script is named hello, the behavior we want to create is for the node to say hello. With our script ready, we can run our game using the run current scene button in the upper right or using the shortcut F six. This will display an empty window, since our game doesn't draw anything, but it also opens up the fifth dock, displaying the output panel. And in our output, we can see our node has printed the words hello world when it was ready. We can end this simulation by closing the window, clicking on the stop button, or using the shortcut F eight. We can change the text that is printed to say anything we want and run it again to see that our node can print out anything we tell it to. We now know how to attach scripts to nodes and run them. In the next lesson, we'll learn about constants and variables. I'll see you in the next lesson. 3. 0-2 Constants & Variables: Hello, friends. We will be starting each lesson by first creating a new folder for the lesson. Then creating a new scene in that folder of the same name. Double click on a scene in the file system tab to open it. With multiple scenes open, we can switch between them by clicking their tabs in the preview doc. Today, we'll discuss the differences between constants and variables using days as our frame of reference. So let's attach a new script to the root node of the scene and name it days. Let's start with constants and declare one at the top of the script using the keyword const, followed by the name of our new constant, which is conventionally written in upper snake case. A constant is like a container where we can store information, but that information is never allowed to change. Something that we would consider to be a constant might be the number of days in the week. Since it can't be changed, it must be given a value immediately, which is why we have an error. We must follow the name with an equal sign, the assignment operator to give the constant a value. The number of days in the week is seven. It is reasonable to assume that it will always be seven and it is the same for everyone. Therefore, it should never need to change its value. Conversely, we have variables, which are also containers for storing information, but ones that are designed to be changed. We can declare a variable in the same way using the keyword VR, then giving it a name conventionally written in lower snake case. This makes it easy to see the difference between constants and variables in our scripts. Something that changes frequently might be the value of today. Unlike constants, variables are allowed to be empty. Let's override the ready function of our base node and print out the values of both the number of days in the week and today. We can see that the number of days in the week is seven, but the value of today is printed as null, which means empty or no value. Let's fix that by initializing today to be Thursday. And we can make our output more readable by adding some context, starting with something like today is then leaving a space after is a plus sign, then our variable. In this case, the plus sign is being used to append two pieces of sentence together. If we try to do the same thing with our constant, however, it will cause an error because our constant is a number, not a word. When we declared our constant, we assigned it a value of seven, which is a number without any decimal points, which in math is called an integer. So our constant has a type of integer. Today, on the other hand, was assigned a value of some characters wrapped in quotation marks. In programming, we call this a string. So our variable has a type of string. The plus operator can only be used when the types of both operands are compatible. We can get around this by using a built in function to change the type as it is being used here to a string, passing the constant as an argument to the function. This will not change the type of the original constant, only how it is being used here within the context of the append operation. And we can continue adding more context after with another appended string as well, remembering to add an extra space at the front. So now we can print out our constant and variable using them in easy to understand sentences. After these lines, let's pretend a day passes. We can add extra context to our scripts that will never be seen by players, but only exists to help us as developers understand our own code or code written by others. These are called comments and are created using the OctathorpPound sign or hashtag. Any text written after this symbol will be colored in gray and won't affect how the script runs in any way. They can be on their own lines or at the end of a line of code. So let's use a comment to explain that we are pretending that a day has passed between the code above this line and the code below. We'll change the value of today to be Friday and print out another sentence. Today is plus Today, which now holds a different value. We can see that the value of today was first printed as Thursday and then changed and is printed as Friday on the next line. The comment had no effect on the script being run. If we try to change the value of our constant, obviously, this will cause an error because constants are not allowed to be changed. If we no longer want to use some lines of code in our script, we can easily change them to comments by highlighting them and pressing Control K or Command K, adding the comment symbol at the front of every highlighted line. Pressing it again will remove the comments. We can specify the type of variable or constant by adding a colon after the name. Followed by the type name, we want to restrict this constant or variable too. Let's restrict our constant to be of type int and today of type string. Other than strings and integers, there are two other primitive types we can use to store basic information. If a number has decimal points, it is no longer an integer and instead a different type called a floating point number, which uses the type name float. Let's add another variable for today's date and give it a type of floating point number with a value of 12.05, which is today's date December 5. And the last type is called Boolean using the shortened name Boole, which can either be true or false. So we'll add another variable for whether or not today is a holiday. I'll restrict this to be a boolean, but I won't give it an initial value. Let's add two more print statements to print out the values of these variables with context. Today's date is plus date, and today is a holiday. Colon plus is a holiday. When we run this now, we can see our date printed out, but is a holiday says false, despite not giving it a value. This is because all primitive types have a default value, but the default value can only be assigned if we specify the variables type. Since we specified that is a holiday is a boolean, it was assigned to the default value for a Boolean, which is false. The default value for both an integer and a floating point number are both zero, and the default value for a string is just an empty string, which is not the same as null, but is a string with no characters in it. If we don't specify the type of a variable, its default value will be null, but it can be assigned a value of any type, and its type can change at any time. Let's remove the type from date. Then give it a new value of December 13 and print it out a second time. The variable starts out being assigned a value of a floating point number, gets used by the print statement, then assigned a string value before being printed out again. This is allowed because GD Script is a loosely typed language. This offers greater flexibility when writing our scripts, but also greater responsibility to avoid type compatibility errors like we saw with the plus operator. It is recommended that you always give your variables a type, not only to avoid errors, but also to improve the efficiency of running your scripts. If the engine knows the type of your variables, then it also knows exactly how much memory it needs to occupy. This also applies to using constants in place of variables. If the engine knows the value can't change, then it can be used more efficiently. In the next lesson, we'll learn about how to control the flow of our scripts. I'll see you in the next lesson. 4. 0-3 If Statements & Conditions: Hello, friends. I've already gone ahead and created a new scene in a new folder for this lesson. Today we'll learn how to control the flow of our scripts to run different lines of code, making choices about whether or not we can see. So let's attach a new script to the root node of our scene and name it vision. We will start our script by overriding the base nodes definition of the ready function. The most basic method of controlling the flow of our scripts is the I statement, which starts with the keyword I. I is followed by a conditional statement which must either be true or false. For now, let's put true, which is then followed by a colon. Similar to the colon at the end of our function declaration, this marks the end of the statement, and continuing to the next line, it is automatically indented another level. Any lines of code following this if statement, which are indented will only be run if the condition of the if statement is true. So let's print out something like the condition was true and then run the current scene to see our print statement working. If we change true to false, we can see that the print statement is skipped over this time. We can add another line after the if statements indented body on the same indent level as the I statement simply with the keyword se followed by a colon. This creates another conditional body that will be run only if the condition of the original I statement was not met. Let's duplicate the print statement and change it to say something different. Since the condition was false, the se block was executed instead of the I block. And if we change the condition to true, the reverse will happen. This isn't very useful if we always know the outcome of the conditional statement to be true or false, but we can replace it with a variable. Let's declare a Boolean variable, which is whether or not the light is on in the room. Booleans are conventionally named in such a way that they imply their use as a condition. In this case, light is on is implied to be true or false based on how it is named. Now our if statement can set its condition to be whether or not the value of our variable is equal to true. When comparing two values to see if they are equal, we use a double equal sign, known as the equal operator, which is different from a single equal sign like we used before as the assignment operator. We will then print out either I can see or I can't see as a result of whether or not the light is on being equal to true. Since the default value of a boolean is false, we can see the output as I can't see. But if we set the variable to true, it changes to I can see. Since the variable itself is a boolean, either true or false, we can remove the comparison operation altogether and just use the boolean as the condition and get the exact same result. We can reverse the value of any boolean, meaning if it is true, it becomes false or if it is false, it becomes true by using the keyword not. Like the STR function we used in the previous lesson, this only changes how it is being used in the local context and does not actually change the value stored in the variable. So if not, light is on, then we can't see, and else we can see. Naught can also be represented by an exclamation point. Let's change the value of lights on and run it again. I'll then revert these changes back to how they were before. We can make our conditions much more complex by combining multiple conditions together using logic operators. Let's create another variable named Has dark vision. This variable implies that we should be able to see even if the light is not on. So we can add to our if statements condition to be either that the light is on or that we have dark vision. And if either of these conditions are true, then we can see. Only if both conditions are false, will it result in us not being able to see? What about if, instead of having dark vision, we are wearing night vision goggles, since they only allow us to see in the dark but not in the light. Changing the variable name, the condition of our I statement needs to change. Since if both conditions are true, then we shouldn't be able to see. Only if the values of these two conditions are different, should we consider the condition to see to be met? We can use the not equals operator to check if the two values are not equal to each other. If you are familiar with logic operations, this is known in other languages as an exclusive or. Now, only if either the light is on or we are wearing night vision goggles and not both, will we be able to see. Next, let's consider that our hypothetical person might not be human and add a variable for the number of Is that they have, which should be represented as an integer. For now, we'll give it a value of two Is. Ignoring the other variables, what would be the condition that we set to be able to see based on this variable? If the number of eyes we have is anything greater than zero, then we should be able to see. We can also express this using another operator, greater than or equal to and change the right hand side to one. So they must have eyes greater than or equal to one. These are comparison operators that will return a Boolean result by comparing the value of numbers on its left and right sides. We can logically conclude that it should be impossible for any creature human or otherwise to have a negative number of eyes. The value of our variable should only be zero or something larger than zero. And the condition to be able to see really boils down to these two options. Do we have zero eyes or non zero eyes? Just like the boolean variable can be used implicitly as a condition, an integer can also be used in this way with zero being considered a false condition and anything other than zero being considered true. The same logic is also applied to floating point numbers. We can declare a float variable, let's name it range of vision and give it an arbitrary value of 7.8 meters. We can use our comparison operators to determine whether this number is greater than less than or equal to a certain value, or we can use it implicitly in its own condition with zero being considered false and anything else being considered true. What about strings? Let's change things up slightly and declare a string variable for what we heard and give it a value of bumps in the night. Then we might logically use this as an if statement as if what I heard was not an empty string, then we can say, I heard something. Otherwise, I heard nothing. And just like the other variable types, we can drop the comparison and use the variable itself as the condition. With all variables, their default values are considered to be false, and anything else is always considered to be true when used as a condition. If we declare a variable without a type, let's call it what I am looking at, but don't give it a value, then we already know its default value will be null. Even without a type or a value, any variable can be used as a bullying condition. Any variable that is empty, meaning its value is null is considered to be false. If we were to populate this variable with an object, then its value as a condition would be considered true. We don't currently have any other objects to play with, but we can always use ourselves. So let's set the value of what I'm looking at to be the keyword self. And this results in being able to see. In the next lesson, we'll use loops to repeat lines of code multiple times. I'll see you in the next lesson. 5. 0-4 While Loops & Operators: Hello, friends. Today we'll learn how to repeat lines of code multiple times with loops by imagining a lady who has fallen in love for the first time holding a flower. So let's write a new script and name it flower. Then override the base nodes definition of the ready function. Our imagined lady is holding a flower that has a number of petals, which we will store in a variable and restrict its type to an integer. Then give it a value of some arbitrary number, let's say five. We'll also declare another variable named He Loves Me, as a boolean, which we believe with its default value of false. We can start our script by printing out a story about the lovestruck lady holding her flower. She removes each petal from the flower one by one, stating either he loves me or he loves me not. First, we need to reduce the number of petals on the flower by one. So we will start with the number of petals variable, then use the assignment operator to assign the variable a new value. The value we want to assign it is the number it already has minus one. We then want to change the value of the booling variable. He loves me to be its opposite. So he loves me, is assigned to naught He loves me, reversing the value of false true or vice versa. Next, we can print out the results. He loves me. We may want to encapsulate this part in quotation marks, but if we try to put a quotation mark inside our string, it will instead mark the end of the string. Some special characters like quotation marks can be created inside a string using a backslash. If we write backslash quotation mark, this now represents a quotation mark character, not the end of the string. And we can include another one after the Ladies declaration. Let's duplicate this line and change the declaration to say, He loves me not. Another example of a special character we can write using the backslash is the backslash itself. We can also combine the two lines above and separate them with backslash N, which represents a new line. So they are printed out on two output lines from a single print statement. We now have two possibilities that we want to print out based on the value of our Boolean variable. So it would seem that we should wrap these in an if statement. If he loves me, then print this. If he loves me not, then print that. But in cases where if statements are contingent on a single boolean variable to make a minor change, there's a more efficient method. So let's return to the original format. Our declaration will be he loves me, if he loves me, else, he loves me not. This is not the same as an if statement despite using the same keywords, but it is called a ternary operation. Since it does not create a new block of code with an indentation, it is actually executed more efficiently and is recommended to be used in simple cases like this one. We can actually reduce the size of the variation even more by only changing it to either be an exclamation point or a space followed by the word not, then the exclamation point. This works for the case if he loves me, but if we change the value to true by default, then we only see not in the other case. Just like mathematics, there is a specific order of operations in which our scripts will execute multiple operations on the same line. Since both the string append and the ternary I are both operators, one must be executed before the other, and in this case, it will be the string append. And just like in mathematics, brackets are always the first to be executed. So we can wrap any operation in brackets to ensure it will be executed first in the order of operations. Wrapping our ternary statement in brackets, it will now run before the string append and give us our expected result. So now we have our block of code which needs to repeat for as long as the flower still has petals. Using the keyword WW, much like an if statement, we can repeat an indented block of code as long as the condition remains true. The condition in this case being that the number of petals on the flower is not zero. Whatever the number of petals on the flower is, it will be reduced by one each time. Then after the print statement, the logical flow of this script will return to the beginning of the WWloop to check the condition again. When the number of petals reaches zero, the condition is no longer met and the loop breaks, proceeding with the remainder of the script, if there is any. So let's write a short conclusion to our story based on the results. She stands up with tears in her eyes. But based on the final value of He Loves Me, she's either happy or sad, and we will print out the different final phrase. Running this scene, we can see our story printed out in the output panel, and with five petals, the lady is happy. If we change the number of petals to six, then we get a different result since the loop repeated six times instead of five. But what happens if we change the number of petals on the flower to zero? The loop doesn't run at all, and the love was doomed from the beginning. I don't recommend following this example, but just watch what happens if we give the flower a negative number of petals. While this is realistically impossible, in our code, it is very problematic. Since the condition of our wall loop will never be met, it will never break, and the script is trapped inside it, never finishing. This is an infinite loop and should be avoided at all costs. In this case, we can prevent the infinite loop by changing our condition to be if the number of petals is greater than zero, since a negative number will still break the loop. We can use another operator when reducing the number of petals as a shortcut. Removing the need to write the name of our variable twice, we can perform simple mathematical operations on our number of variables using a special assignment operator. In this case, the minus equals operator can change this line of code to number of petals minus equals one. These shortcuts exist for all basic arithmetic operations plus equals multiply equals or divide equals, and can be used with any number or variable as the other operand. There is one more operator that exists for basic arithmetic as well, the modulus operator, represented by the percentage sign. Modulus performs a division operation, but doesn't return the quotient as the result like the division operator does. Instead, it returns the remainder of the division. This entire script, other than the story being told, is really just determining if the number of petals on the flower is an even or odd number, but is doing so in the most inefficient way possible, counting down each individual petal. So let's comment out the entire wall loop and instead use modulus to speed up the process. Knowing that all even numbers are divisible by two, we can use number of petals modulus two. The only possible result as a remainder of this division will either be zero if the number of petals is even or one if the number of petals is odd. Our script could be simplified to just if the number of petals modulus two is equal to one, then the lady is happy. Otherwise, she's sad. Since we understand how integers are interpreted as conditions, we don't even need to perform the comparison operation here and can just shorten it to I number of petals modulus two. The result of the modulus operation could be assigned directly to the Boolean variable to get the same result without the need for an if statement, and the zero or one will automatically be converted to false or true accordingly. We could go further by removing the variable and just using the modulus operation directly inside the turny statement. In the next lesson, we'll learn about collections of related variables. I'll see you in the next lesson. 6. 0-5 Arrays & For Loops: Hello, friends. Today we'll consider how we can organize large amounts of variables, especially when they hold related information. I've already gone ahead and created a script named census and overridden the base nodes definition of the ready function. For our hypothetical scenario in this lesson, we are imagining a census worker who needs to record how many people live in each house on a single road in their town. We can declare a single variable to hold all this information, Let's name it Main Street. And the type of this variable will be an array. An array can hold a list of variables of any of the other types. In this case, the type of the variables we are looking for are integers, representing the number of people who live in each house. We can specify the type of contents of an array using square brackets after the type name array and putting the type of the contents inside the square brackets. Now this array can only hold integers as its contents. Before we can access the contents of an array, it needs to have a size, the number of variables that are contained inside it. Unlike other variables, arrays are more complex and have their own functions. We can access these functions by following the name of the variable with a period, then the name of the function. In this case, the resize function, which sets the number of addresses inside this array, representing the number of houses on Main Street, which we will say is six. Our imagined town is a little unusual in that the house numbers on Main Street start at zero. So our census worker starts at the house at zero Main Street and knocks on the door to ask the resident of the home how many people live in the house. We can store a value in an array starting with its name, then using square brackets to mark the address of the specific integer, in this case, address zero, then using the assignment operator. We can assign an integer to that address. So let's say that the house number zero on Main Street has five people living in it. Moving on to the next house on Main Street address number one, someone answers the knock at the door and tells the census worker that there are two people living in that house. At the next house, address number two, the house is under construction and has a for sale sign, which means this house is clearly unoccupied, and our census worker records the number of residents as zero. At number three Main Street, nobody answers the door, despite the fact that there is a car in the driveway and signs of occupation. What might we consider the census worker should record as the number of residents? We might think that it could be zero. But how would we differentiate between an unknown number of occupants and an unoccupied house? If we consider that the number of occupants of a house should never be considered a negative number, we could use the number negative one to mean that the number of occupants of the house is an unknown value. And at number four Main Street, there is, again, no answer at the door. But the house also appears to be neglected, and likely nobody has lived there for quite some time. We could assume that the number of occupants is zero maybe used the same negative one value for an unknown number of occupants or create more negative value codes for different situations like using negative two to mean probably unoccupied but not confirmed. Address number five on Main Street doesn't even have a house, but it's just a vacant lot. So again, this could be represented with a zero or another negative value to encode some sort of meeting. Let's print out the results of the census and see what they look like. We can see our array represented as a comma separated list of numbers encapsulated in square brackets. This does a decent job of representing the number of people living in each house on Main Street. But what if we wanted to use this data to get a total number of occupants of all the houses on Main Street or on average? If we calculated the sum of all of these numbers, the unknown numbers being represented as negatives would skew the results. One of the best benefits of using arrays to store related information in this way is how easy it is to loop through it. Using the keyword four, we next write the name of a new variable, one which will represent each individual element inside the array, followed by the keyword in, then the name of the array. Like functions, if statements are wa loops, this is followed by a colon and an indented block of code which will be repeated. These lines of code will be repeated once for each of our six houses on Main Street, and we can name the variable house, as it will be used to access each individual house inside the loop. Let's say we first want to find the average number of occupants who live in an occupied house. That would mean adding up all the positive numbers then dividing by the number of occupied houses. So we'll need three new variables, one for the total number of occupants, another for the number of occupied houses, both as integers, and a floating point number for the average. For each house in Main Street, we can check if the house is occupied, if the number stored in the array at that address now stored in the house variable is anything larger than zero. If this is true, then the total number of occupants in occupied houses can be increased by house, and the number of occupied houses incremented by one. After all six houses on Main Street have been checked, the loop breaks, and we have our two integer numbers. So we can calculate the average by dividing the total number of occupants by the number of occupied houses. Then print out the results. There are plus occupied houses, plus occupied houses on Main Street, with an average of plus average occupants plus occupants. But if we run this code, the average is represented as an integer, three, which we know is not correct, since there are a total of seven occupants in two occupied houses, the average should be 3.5. This happened because we performed a division operation with two integers, and the result of the operation will also be an integer, even though we are assigning it to a floating point number variable. Godot also provides a warning against using integers in division operations. To resolve this, we can change our integer variables to floating point numbers in their declarations, or we can change their type locally before performing the division. Much the same way as we changed integers into strings before appending them, we can change an integer into a floating point number before performing a division. Changing the result of the division to a floating point number as well. Changing the type of a variable in this way is called casting. We are casting an integer to a float. Now we can see the results we were expecting with an average of 3.5 occupants per occupied house. A benefit of GD Script, being a loosely typed language is that we do not need to specify the types of our variables, including the types contained within an array. If we allow our array to contain any type of variable, we can change how our census worker records information. Let's assume address zero remains the same with five occupants. But address one also provided the names of the two residents who live there. Instead of recording the occupants as a number two, we could record their names in a string. So Main Street address number one is occupied by Jordan and Ashley Smith. House number two was unoccupied, which we could represent as a zero. But we might also consider recording it as a boolean instead, and give it a value of false to mean that the house is under construction and can't possibly have occupants. At number three, nobody was home, but there are definitely people living there. We just don't know how many. We could also store this value as a boolean and give it a value of true. At number four, it really seems like nobody lives there. We may want to mark it as zero occupants. At address number five, since there isn't even a house there, we might actually consider using null as the value since null represents the absence of any value. We can use the keyword null to assign this to the array at address five. Now our printed array looks quite different, containing variables of all different types instead of just integers. And we can discern more information from it. Arrays can even contain other arrays as their contents. So let's change our list of names from a single string to an array of strings. We can create this array at the same time it is being assigned using square brackets, then populating it with a comma separated list of strings as its contents. So if we wanted to know how many people are living at Address one on Main Street, we could print that out as Mainstreet one dot SIE. In the next lesson, we'll learn more uses of arrays to create more dynamic data collections. I'll see you in the next lesson. 7. 0- 6 Stacks & Functions: Hello, friends. Today we'll continue working with arrays in different ways by setting up a game of Old made. I've already gone ahead and created a script named Old Made and overridden the base nodes definition of the ready function. In order to play old made, we need a deck of cards, which is a collection of variables which we can hold inside an array. Since the game of Old Made doesn't really care about the suits of the cards, we can ignore that information, and each element in the array only needs to contain the cards rank from ace to king as an integer. To generate our deck, we can use a four loop. But instead of using the four loop to iterate through an array, it can just be used to count through our card ranks. Starting with four, we can declare a variable to represent a card's rank, followed by the keyword in, then specify a number. If we were to consider King to be a number, it would be the 13th rank. For now let's just print out rank so we can see what happens. The four loop starts with a rank value at zero and counts up to 12, repeating this loop and print statement 13 times. For the sake of sanity, it might be a good idea to consider card number two to be represented by rank two, and thus Ace would be one, and king would be 13. While starting a four loop at zero is really helpful for iterating through arrays since their first index number is zero, it isn't that helpful in this case. We can change the way a four loop counts by replacing the 13 with a function call, range. Function calls are followed by parentheses containing arguments. The arguments for this function are the lower and upper limits of the range. The lower limit will be included in the range, but the upper limit will not be included. Range 114 will contain all numbers 1-13, we can see that is printed out in the output. Another way of adding information to an array instead of using the square brackets and index number is to use a function named append. This append function accepts an argument of the value being added to the array. This will position the value being added to the end of the array, wherever that may be. And since there are four of each rank in a deck of cards, one for each suit, we should repeat this line of code four times for every rank. We can do this with another four loop, this time starting at zero and counting up to, but not including four. Printing out the deck, we can see our array has four of each number 1-13 for a total of 52 cards. But to play old made, we want to remove three of the queens, or in this case, 12. So in our four loop that is iterating through the card suits, let's check if the rank is 12. And in this specific case, we only want to allow 112 to be added, using the keyword break to instantly break out of this loop. Break will only end the most indented loop it is currently in. So we will end the suit for loop, but not the rank for loop. This will then increase the rank to 13 and proceed with adding four thirteens to the deck. And testing it out, we can see how there is only 112. The first thing that happens in our game is shuffling the deck of cards, which in GD script is a simple built in function of rayse. We only need to call this function and we can see that the cards get shuffled in our deck. We will also need another variable, an array of hands of cards to represent our players. Each hand inside the hand array needs to hold multiple cards, so they are also arrays, which we will need to initialize before we can use them. So counting from zero up to but not including four, we can append a new hand to the array. Our hand starts off as an empty array represented by square brackets. If we imagine our deck of cards, the front of the cards being the side with the rang and suit, the back of the card being blank, then we might also imagine the deck being face down. The front of the array is the bottom of the deck, and the back of the array is the top of the deck. The process of dealing out the cards can be done by iterating through our deck, but we do not actually need to reference specific cards at all, since it doesn't really matter what they are only that the card is taken from the top of the deck and handed to a player. So to remove a card from the top of the deck, we can call another function. This one is called pop back. It not only returns the last element in the array, but also removes it from the array. We then want to add this card to the player's hand and we'll start with player one, assuming player zero is the dealer. Just like we can use pop back to remove a card, we can also add a card with pushback. The card we are pushing onto the back of the player's hand is the same card we are popping from the back of the deck. We can simply put this function call inside the brackets of the function call and use its return value as the argument to the push function. Using pushback is the exact same as append. The append function is a legacy of strings, since they are usually stored as arrays of characters, while push and pop come from using stacks or cues like we are doing now. To deal our next card, we'll need to increment the hand that is being dealt to. Let's store that in a variable as an integer and give it an initial value of one. Replacing the one in our array index with our variable, we'll need to increment it by one after each card is dealt. But this will obviously just count up to 51, and there are not so many hands. So we'll need this number to return to zero each time it reaches four. This can be accomplished using our trustee modulus operator, assigning hand to be modulus equals four. But if we want to allow our code to work with any number of players, it would be better to replace four with the size of our hands array. To see where we are so far, let's print out our hands by iterating through the hands array and printing out each one. Then print out the deck. We can see our four arrays and the deck is empty. We can even change the number of players and the cards will deal out to the correct number of hands. Our ready function is getting rather large. We can organize our code better by declaring our own functions. Separating our logic into small chunks, we have a section that creates our initial deck of cards, one that creates the player's hands, and one that deals the cards. Using the keyword funk, we can give each of these blocks of code a name followed by parentheses and a colon. Initialized deck, initialize hands, and deal. Then the ready function can call each of these functions in sequence. Our functions can also accept arguments, such as the number of hands we want to have. Let's pass four as the argument. To write our function to accept the argument, we need to add a matching parameter inside the parentheses of the function declaration. Much like declaring a variable, it has a name and optionally also a type. Since we are using this to resize an array, it's a good idea to restrict it to be an integer. We can then use the parameter inside the function much the same way we would use any other variable. The last thing we need to do to start playing would be to remove all of the pairs from each player's hand. So iterating through each hand in the array of hands, we can call another function to remove the pairs from that hand, passing the hand as an argument. Giving this function a definition, we can then accept a hand as an array parameter. We will need to iterate through the hand with a variable. Let's call it card one. But we can stop before we get to the last card. So we'll only go from zero up to the size of the hand minus one. We can then iterate a second time in much the same way, but this time, start at the card after card one and go all the way to the end of the hand size. Inside these 24 loops, card one and card two now contain every unique pair of cards in our hand, so we can easily compare the two cards to see if they are a match. If they are, they can be removed from the hand, starting with card two. If we removed card one first, then the index of card two would actually change as a result, since all the cards would move one position. If we find a match, we don't want to continue this loop or either loop, but we want to restart the entire process again. A simple way of doing this would be with a while loop, a Boolean variable for whether or not we found a pair with a default value of true. While a pair was found, we can immediately set it to false. This allows us to enter the loop but not stay here unless a pair was found. In other languages, you could do this with a do Wile loop instead. If we find a pair, we can set the variable to true, then also break out of both loops resetting the while loop. If both four loops complete without finding a matching pair, found pair will be false and the while loop will break. We can repeatedly run our simulation and see that none of our players' hands will ever contain matching pairs, and the players are ready to start playing their game of Old Maid. In the next lesson, we'll use another form of flow control. I'll see you in the next lesson. 8. 0-7 Match & Return: Hello, friends. Today we'll use another form of flow control to simplify complex conditions. I've already gone ahead and created a script named months and overridden the base nodes definition of the ready function. Let's start by declaring a variable to hold the current month and set it to be January and a second variable to hold the number of days in the month, which will be left as zero by default. We can print out a simple sentence stating that the number of days in January is 31. But first, we want to populate our variable with the number of days based on the value of month. So let's write a function that can do just that. Assign the number of days in the month to be returned from a function we will write, which will accept the month as an argument. Giving this function a definition, accepting the month as a parameter of type string, it also needs one more piece of information, a return type. The type of value returned by a function is defined after the parentheses with a hyphen and greater lansinn an arrow, followed by the type name. In this case, it is an integer, representing the number of days in the month. If we do not specify a return type, the return type for any function we write is null by default. Inside our function, we need to return an integer, which means we should declare an integer at the top of it, and it will need to hold the number of days in the month. Then at the bottom of the function, we will return the value held in this variable. Between these two lines, we need to populate our variable with the correct number of days based on the month. If the month is January, then the number of days is 31. We learned previously that we can provide an alternative with the se keyword, but that only provides us with two options out of the 12 we need. We can use another keyword, if, short for se if to provide another condition which will be checked if the original condition was false. So else if the month is February, then the number of days is 28. And we can repeat this as many times as we need to, providing a case for every possibility. But many of these options have the same outcome, either 30 days or 31 days. We could vastly improve the efficiency of this if statement by combining the most common outcome, 31 days to be the default case and replace all of them with a single else keyword at the end. So if the month is not February or any month with 30 days, then the number of days must be 31. All of the cases resulting in 30 days can also be combined into a single statement using the or operator. If the month is September or if the month is April or if the month is June, or if the month is November, then the number of days is 30. But the statement is quite long with more cases, it might run off the screen. For simple case by case statements like this, there is a cleaner and easier to use keyword than the I statement called match. Match is followed by the name of a variable, a colon then an indented block of code. Inside a match block, we can specify any number of specific cases for the value of the variable. Let's start with February. The case is also followed by a colon and another indented block of code. This code will only be run if the value of month is February. We can group cases together in a comma separated list. So our I statements condition can be shortened into just a list of four months. If the value of month is September, April, June, or November, then the number of days will be set to 30, and our block can be replaced with a wildcard case represented with an underscore, setting the number of days to 31 if the value of month is anything else not specified above. This is the same as using default in other languages. Each of these blocks of code are called branches. And in GD script, a match statement will only ever execute the uppermost branch whose condition was met. In other languages, this is similar to a switch statement, but differs in that switch statements can execute more than one branch if multiple conditions are met. Because of this restriction, there is no need to include breaks in match branches. If we wanted to print out the number of days in every month, we would probably want to use a loop, but we can't simply count or increment a string like January to somehow become February. So it is common in code when representing things that exist in a sequential order to put them in a numbered list called an enumeration. An enumeration in GD script is just a group of related constants. We might have a constant for January with a value of one, another for February with a value of two, et cetera. But using the keyword Enum, we can name the group of constants, let's name it months followed by braces. Inside the braces, we can group the constants together and they will each be assigned a number automatically based on their position in this list. Anything contained within the braces does not need to stay on one line and can be broken up into whatever format you prefer to make it more readable. Indentation doesn't matter here, but usually when writing anything encased in braces, most coders will indent to the contents, so it looks similar to a function. While I prefer the braces to be lined up vertically, many coders prefer to put the opening brace on the declaration line like so. Just like Constance, enumeration entries are conventionally named in upper snake case. Now that we have an enumeration, the month can be restricted to the type of this enumeration. We can also assign it a value from the enumeration, starting with its name, followed by a period, then the entry in the list. The month being appended to the string output is no longer a string itself and must be cast to a string before it can be appended. The argument being passed to the number of days is no longer a string and is now a month, and we can alter our function to accept a month as a parameter too. Since month is now a month, not a string, we'll need to change our conditions to match using the name of the enumeration followed by a period, then the entries in the list. But when we print out the results, we see that instead of January, our month is written as the number zero. While the type of our variable is a month, which is an enumeration, the actual value is treated as an integer, its position within the enumeration. Since January is the first entry, its value as an integer is zero. February would be one, et cetera. This allows us to modify the value of month with simple arithmetic, so January plus one becomes February. If we wrap this code in a loop that repeats 12 times, we can iterate through all 12 months with ease. But what about writing the name of the month as a string? We could do this in a couple of different ways. Our enumeration type has a property named keys, which is all of our entries as an array of strings. If we index this array using our integer variable, it gives us the entry name as a string matching that number. But following the Upper snake case naming convention, we may not want to print out the name this way. We could rename all of our enumeration keys in Pascal case instead, or we could declare a constant containing the array of strings, holding all our months names in a more presentable format. Then use the month as an index into this array. Another thing we can do with enumerations is manually set the values of the entries using the assignment operator. Let's say we want January to be one instead of zero. The rest of the entries will automatically update their values to increment from one, so February is now two. But this no longer matches the constant array indices. So if we wanted to use this to write the name of the months, we would need to either add an empty entry for index zero, Or subtract one from the month as it is being used to index the array. In the next lesson, we'll learn more about how the engine uses and executes our scripts. I'll see you in the next lesson. 9. 0-8 Scene Tree & Inheritance: Hello, friends. Today we'll learn about how the engine uses the scene tree to run our scripts. I haven't yet attached a script to the root node of the scene tree, but we'll instead start this lesson by adding more nodes. Right clicking on the root node, then selecting add child node, still just a normal node, we can rename it to be president and pretend our scene tree is the structure of a company. The president node is indented because it is a child of the scene's root node. With a node selected, we can also use the shortcut Control A or Command A to add another child node. Let's name this one operations manager, and it is indented another level because it is a child of the president. Let's now attach a new script to the president node and name it employee. Overriding the base nodes definition of the ready function, we can simply print the name of this node and append is ready. This script can be attached to more than one node. So let's attach the same script to the operations manager node by dragging it from the file system tab to the scene tree. Then run the scene to see what happens. We can see that the operations manager is ready, then the president is ready. Both nodes that have the script attached run the script, and since they have different names, the output was different. We can also see that the operations manager was ready before the president was ready. To understand why we'll need to add more employees. The operations manager will oversee a number of operators. I'll add another child node to the operations manager and name it operator one. Then attach the employee script. We can right click on any node except the root node and select duplicate to create a copy of it. The duplicates name will automatically include an increasing number, so we can have operator two, three, and four, et cetera. Since the node we duplicated had a script attached, the copies created also have the same script attached. Since the operators have the same indentation level and are all children of the operations manager, they are called siblings, and siblings are not allowed to have the same name. Our company should have more than one department, so let's duplicate the entire operations department by duplicating the operations manager. All of the child nodes are also duplicated. Since the operators are not direct siblings, they're allowed to keep their original names. Let's rename the manager to be marketing manager, and they will have just two marketers working on their team. Parent nodes can also be collapsed to hide their children or expanded to show them. All of the employees of this company have the same employee script attached to them. So let's run the scene and get a better idea of the order in which the scripts will be run. We can see that the first operator is the first to be ready, followed by each operator in sequence, and finally, the operations manager. The same follows for the marketing department. Then finally, the president of the company is the last to be ready. How is Gadot deciding this order of execution? The engine starts at the top of the scene tree and works its way down, but it does not consider any node to be ready until all of its children are ready. So the president is not ready because the operations manager is not ready. The operations manager is not ready because the operators are not ready. The operators are ready in sequence, since they have no children. Once all of the operators are ready, then the operations manager is ready. But the president still isn't ready because the president has another child who is not ready. The marketing manager was not ready until all of the marketers are ready, and finally, the president is the last to be ready. Since the root node doesn't have a script attached to it, its ready function is that of a default node, which is empty. Besides ready, there are other functions of node we can override to be executed later after a node is ready. The most common being process, also preceded with an underscore. The engine will try its best to run the process function of every node in the scene tree 60 times per second using the default project frame rate. So process uses a parameter named Delta, which is a floating point number to represent the number of seconds that have passed since the previous frame. So most of the time it will be one 60th, but not always. We do not need to use this parameter for anything today, so we can proceed the name of this parameter with an underscore, so Gudo knows that we don't need to use it and shouldn't bother with it. But in order to override the process function, it must have the same number and types of parameters. Let's tell our employees to do some work every frame by printing out a statement saying their name appended to does work. Running this scene, we see that all of our employees are working very hard, writing their print statements 60 times per second. This is not the same as an infinite loop as work is actually being done the way it is intended and nothing is broken. Let's make this a little easier to understand by only allowing each employee to do one unit of work using a Bolan variable has done work with a default value of false. In the process function, if the employee hasn't done any work, then they will do work and change the value to true. One 60th of a second later, since the variable is true, they will not do work anymore. But if we declare this variable inside the process function, then it will only exist inside the process function and only for one single iteration of it. Next frame, when the process function is run the second time, the variable is declared again and still defaults to false. So this will have no effect. For our variable to persist, it needs to exist outside the context of the process function. So we'll declare it outside the function without any indentation. Variables declared here can be accessed anywhere in the entire script. This concept is called scope and is one of the main reasons why we use indentation in our scripts. So we can see which variables exist within which scope. Running the scene now, we can see each of our employees declares that they are ready to work. Then only once everyone is ready, they each do one unit of work, but now in a different order. The order in which nodes and the scene tree execute their process functions follows the exact order of the scene tree from top to bottom. Parents do not need to wait for their children like the ready function. We may want all of our company's employees to be similar but not exactly the same. The work of a manager isn't really the same as that of a worker. We can use inheritance to create different behaviors for similar objects. In the same way we are writing scripts that extend node, but changing how they get ready and how they process. First, we need to give this script a name that we can use as a reference, using the keyword class name, followed by a name that describes the behavior of the script, usually the same as the script name, but written in upper Pascal case. Now that the engine knows this is an employee, let's create a new script and name this one manager. But instead of inheriting from node, this time we can inherit from employee. Because our manager script extends employee, everything written in the employee script will still apply to this one, but we can add more or make changes. A manager is still an employee, but the way they do work is different. We should replace the script attached to our manager nodes with the new manager script. Let's override the employee's definition of the ready function. So when a manager is ready, they won't just say they are ready, but they will say that their entire department is ready. In order for both of our managers to be able to output the name of their departments, they will need a variable to hold the name of their department as a string. But how can we populate this variable to hold different values for different departments? If we proceed our variable declaration with the tag at export, this variable will become accessible by other parts of the Gadot engine, namely the inspector panel. In order for a variable to be exported, it must be declared at the script scope level. Selecting the operations manager and the scenetre, there is now a field in the inspector panel where we can give the department variable a string value. This way, the operations manager and the marketing manager can each have their own value for this variable that we can easily control. Running the scene, we can see that the nodes which have the manager's script attached now declare that their department is ready, while the other employees all use the previous definition in the employee script. The process function in the employee script is also inherited by the managers and is run the same as before. So let's change our manager's process function. Managers will say something different. Name plus manages workers to do their work. The has done work variable from the employee script was also inherited and does not need to be declared here to be used. In fact, we can't declare a variable with that name since it would cause a conflict with the inherited variable of the same name. Let's run the scene again and see how our managers now do their work differently from other employees. In the next lesson, we'll learn more about using nodes in the scene tree and object oriented design principles. I'll see you in the next lesson. 10. 0-9 Abstraction & Encapsulation: Hello, friends. Today we'll explore how to write classes that are easier to use and understand. Imagining a car as our frame of reference. Let's create two nodes in our scene, a driver and a car as a child of the driver. Then attach a new script to each of the same name. Cars are very complex pieces of machinery, and most people who drive them have no idea how they actually work. They only understand how to operate their car. Let's start in the car script and give it a class name of car, then add a variable for the year of the car as an integer. Another for the make of the car as a string and another for the model also as a string. Exporting all of these, I'll set my car to be a 2007 Honda Civic. When creating a new class, be sure to save the script before trying to use it. In the driver's script, the driver will need a reference to the car, which we can store in a variable of type car. Nodes can access other nodes in the scene tree, most often their children using another tag similar to export called on ready. Using the tag on ready, we can assign the variable value after the node is ready, which means all of its children are also ready, but before calling the ready function of this node. We can assign it to the return value of a built in function G node, which accepts a node path as a parameter. If we specify the name of the child node in quotation marks, we now have a reference to the child node stored in a variable, and we can access its properties and functions, including those in the attached script. Overriding the definition of the ready function, we can access the car node and print out its year, make and model. The ready function is executed after the on ready tags. A shortcut exists for the get node function to make this easier, the dollar sign, followed by the same node path. Et's switch back to the car script and add another variable. This one specifying whether or not the engine is running as a Boolean. As a driver, we know if the engine is running and we have control over whether or not the engine is running, since we can choose to start or stop the engine using the key. So we would consider this variable to be public. Another property of our car might be the number of cylinders in the engine as an integer, and I'll assign it to have a value of four. This is something that the driver doesn't need to know, can't access easily and should never be allowed to change. So unlike the public variable, this one would be considered private, and we can mark it as private by proceeding its name with an underscore. In the driver script, we can set the value of engine is on to true by putting the key in the ignition and turning it. But first, we should be pressing the brake pedal. Let's use a function to set pressure being applied to the brake pedal, which we will assume is up to a maximum of 20 kilograms of force. So to start our car, we should probably set the brake pressure to somewhere around 10 kilograms. Back in the car script, we will need to define this function which sets the brake pressure. Like the engine is on variable, this would be called a public function, since it is being used by another script. This function will accept a floating point number as the parameter representing the amount of pressure being applied to the pedal. But what does the car actually do when we apply pressure to the brake pedal? From the perspective of the driver, the driver chooses to apply a certain amount of pressure to the pedal without ever knowing the exact position. From the perspective of the car, the position of the pedal is what is being measured and used to stop the car. The car uses the position of the brake pedal to adjust the amount of pressure being applied to calipers which hold brake pads against the wheels of the car, not to mention the complexity of anti lock brakes or other systems. So if we were actually programming a real car, we would need to write several complex functions here that convert the simple action of the driver applying pressure to the brake pedal to the complex mechanics of squeezing the calipers. This is part of the internal functions of the car and not anything that is controlled or accessible to the driver through any means other than applying pressure to the brake pedal. So we would consider these to be private functions, since they are only meant to be used by the car itself. And we can mark our private functions by proceeding their names with an underscore. Notice how this is the same as the process and ready functions. The way GDScript uses private variables and functions is more like the way other languages use protected ones in that they are accessible to inheritors. GD Script does not actually enforce these privacy rules, however, and scripts can still access private members. These conventions exist purely to facilitate better class structure and design. Another way of using comments in GD Script is to create regions of our scripts that are related, using the region keyword followed by the name of the region. We can end a region using the keyword and region. So let's make a public region and a private region in our car script, separating what should be accessible to the driver and what should not. To keep things simple, let's say that the driver only needs to be able to turn the engine on or off, apply pressure to the throttle, apply pressure to the brake pedal, or turn the steering wheel. What actually happens inside any of these public functions is the internal mechanics of the car itself. The driver does not need to know how any of it works to operate the car. For example, when pressing the throttle, what is actually happening is that the car opens an air intake valve on the engine, letting more air and oxygen into the engine. So the car needs to use a sensor to measure the amount of airflow and the amount of oxygen that is now flowing into the engine. Then use that to adjust the amount of fuel being injected into the engine's cylinders. All of these functions are private, since we do not need to know what they actually do in order to drive the car. Way our car moves would be in the process function, and we'll need another private variable named phase to represent which of the four phases each cylinder is currently in. In the car's process function, if the engine is running, we can iterate through each of the cylinders of the engine. Adding together the cylinder and the phase, then modulus four, we get a different phase for each cylinder. Matching this number, we can tell each cylinder to perform a different phase, the intake stroke, compression stroke, combustion stroke, or exhaust stroke, each accepting the cylinder as an argument. Then increase phase and cycle back to zero when it reaches four. Each of these functions can then control the intake valves, exhaust valves, fuel injectors, and spark plugs of each cylinder to run the engine. The amount of force being produced by the combustion strokes of each cylinder would then move the car forward while the brake pads try to stop the car, and the steering wheel position changes its direction. The car's position would then be moved by the direction, speed, and Delta time. Don't worry if none of this makes sense to you because that is precisely the point of this lesson. You do not need to understand it. Since all of this is in the private region of the script, the driver does not need to know how any of this works in order to drive the car. They only need to know how to use the public region of the script. The separation of public and private enforces two important principles of object oriented programming. Encapsulation is the public region, providing access to public variables or functions that are easy to use and simple to understand, and abstraction is the private region, hiding the details of complex systems or mechanics which do not need to be understood to be used effectively. You will know if your classes adhere to these principles if you can hide all of the private contents and still easily understand how it is meant to be used. So our driver can now simulate driving the car by accessing only the public regions of the car script, from pressing the brake and starting the engine to releasing the brake, pressing the throttle, turning the steering wheel, et cetera. These principles are not only important for our own scripts, but also allow us to use scripts written by other developers without fully understanding how they work internally. They also make R scripts more flexible. Imagine if we swapped out our gas car with an electric car. Would anything in the driver's script need to change? Only the car script would need to be changed for an electric car script, since all of the public variables and functions would still exist in the electric cars script. Likewise, we could also change the driver script to an autopilot script, one which only needs to be given a destination and will automatically be able to operate the car. In the next lesson, we'll learn even more about object oriented design principles. I'll see you in the next lesson. 11. 0-10 Polymorphism: Hello, friends. Today we'll cover the last of the object oriented programming principles, polymorphism. Extending the concepts of inheritance and abstraction, we can write classes that represent a more abstract concept, a collection of more specific classes that are related. Let's use animals as an example by creating a script named animal that extends node, but we don't need to attach this script to any nodes in the scene tree. Here we can give the script a class name, then define properties and behaviors that are common to all animals, like a variable to hold the plural of the animal as a string, and another for the name for a grouping of this animal. And let's also define a function for the animal to move, eat, or speak. While we can easily define the plural of animal as animals, there is no word for a group of animals. We also can't define how an animal moves or eats without knowing what kind of animal it is. So the bodies of these functions can remain blank. But we might consider some behaviors to be common enough that they should have a default, such as speaking. While there are many different mammals that make a wide variety of noises, the majority of animals don't, including fish and insects. Most people would not describe them as speaking. So when telling any random animal to speak, we might consider the default behavior to be silence. So let's add some different animals to our scene tree, starting with a cat. We can now use inheritance, like we have before to make any number of different animal scripts that inherit from animal like cat. We'll then override the ready function to give the variables which are inherited from animal a value that is appropriate for a cat. The plural would be cats, and a group of cats is called a Clouder. The behavior functions can also be overridden to change the silent speaking behavior to meow. Cats walk on four legs to move around, and I'll say that they eat fish. The actual contents of these variables and functions are not relevant, but the focus is on how they are inherited from the abstract concept of an animal to a more specific instance of a cat. We can repeat this process to make many more different kinds of animals to add to our scene tree like a bird or a fish. And giving each a new script inheriting from animal, they can each provide their own unique values for the variables and implementations of the functions they inherited. The plural of bird is birds. A group of birds is called a flock. They fly to move around, they eat worms, and they chirp to speak. I'll get a head start on my fish script by copying the contents of the cat script. And the plural of fish is fish. A group of fish is called a school. They swim to move around, they eat algae, but they don't speak. By omitting the speak function, fish will use the inherited definition from the animal script for speaking. So far, all we've done is use the object oriented principles we already know to inherit, abstract and encapsulate the properties and behaviors of animals. But all of this allows us to use polymorphism by treating all animals as if they are equal and interchangeable. First, let's add a script to the root node of our scene and call it Zoo, inheriting from node. Our zoo is full of different animals, but it doesn't matter what those animals actually are. Overriding the definition of the ready function for our Zoo, we can easily iterate through our list of animals and treat all of them as if they are just animals. A quick and easy way to store all of our animals into a single variable. Let's call it animals is to use a function of node called Get children. This returns an array of nodes, all of the child nodes of this node conveniently organized into an array in the same order as the scene tree. Because this relies on the children, we must use the tag at on ready. Since we know that all animals have the same properties and behaviors, we can iterate through each animal in our array of animals and tell each one of them to speak. And despite treating them all as animals, each will speak in their own unique way as defined by their own particular scripts or use the definition inherited from animal if they don't have their own. We can create as many levels of inheritance as we want to. So let's create another abstract script for mammals, inheriting from animal. Mammals are a subcategory of animals, including all animals which have mammary glands and use them to nurse their young. These are unique properties and behaviors of mammals that do not apply to other animals. So we can add a new variable to the mammal script for the number of mammary glands this animal has and write a new function called nurse. Again, the contents of the functions are not relevant to this lesson. This script will also need a class name in order to be inherited. Switching over to the cat script, since cats are mammals, and so we can give the number of mammary glands a value for cats, which should be eight. And we can add new mammals to our zoo, as well, like a monkey. Monkeys are also mammals, but they only have two mammary clans. I'll once again copy the contents of another script to make things faster. The plural of monkey is monkeys. A group of monkeys is called a troop. They move by climbing trees. They eat bananas, and I'll say that they say oh. Our Zoo script can now take advantage of this new inheritance structure to apply unique conditions specifically for animals that are mammals. We can directly use class names in conditional statements to say, if the current animal is a mammal, then we will execute some extra code exclusively for mammals. I'll just print out some extra lines describing our mammals. And we can see our output is both consistent for all animals, but also has something unique specifically for the two mammals. You can imagine how we could change our list of animals in our zoo to be any different kinds of animals, and we could alter our structure of inheritance to categorize them as precisely as we need to. In the next lesson, we'll learn about another data collection we can use to group related information. I'll see you in the next lesson. 12. 0-11 Dictionary: Hello, friends. Today we'll use an alternative to the array that is sometimes used sort of like a class without any functions called a dictionary. Imagine a row of lockers like you would find in a high school or a gymnasium. If we declare an array of variables, we might consider the array index of each to be the lockers number. Let's say there are ten lockers, and we can access each individual locker to put something inside, starting at locker zero, one, and so on. What we put inside each locker does not matter. It can be an integer, float, string, boolean, null, or an instance of a class. And we can print out the contents of the lockers to see them. Now imagine that when we put something in one of the lockers, we don't just close the door of the locker, but also put a pad lock on it. This padlock requires a three digit number combination to open. Previously, if we wish to retrieve the contents of the locker, we only needed to know the lockers number, walk over to it, and take the contents out. Now we can ignore the lockers number, and instead, we need to know the combination to open the padlock. Let's say that the combination is 149. As an array, assigning something to number 149 would mean that the array would have to have 150 lockers. If we were to change the type of our array to a dictionary, this would still work except we don't need to set a size for the dictionary before we can access its contents. Notice how the output has changed. Dictionaries are represented by braces instead of square brackets, and each entry is a number representing a key followed by a value of what is contained in the locker locked by that key. There are also no entries in the dictionary for any key which was not assigned a value. As a dictionary, this number is not an index or address. It is a key that we use to open a lock. And just like the contents of the locker can be any datatype, the keys we use to lock them can also be any datatype with only one restriction. Every key must be unique. Otherwise, we're unable to find the locker that matches the key. So let's try locking up a locker with a different kind of lock, one that uses letters instead of numbers. So the key of this dictionary entry is a string, but its value is a number. The complete opposite of this locker, whose key is a number and value is a string. Let's lock the next locker with a spin lock, which requires three numbers to unlock it, which we could store in an array. So our dictionary entries key is an array represented by square brackets containing a comma separated list of three integers. Maybe this locks number includes a decimal point, so the key is a float. And somehow this locker is locked by photosensitivity and can only be opened if the lights are off. So its key is a boolean. We can even use custom classes as either our keys or values in dictionaries. Let's write a new class for key, which will not need to inherit from anything since it won't be attached to a node, nor will it be inherited. Our key class needs a class name and will have a variable that describes its teeth. The implementation of this class is not relevant, but we can pretend it is a key. Back in the locker script, we can store an instance of our key in a variable. Let's call it key one of type key by assigning it to the class name of key Nunu creates a new key, which is assigned to our variable. We can now use this key to create an entry in the dictionary. We can also create more keys to create more entries. As every key we create is considered unique. The output now displays the keys as reef counted followed by a long number. The names we have used in other classes were inherited from node. But since key doesn't inherit from node, it doesn't have a name. Ref counted is short for reference counted object, and it's the base class for GD script. If we write any class which does not inherit from anything, it will inherit from reef counted and be assigned a random long number. We can ignore this and just understand that our keys are reference counted objects, meaning Gadot is automatically keeping track of each unique instance of each object we create. But what do we want to store in the lockers? Just like arrays can contain other arrays, dictionaries can also contain other dictionaries. Matching how dictionaries are printed out, we can create our own dictionaries on the fly using braces. Each entry starts with a key followed by a colon and then the value that matches that key. Common use of dictionaries isn't to create anything like this locker scenario, but instead to create something more like a class, albeit one without any functions, only variables. Let's say that this locker contains a plush toy, which we will represent with a dictionary. And this plush toy belongs to a set of collectible plush toys that are similar but varied in their own ways. Each of the plush toys is a different type of animal with a color and a name. Each of these can be keys in the dictionary. Let's say that this locker contains Bruno the brown bear. And the next locker contains Arthur the White Goat. We can see our dictionary plush toys inside the dictionary of lockers. It so happens that color is also an already defined class in Gadot. So instead of storing our colors as strings, they can be stored as colors using the class name color. As you can see, there are lots of predefined colors for us to use, and we can tell by how they are named in upper snake case, that these are constants of the color class. We could even flop this around and pretend that the plush toys contain an NFC or near field communication tag, making them the key to access the locker. And we can put whatever we want inside the locker just as before, including another plushy. Let's make another plush toy to store inside the locker, which is unlocked using Arthur as a key. This time, it's cutie, the gray elephant. So re imagining this scenario, there is an NFC reader near the lockers, and we are holding a plushe with an NFC tag inside, something like what you might find in an escape room. If we hold the plush toy against the reader, we need to check which locker matches the plush toy and unlock it, if any locker matches at all. But if we try to access a key in a dictionary which has not been assigned a value, we will cause an error. Much the same way we would if trying to access an array index out of range. We can check if a dictionary contains an entry matching a specific key using the function has, then passing the key as a parameter. This allows us to check if a dictionary entry exists before trying to access its value, avoiding the error. If the dictionary doesn't have the key, I'll print out a different message. Instead of defining the same dictionary twice, it would be better to store in a variable and use the variable twice. In the next lesson, we'll explore some different techniques that you can use when you get stuck or need more information. I'll see you in the next lesson. 13. 0-12 Debug: Hello, friends. Today we'll go over a few different strategies that you can use to help you when you inevitably get stuck. I've already attached a script to the scene's root node named debug. You've probably noticed the autocomplete feature that is available if you specify the type of your variables. This not only allows you to see all of the properties and functions of the class, but after selecting a function, you can also see the types of all the functions parameters so you can provide matching arguments. A, when you know the types of all your variables, this makes mismatch errors clearly apparent, and you'll be warned of the error without having to run it. Without strict types, the engine doesn't know what is mismatched until attempting to execute the line. If you want to browse through a built in class like color, we can easily access the information by clicking on either of the buttons in the upper right corner of the panel. Online Docs opens a tab in your default web browser to the GADO API matching the version of the editor that you're using. Here you'll find basic information about Gdo tips on getting started, detailed tutorials on the basics, community links where you can find additional resources, and a complete class reference. As you can see, there are a lot of classes. And selecting any of them, we can see what they inherit from and what other classes they are inherited by. Each has a description of what it does. Links to tutorials on how to use it, a list of properties and methods. When talking about classes, we tend to refer to variables as properties and functions as methods. There are also signals, something Gadot uses for automatic communication between nodes, enumerations and constants like we have used before. All of these have their own subsections and descriptions of how to use them. Back in the GDA Editor, search Help opens a window in GDA where you can see a list of every class. Selecting a class, we can see all of the same information that is available from the GDA website in our editor, so we can access it offline. Returning to our script, we can even access this information easier by holding down the control or command key than clicking on a class name, bringing us straight to the reference information for that class. The same can be done for specific functions and variables. Clicking on them not only opens up the reference page to the class, but also brings us to the function or variable that we clicked on. There are also global functions that we can use mostly to perform mathematical operations like clamp, for example. If we use this function, we can see the parameters it is expecting and we can use it to clamp our variable to be 0-1. Holding the control or command key and clicking on the name of the global function will allow us to access the reference for this function, complete with a description and how to use it. These are all contained within the global scope class. I'll add another variable and another line to my script. If we run our scene, we can view the scene tree of the running simulation through the scene panel by clicking on the remote toggle. This is not the same scene tree in the local tab that we build to define the scene like a blueprint. This scene tree is the one that was constructed by the engine to run the scene. Selecting any node, we can see its properties in the inspector and we can see that the ready function has already run since the colors have different values. We can change the values of any of these properties too. We can also use print to print out whenever we want to see what our variables hold at any moment. And it helps to be as descriptive as possible with your print statements, so there is no confusion about where they are coming from. But if we change things up and use the process function, I'll just change the color gradually over time, then add a print statement here. Since this process function is running 60 times per second, the print statements value as a debugging tool is greatly diminished since the output log is just going to repeat the same message faster than we can possibly read it or react to it. We can pause the simulation while it is running, using the pause button or pressing F seven. This allows us to see the remote scene tree as it is at this moment and review the contents of the output panel with the simulation paused. But this still isn't very useful, as several frames will be completed between the time when the simulation starts and when we can pause it. If we click to the left of any line of code, we can add an automatic breakpoint indicated with a red circle. When we run the current scene, the simulation will pause when it reaches this line before executing it. This is much more helpful if we want to see our simulation run one frame at a time. Now we can see how each frame the color gradually changes one frame to the next. Let's have our process function call another function to perform a simple task. I'll just change the color gradually by reducing its red value. So now we should see the color gradually change every frame becoming less red and more blue. With the breakpoint still at the first line of the process function, I'll run the scene. It stops here, and we can see that the next line of code to be executed is indicated with a yellow triangle. While the simulation is paused like this, we can tell it to execute only a single line of code at a time, rather than an entire frame by selecting step over from the Debug menu or using the shortcut F ten. This will execute only the line of code which is pointed at by the yellow triangle, then immediately pause again. So we can see the changes made only by that single line of code, and we can see the yellow triangle point to the next line waiting to be executed. We can continue running our script line by line if we continue stepping over until the process function ends and the frame is complete, returning to the top of the process function to run a second time. Now we can watch each individual change to the color as its blue value is increased separate from when the red value is decreased, even though they happen during the same frame. In the case of function calls, there is another option to step into the function. If we select this option or use the shortcut F 11, the yellow arrow will instead step into the function being called and execute that one line at a time until its completion. When the function is complete, the yellow arrow returns to the original function to continue executing that one. Using these tools, we have a very focused view of what our classes are doing and when, how they are behaving and we can watch them in as slow motion as we need to to figure out what is going wrong at what specific moment in time. If you can't solve a problem yourself, the GDA community is very helpful and always willing to lend a hand. There are Discord servers for GDA developers, including my server where my students help each other out. The link to join is in my profile. There are also online forums on websites like Redit where you can ask questions too. You now have a basic understanding of most of GDScrip syntax and the tools needed to explore these concepts further. When you're ready, please ask me for a discount code to any of my game project courses, and good luck. 14. 1-0 Setup: Oh friends, welcome to my course. I'm making a complete two D pixel platformer in Godot. To get started with the Cado engine, you'll first need to download it from their website, head over to Godoengine.org and download the latest stable version. For this course, I'll be using God version 4.2 Once the download is complete, just unzip the folder and run the EX file. Be sure to relocate these unzipped files to an appropriate location on your hard drive. I'd like to have the engine pinned to my task bar for easy access. There are no complicated installers, hubs, or store interfaces to muddle through. If you've ever worked with other game engines, you'll probably be surprised at how simple and easy it is to use Good. By comparison, when you're ready, click on the New Project button. Give your project a name. This is often the same as the title of your game, but often games start without having an official title yet. Developers will use things like Untitled Platform or Untitled Pirate game until an official title is chosen. Select where on your hard drive you want the project to be stored. I recommend making a sub folder in documents named Godot Projects and give each of your projects its own dedicated folder within that folder to keep them organized. Since the game we will be making uses simple two D pixel art in two D scenes, we can use the compatibility renderer which supports desktop, mobile and web platforms and is the fastest at rendering simple scenes like ours. Lastly, God will optimize compatibility with Github version control by default, which is very useful when you're done, click Create and It to create the project and open it for editing. The project opens in an empty three D scene, but we're making a two D game. Under the Scene tab, which is in the upper left corner. By default, click on two D scene to create a new two D scene. This will automatically switch our editor view to two D mode. If you ever find your editor is in three D mode, you can always switch with the buttons at the top of the editor window. Cado. Every scene is defined as a tree of nodes. The scene itself is defined as a node two. It is a node two D, this is the scenes root node. We build our scenes by adding branches to the scene tree. Click on the plus button under the Scene tab to add a node to the scene tree. As you can see, there are a lot of different node types. Type, label into the search bar and add a label node to your scene. Select your new node A nodes properties can be edited in the inspector tab, which is on the right side of the editor window. By default, type any message you like into the text area. When you're done, save your scene by selecting scene from the menu bar, then save scene. You can also use the keyboard short cart control S, or command S, give your scene a name. The naming convention for Godot is to use snake case, which is all lower case with underscores instead of spaces. Click the save button to save your first scene. When you're done, hit the Run Current Scene button in the upper right corner of the editor window. It's the one with the play icon on a clapper board. This isn't a very exciting scene yet, but it works. Click on the stop icon to stop the scene. Under the file system tab, which is located in the lower left corner, by default, you can see a list of all the files that make up your project. Every new Godot project has only one resource file provided by default, the Godot logo. Click and drag the logo into your scene. This added a sprite two D node named icon to the scene tree and set the icon as the sprites texture. This is just an image being drawn on screen. Let's get ready for the next section of the course by making a solid floor for our character to walk and jump on. For that we'll need to add collision. Right click on the icon node and select add child node. Using the search bar, look for static body two D node. This adds the new node as a child of the sprite, but it is showing a warning. If we hover over the warning icon, it will give us more information. This node can't collide with anything because it doesn't know what shape it is. To do this, the static body two D node needs another child node. Adding another node like before this time search for collision shape two D node, the warning icon on the static body Tu T note has disappeared. But the newly added collision shape Tut node has another warning. It asks us pole to please create a shape resource for it. This is done in the inspector panel using the drop down menu labeled Shape Select New Rectangle Shape. This has satisfied the warning. But looking at the scene, we can see that the collision shape doesn't match the icon. If we want the collision to cover the entire icon, we need to adjust it. You can click and drag on the red circles to resize the collision shape. If you want more precise control, you can click on the rectangle shape two D resource to expand it, which exposes text fields where you can enter exact values for the size. If the collision shape is off center, you can expand the transform section under node two D to adjust its position. You can also adjust this value manually by clicking and dragging the Red Cross in the center of the collision shape. Select the icon node and rename it to floor. Since we no longer need to make any adjustments to the child nodes, we can collapse this node by clicking on the collapse arrow. Now let's make this into an actual floor. Adjust your view within the viewport until you can see the entire blue border. Since it is overlapping with the red x axis, the top of the box appears magenta and the left side overlapping with the green Y axis appears. Can this blue box is the boundaries of the screen when we run the game with the floor node selected, adjust its position, size, and shape so it covers the bottom of the screen. Holding down the Alt or Options button will move only the selected node and its children. We've just created a functional floor for our games testing environment out of nothing more than the Godot icon. This type of work flow is common in game development. Using placeholder assets to create a minimal project, which can be used to prototype and demonstrate game mechanics. But in order to make a game that looks good, we'll need assets. I've built this course using a free asset pack called Treasure Hunters, created by Pixel Frog. From it, these assets are released under a Creative Common Zero license. You can distribute, remix, adapt, and build upon the material in any medium or format, even for commercial purposes. Attribution is not required. You can download the entire asset pack for free or optionally support the artist by paying whatever amount of money you choose. Once the download is complete, unzip the folder. Importing the assets is as simple as clicking and dragging them into the project window. I'll also be using sound effects and music downloaded from Freesound.org The Victory War and Battle Music loops library was composed by Little Robot Sound Factory. The Battle sounds pack is created by Luke Sharpals. These sound and music files are under an attribution license. They are still free to use for any purpose, but you must give appropriate credit to the creator of these assets and provide a link to the license. Pay close attention to the licensing and attribution requirements of assets you include in your games. Importing these assets works the same as the artwork. Just click and drag them into the editor. However, these audio files are much larger than the images and we won't be using very many of them. I recommend only importing these assets as you decide to implement each one. Now we have a functional floor with collision and all the art assets we need to start the next section which will be implementing a character. I'll see you in the next section. 15. 1-1 Character: Hello friends. In the first section, we started the project, imported some assets and created a functional floor with collision. In this section, we'll focus on creating a character for the player to control and play with. To get started, we'll first build the node structure of a typical character in the scene panel. Click the plus button to add a new node to the scene tree. Search for a character body node two D, and create it. I'll rename this node to the name of my character. Just like with the floor, there's a warning. This node has no shape. So it can't collide or interact with other objects. We already know how to remedy this problem. Simply add a collision shape two D node and define its shape. The warning reminds us that we must create a shape resource in the inspector. Most characters in games use capsules as their collision shapes because they are easily adjusted to encompass the overall shape of a humanoid and are simple for the engine to work with. By default, new nodes are added at the scene origin in the upper left corner. Let's zoom in on the new nodes. We also need to be able to see what the character looks like. For that, we'll add another child node to the character, A sprite, two D. We saw in the previous lesson that there is a texture property in the inspector panel for sprites, but this one is empty browsing through the treasure hunters asset pack. Select a character sprite to use. By default, I don't want my character to be equipped with the sword by default. I'll select from the without sword folder and pick idle one. Now we can see the character as it will be drawn in the game, but it is blurry. That's because Godo's default project settings are not optimized for pixel art. To fix this select project from the menu bar, then Project Settings. There are a lot of project settings and depending on your version of Godot, they may not be organized or named the same way. If you have trouble finding any project settings, there is a search bar at the top of the window labeled filter settings. We need to find the settings for rendering two D textures, then change the default texture filter from linear to nearest. This will stop the graphics engine from trying to smooth the texture and simply draw as is on screen. With the changes made, we can close the window and now the character is drawn in perfectly defined pixels. When working with pixel art, this is generally the preferred aesthetic. With the red X and green Y axes marking the scene origin. We should assume that the character's origin will be at their feet. Let's drag the spread up until the red X axis acts as a floor where the character will stand. Make sure that they are also centered about the green Y axis. To make adjusting the collision shape easier, I'll re, order it to be below the sprite in the scene tree but still childhood to the character. This also determines what order the nodes are drawn on screen. With the collision shape in front of the sprite, it's easier to move and adjust its size to match the character. Remember that the bottom point of the collision capsule should line up with the character's feet and the red X axis for the character to stand cleanly on the floor. And should also be centered about the green Y axis. In two D games like this, it is generally considered good practice to make the collision shape smaller than the character. This will prevent the player from getting hit by attacks they would perceive to be near Mrs. and allow them to get closer to the environment. Before the next step, make sure your file system panel is focused on the root resource folder. New resources will be created in the last folder you interacted with. In the file system panel, you can collapse any open folders and click on the blank space. If your insurer with that done right, click on your character. We can take any branch in our scene tree and save it as its own scene. I'll name this new scene after the character it's already done since it will use the node's name as the new scene name by default. Now Roger is their own scene separate from the scene we've been working in. Roger's node in the scene tree has a clapper board button and the child nodes have been hidden. Clicking on the clapperboard opens Roger's scene. This allows us to edit Roger in isolation. Any changes we make here will be transferred to all scenes containing Roger in the main scene. We can now move Roger from the scene origin down to the floor where they will be drawn on screen. If we run the current scene, we can see Roger hovering above the floor, but he should probably fall down to the floor from gravity. In order to make Roger behave like a character, we need to add a script switch to Rogers scene and select the root node. Then click the scroll with a plus button to add a new script. It's good practice to write common behaviors as generically as possible. This script should not be Roger. Instead, I'll name the script character and write the script in a way that it can apply to any character, not just Roger Godot offers a default template for scripts attached to certain nodes. We'll see what this template has in it. By default, the script will inherit the behaviors of the node type it is attached to, in this case a character body two D. We will be writing all of our scripts in Goido's native language, Godot script. Click Create to create the new script and attach it to the node. The main panel will automatically switch to script view and open script for editing. As you can see, the template already has several features. The character has a speed and a jump velocity. These are measured in pixels per second. There's also a gravitational force which is being set by the project settings. In the physics process function, we can see that the gravity is applied to the character if they are not on the floor. A jump button has been implemented adding jump velocity. When pressing UI, except which is the Spacebar, there is directional control for left and right directions allowing the character to move and stop. Move inside is a built in function which will take the character body's position, velocity, and external forces. Then determine where the character will be after delta time has elapsed. With the default settings, this code will run 60 times per second. If we run the current scene, we will see Roger fall from the scene origin. But this is Rogers scene, it's not meant to be played. Switch back to the main scene and switch the view to two D. Playing this scene, we can see Roger immediately fall to the floor. Pressing the spacebar causes Roger to jump. Pressing the left and right arrow keys will move Roger left and right. This implementation of controls isn't very good, but does offer a starting point from which we can build our game. Now we have a basic character being drawn on screen with basic controls and physics. In the next lesson, we'll focus on improving our player controls. I'll see you in the next lesson. 16. 1-2 Input: Hello friends. In the previous lesson we've created a basic character with a spray collision physics and basic input. In this lesson, we'll set up better input handling to control our character. Let's start this lesson with some housekeeping. As you can imagine, our game will contain a lot of different resources. And it is important to keep them organized so we can quickly and easily find any resource we need, right? Cooking on the root folder or in a blank space. Create a new folder and name it. Scripts, then drag the character script into the folder. Then repeat the process with the scenes. But we have two different types of scenes. We can further distinguish them with a sub folder inside the scenes folder named characters and place Roger in this subfolder. When you're done, switch to script view. Taking another look over the default template provided for the character body two D script doesn't really fit our needs. We named this script Character and plan to apply this to every character in our game, most of which will not be controlled by the player. It's important to isolate and separate functionality into different scripts for this script, which we are using to describe the attributes and behaviors of characters. We should remove any input handling. I'll comment these lines by pressing control K or command K. Applying gravity and movement input during the physics process is still useful. But let's add some public methods to the script to describe exactly what a character can do. In our game, a character can face left or face right. For now, we'll just leave the body of these methods empty by writing, pass or return. A character can run which requires a direction to know if they are moving left or right. We can represent the direction as a float, which is a number that allows decimal values. This will not only be useful for knowing the direction, but also allow variable speed. We will need to store this value in a variable so it can be used during the next physics process. Let's define a private local variable in our script called underscore direction, then set its value in the run function. We can also edit the physics process to use this variable instead of the one it was using before. A character can also jump, but we don't need any parameters for this one. If the character is on the floor, then add jump velocity to the character's y velocity. These will be our public methods which other scripts can use to control any character in our game. We will add more methods to the script as we add additional behaviors to our characters. Other methods like physics process, which do not concern other scripts, are marked with a preceding underscore, just like the underscore direction variable. These are not meant to be used by other scripts, they are only for this script. If another script wants to control a character's direction, they should call the run method instead, because the run method is public. This creates one universal set of clearly named behaviors to describe how a character will act in our gain. A practice known in programming as encapsulation. The contents of these methods, variables, and of the physics process are not important to other scripts. The other scripts don't need to know how the character jumps, They only need to know that this is a character and it can jump hiding. The details of how functionality is implemented is known in programming as abstraction. These practices will make your scripts much more organized, easier to understand, use, and adapt for other purposes. This is starting to look like a better character script, but we've cut off the ability of the player to control the character, because we want that to be done by a separate script switch to the main scene. If you're not there already, right click on your character and add a child node. This node doesn't need any type. It can just be a basic node and name it Player. We are only using it to attach an extra script to the character. Next in the file system panel, let's write click on the scripts folder to create a new script and call it player. Then attach it to the new node. Click on the script icon to open the script for editing. The purpose of the script will be to receive input and call the appropriate methods in the character script as a result. Which means that we will need to reference to the character. If you recall, we attach this script to a child node of the character node. We can easily get a reference to the character node by declaring a variable at the top of the script. We will name this variable underscore character, because only this script should need to access it and assign its value to get parent. Starting the declaration with at on ready will allow us to assign a value to this variable after the node has been created, entered the scene tree and is ready to start running. Meaning that the node will know who its parent is by that point in time. In order to receive and process input, we will use two different methods, underscore process and underscore input. The input method is more efficient for handling button press and release events. This method takes one parameter, typically named event, and its type will be input event. All we need to do is check the event to see if the player pressed the jump button. If they did, then we will tell the character to jump like the physics process Underscore Process takes delta as a parameter, which is a float type representing the amount of time which has passed since the last process. Usually one 60th of a second. But since we aren't going to be using the value of delta here, we can prefix its name with an underscore, letting Goodot engine know that we don't need this value in the process method, which will run every frame regardless of whether or not input was given or changed. In any way, we can check the status of our movement input. This will allow us to handle both key presses and analog stick axes more easily and interchangeably. We will call character do run here passing in the argument of input get axis, run left as the negative value and run right as the positive value. You may have noticed that the default inputs were UI accept, UI left, and UI right. These are built in input mappings meant to control user interfaces. Since we have used different names for the input mappings, we will need to add these to the project settings before they will work. Open the project settings and switch the tab to input map. If you click on the Show Built In Actions toggle, you can see the input actions which were used previously. You can re hide these mappings with the same toggle type. Run left into the add new action field and click the Add button. Then repeat for run right and jump to map each of these to a button. Click the plus button on the right. This opens a pop up window where you can select any input for keyboard, mouse, or joypad. You can use the search bar to filter the options or use a listening field to detect it automatically. For run left, I'll use the A key. Then repeat the process to add a key for run right and jump. You can also add multiple buttons to each mapping to make your games work seamlessly. With a game pad, I'll use the left stick to run and bottom face button for jump. When you're done, try running the scene and testing out your new input mappings to control the character. Everything should work the same way as before, but now the input handling and character controls are being handled by separate scripts. Using this method, you can imagine how the character the player is controlling can become interchangeable. The input handling script could also be replaced with an AI script to control other characters in your game quite easily. We now have better input handling for controlling a character in your game. In the next lesson, we'll focus on improving the feel of the locomotion and jumping mechanics. I'll see you in the next lesson. 17. 1-3 Locomotion: Hello, friends. In the previous lesson, we improved our character's input handling by isolating it into its own script separate from our character. In this lesson will make the locomotion controls of the character feel better to the player. If you run the main scene and pay attention to how the left and right movement feels, it is very rigid. The movement speed is instantaneous and constant, which is not how humans or any other objects really move. Open up the character script to simulate more realistic movement. We can actually use variables taken from real world physics. In reality, an object will accelerate gradually up to its maximum speed and accelerate as well. Here at the top of the script, Godot has defined a constant value for the characters speed. Let's add two new variables here to represent acceleration and deceleration, which we are measuring in pixels per second squared. These can be private preceded with an underscore and will be of type float. We'll give them initial values for now. I'll just use the same value as speed and adjust them later after testing how they feel. Now the physics process will need to use these values to calculate the character's velocity. If we first look at the else block, this is where the character will decelerate when the player isn't providing any input. All we need to do here is change speed to deceleration. This useful function called move toward will start at the value of velocity x and move toward zero an amount of deceleration. This works well for both left and right direction, since coming to a stop will mean moving the velocity toward zero. But if you look above, the gravity value is being multiplied by delta. Remember that this code runs 60 times per second. And we are providing our rate of deceleration in units of pixels per second squared. We can multiply the value of deceleration by delta to adjust its value to match the amount of time which has elapsed since the last physics process. Then we can rewrite the F block to use the same function and apply acceleration. This time we are starting at velocity x, moving toward speed times direction at a rate of acceleration multiplied by delta. Remember that we can use this script for every character in our game, and we may not want every character to have the exact same constant speed. First, let's change speed from a constant to a private variable and edit the acceleration formula to match. Next, we can add at export to the front of these variable declarations to make them accessible to other parts of the Godot engine, namely the inspector. If we switch to the character scene and select the root node, you'll now see these variables in the inspector and can edit their values. In this way, each character can define their own movement, speed, acceleration, and deceleration values. They do not all need to be the same constant values. Switch back to the main scene and try playing with these new values. You can see how the character accelerates up to speed gradually and likewise decelerates. Since we used the same value as the characters speed for acceleration and deceleration, we know that the time it will take to reach top speed is exactly 1 second. Likewise, the amount of time it takes the character to come to a complete stop is also 1 second. We can make adjustments to these values quickly and easily from the inspector even while the scene is playing. This allows us to quickly test and feel how different values for our variables will affect the game and see which values work best. I think that the character should reach top speed in half of a second and come to a stop in a quarter of a second. We'll increase the values of acceleration and deceleration by a factor of 2.4 accordingly, let's try it out. That feels better to me if you have your rate of acceleration set lower than your rate of deceleration. However, if you try to switch directions while moving, the redirection will feel very unnatural. This is because you expect the character to decelerate down to zero, then accelerate in the opposite direction. But the code as written says that they should simply accelerate from the wrong direction to the right direction. To make this feel better, we can change the if statement to first check if direction is zero, in which case the character should decelerate. Next, knowing that the direction is not zero, we can check if velocity x is zero, meaning that the character is stationary and tell them to accelerate. We also need the condition if the sine of direction is the same as the sine of velocity x, meaning they are already moving and the player wants to keep moving in the same direction. Our last possibility is if neither direction nor velocity is zero and their sines do not match, meaning the player wants to move in the opposite direction the character is moving. In this case, we can instead move towards speed at a rate of deceleration. This will feel much more natural when the player tries to turn around while moving. Let's try it out much better before we move on. I personally don't really like thinking in terms of pixels, especially because these could just be placeholder assets. What if you decided you wanted to make this game using a different asset pack that uses 64 pixel tiles instead of 32 pixels? Now, all of your mechanics aren't going to work the same, and every value needs to be adjusted to match the new pixel size of your assets. Instead, I prefer to think of my mechanics in units of tiles per second, pixels per second. This would be a project wide constant value, which a lot of different scripts will need quick and easy access to. For this, we can create a new script folder called auto loads, then create a new script within that folder called global. This script doesn't need to run any code. It will only be used to hold variables when they are used by the entire project. Like this one, we can declare our variable in this script, PPT, or pixels per tile. It is an integer, a number without decimal points, and its value will be 32. But how do other scripts access this value? Open the project settings and switch to the auto load tab. This is a list of scripts which will automatically be loaded when your game starts and will remain there until it is closed. They can also be accessed by any other scripts by their node name. Click on the folder icon to open a browser and find your global script. The name of the script will be used to automatically generate the node name. Click the Add button and add it to the list of auto loaded nodes in the character script. We can adjust the values of our new variables to be defined in units of tiles instead of pixels. It makes more sense in my mind that the character moves at a speed of eight tiles per second, rather than 300 pixels per second. If I choose to switch to an asset pack which uses 64 pixel tiles, all of my mechanics will still function the same. All I would need to change is the one value in the global auto load script. If you prefer to use pixels as your main unit, feel free to continue doing so. When we start our game. Cado will automatically run a method on every node when it is ready, aptly named underscore ready. In this method, we simply multiply each of these values by global dot to convert them into pixel units. We now have our character accelerating and running more realistically. In the next lesson, we'll improve the jumping and gravity mechanics. I'll see you in the next lesson. 18. 1-4 Jump: Hello friends. In the previous lesson, we improved the character's locomotion mechanics. In this lesson, we'll make similar adjustments to the character's jumping and gravity. If we run the main scene and try jumping, you'll see that the character jumps very high and floats in the air for a long time. It doesn't really feel good taking a look at the character script. The jump velocity is another arbitrary constant value which doesn't really fit our needs. Instead, let's define our characters jump in terms of how many tiles high they should be able to jump. This will be an exported private variable named underscored jump height with type float. And I'll use a default value of 2.5 while not exactly realistic. This allows the player to jump on top of a platform that they could also choose to walk under. We also need to multiply this by global bt. In the ready method, before the game starts, we will need to calculate the velocity that the character will need to reach that jump height. We can replace the jump velocity constant with a private variable to hold this value. Since it will be calculated at run time, it does not need to be exported. This calculation can be added to the ready method. Two, the jump velocity can be calculated using the square root of jump height multiplied by gravity multiplied by two. We can't use square root on a negative number, it has to be positive. Luckily, in two D games, the y axis is inverted. Gravity is already expressed as a positive value. However, our result for the jump velocity is also a positive number. As a result, we need to multiply by negative one to make the character jump up, not down. Now we can edit the jump method to use this new variable. If we test it out, the character will jump exactly 2.5 tiles high when we press the jump button, but the jump is still slow and floating. To fix this, we can open the project settings and alter the value of gravity. Either by filtering the settings or by clicking on physics two D, we can find the default gravity setting. This is set to 980 pixels per second squared. I will instead type calculation directly into the field starting with 9.8 which is gravity on Earth, multiplied by tile size of 32 pixels, then multiply by eight, giving me a value of 2508 0.8 which is approximately 2.5 times what it was originally. This will make everything in the game feel heavier and fall faster, which will appear more realistic to the player. Now the jump feels much better, but I would like to give the player the option of controlling how high the character jumps. There are a lot of different ways in which games implement this feature, like measuring how long the jump button was held before releasing. Adding an initial jump force, an extra force every frame for a short time after, et cetera, done poorly, this can lead to frustrating, unresponsive controls or characters feeling like they're wearing a jet pack. My personal favorite solution to this is very simple and feels very responsive to the player. Simply stop the player from moving upward when the jump button is released in the character script. Under the jump method, we can add a stop jump method. Remember that the y axis is inverted. In two D games, the zero value for Y is at the top of the screen, and positive values move down. If the characters velocity y is less than zero, meaning they are moving up, we can set it to zero to stop them from moving up. Then gravity will start making the move down. The player will perceive this as controlling their jump Ppe by holding and releasing the jump button. We just need to call this new method from the player script. When the player releases the jump button, if event is action released, jump, then character stop jump. Now let's try it out. We can easily control how high the character jumps by releasing the jump button before they reach their maximum apex. This is easy to implement and effective for the player to feel like they have full control. The last thing I want to address in this lesson is that the player has just as much control over the character's movement in the air as they do on the ground. Realistically, there would be no such thing as air control while jumping. But in most video games, air control exists to keep the player in control of the character. It can be especially useful in platforming games for allowing the player to avoid pitfalls or redirect dare to land on platforms. Some air control can be good, but it shouldn't be the same as movement on the ground. To add more specific air control to our character, we can define another exported variable for it at the top of the script as a float type and give it a default value of 0.5 All we need to do is multiply this by acceleration when the player is not touching the floor. To simplify the physics process method, let's divide it into two separate methods, physics and ground physics. These can both be private methods in the physics process. If the character is on the floor, then apply ground physics, else apply air physics. Then proceed with move and slide. Ground physics will not change from what we already have in the air physics method. If direction is not zero, we can move velocity x toward speed times direction at a rate of acceleration times air control times delta. This will still allow the player to have some control in the air, but reduced by half. Let's keep these variables separate from the ones above by also exporting categories for them. These variables will be exported into the jump category. The variables above will be exported into the locomotion category. Let's try it out. Like with the other variables, you can make adjustments to the value and see what it feels good to you. We now have our character jumping and falling more realistically and with better control for the player. In the next lesson, we'll animate the character to match its movement. I'll see you in the next lesson. 19. 1-5 Animation: Hello friends. In the previous lesson, we improved the overall feel of the character's jumping mechanics and gave the player better control of their jump height and trajectory. In this lesson, we'll add animations to the character scene, open the character scene, and get a good view of the character. First, let's make the character face the direction they're moving in. If you select the sprite two D node and look in the inspector, expand the offset section under sprite two D. The property we want to change is flip H. For horizontal clicking on the checkbox, we can see that the sprite is flipped. Hovering the mouse over the name tells us how to access this property. In our script, the property name is flip underscore H, opening the character script. We created methods for face left and face right, but we haven't used them yet. All we need to do is modify the value of the flip H property of the sprite two D node. We can get a reference to the sprite two D node at the top of the script using at on ready var, we'll name it underscore sprite. This will be of type sprite two D. Then assign the value of this variable to be dollar sign sprite two D. Whichever node this character script is attached to, it will search through the child nodes to find one named sprite two D and assign it to this variable. Keep in mind that for this script to work as intended, every character we create must have a child node named sprite two D. Otherwise, this variable will not contain a value. Now in the face left and face right methods, we can use this reference to the sprite two D to alter the flip H property. If the character is facing left, then the flip H property should be true. If they are facing right, it should be false. But these functions are not being called anywhere. The best place to call them would be at the start of the physics process. It doesn't matter if the character is on the ground or in the air. After all, if the sine of direction is negative one, then the character should face left. If the sine of direction is one, then the character should face right. We don't need to do anything if the sine of direction is zero. Now when we run the main scene, the character will face the direction of the player's input. This is a good start, but let's also start working on animating the character. Right click on the sprite two D node in the scene tree and add a child node. The node we need to search for is an animation player node. This node will allow us to change aspects of the character over time, particularly the sprite texture. Adding this node will automatically open the animation panel at the bottom of the editor window. Click on the animation button, then click New Name, the new animation idol. Now you can see a timeline in the animation panel. Each aspect of the character which is being changed by the animation will be listed on this timeline. Click the plus button to add a new property to the animation. The property we need to change is the sprite two ts texture. In order to mark the positions within the timeline where the sprite will change. We can add a keyframe by right clicking on the property track and selecting insert Key. Once a keyframe is added to the timeline, we can easily move it around. Clicking and dragging, if it isn't in the right spot. Clicking on a key frame we can set its value in the inspector. The idle 01 sprite is already populated into the texture field. Since that is its current value, I think that these assets look best. With a frame rate of ten frames per second, I will want to change the sprite's texture every one tenth of a second, meaning that the total animation length will be 0.5 seconds. The timeline is currently showing 15 seconds, which makes editing only the first segment of the entire timeline difficult. Let's zoom in using the slider in the lower right until we can easily see every 0.1 seconds on the timeline. So let's add four more key frames and populate each with the remaining sprites. In order, we need to reduce the length of the animation currently set at 1 second down to 0.5 seconds. We want this animation to loop. Click the Animation Looping button to the right. We can preview this animation by clicking on the play icon at the top of the animation panel. This looks pretty good. Next we need to run animation. Click the animation button and select Duplicate. Then name the new animation run. Expanding the asset folder which contains the run animation, we can see that it contains six sprites. We'll need to expand the length of the animation to 0.6 seconds and add another key frame. Then populate each key frame with the correct sprites in order When you're done, preview the animation to make sure it looks good. Repeat the process three more times to create the animations for jump, fall, and ground. Paying attention to the length of each animation based on the number of sprites provided in the asset pack. However, these animations are not meant to loop, so be sure to turn off looping for these ones. We now have our character animations all set up. In the next lesson, we'll build a state machine to synchronize the animations with what the character is doing. I'll see you in the next lesson. 20. 1-6 State Machine: Hello friends. In the previous lesson, we set up animations for our characters movement. In this lesson, we'll implement those animations and synchronize them to the character's behavior. But before we do that, let's quickly add another node to the main scene. A camera two D node. This will help us quickly get a better view of our character since we can reposition and zoom it in by editing its properties in the inspector. Now when we test to the scene, we'll have a better view of the results of these animations. Now to implement the animations, we'll open the character scene and add another child node to the animation player. This node is called an animation tree. The animation tree node gives us a warning, no root animation node for the graph is set. Looking in the inspector panel, there is a field labeled Anim player. Clicking where it says a sign, we can select the animation player we made in the previous lesson. The purpose of this animation tree will be to control which animation is playing at any given point in time. Using the drop down labeled tree root select new animation node state machine. This will open the newly created state machine in the animation tree panel at the bottom of the editor window. Before we start editing the state machine, however, let's take a look at the asset folder for our character. The animations are split into two folders labeled with sword and without sword. The contents of each of these folders are all same animations, with the exception of the character holding a sword. Or in order to avoid redundant effort, I'll be planning ahead with the structure of this animation tree to accommodate features which will not be implemented until later in the course. To get started with our state machine, we will first right click in some empty space in the animation tree panel and select Add state machine. Then name this new state machine without sword. We can also do this again and create another state machine named With sword. We can then click the transition button in the upper left corner and add a transition from start to without sword. Now when the game first starts, the animation tree will default to playing animations for our character without the sword. We can ignore the sword state machine for now, switch back to selection mode and click on the pencil icon to open the without sword state machine for editing. Inside the state machine, we can create another state machine named movement. Then add the transition from start to movement as the default. This layer of the tree will be used later for another purpose. Open the movement state machine for editing once more. Create another state machine, this time named locomotion, and create a transition from start to locomotion. Then open the locomotion state machine for editing. Finally, we can add animations to the state machine. Right clicking select add animation, then idle and repeat to add run. Create a transition from start to idle, making it the default animation. Then add a transition from idle to run and from run back to idle. The purpose of this state machine will be to change the animation between these two states. We can set the conditions under which these transitions will happen by clicking on them, then editing them in the inspector with the transition from idle to run selected, expand the advance section and select the expression text area. The expression entered into this text area must produce a Boolean value, either true or false. The condition under which we want the character to switch from idle to run is if velocity is not zero. Likewise, the condition for transitioning from run to idle will be if velocity x is equal to zero. We also need to tell the animation tree which node is controlling these advanced expressions. Selecting the tree in the scene tree. Then looking in the inspector panel, we can change the advanced expression base field to the character's root node. Now we can run the main scene and see the animation tree work. Switching the character animation between idle and run based on the character's x velocity. To incorporate the rest of the animations. Return to the animation tree panel and navigate to the movement layer of the state machine Right click to add the jump, fall and ground animations create transitions from locomotion to jump, jump to fall, fall to ground, ground to locomotion and locomotion to fall. Then we can set the conditions for each of these transitions. The characters animation should change to jump if their velocity y is less than zero, then switch to fall if their velocity becomes greater than or equal to zero followed by ground if is on floor. Since this is a built in method of the character body two node, we can access it and it returns a Boolean value. There is no condition for transitioning from ground to locomotion. Instead, expand the switch section and select at end from the dropdown. This will allow the ground animation to complete before transitioning to locomotion, but impose no other conditions. Lastly, if the player walks off of a ledge, we want the animation to transition from locomotion to falling. That will be true if not is on floor. But the transitions from locomotion to jump and fall will both be true at any time the player jumps. We can give the jump priority by changing its priority 1-0 Switching back to the main scene and running the current scene. We can now see the animation tree at work, as it will automatically transition the character between the various states. Now we have the character's basic movements animated. In the next lesson, we'll add dust and sound effects to some of these animations. I'll see you in the next lesson. 21. 1-7 Effects: Hello friends. In the previous lesson, we used a state machine to synchronize the characters animation with their behavior. In this lesson, we'll add some sound and visual effects to add polish to the animations. Starting in the character scene, let's add a new node, an animated sprite two D, and rename it to dust particles. A warning tells us that we need to create a sprite frames resource in order for this node to work with the new node selected. Looking in the inspector, expand the animation section. Clicking on the drop down labeled sprite frames, select new sprite frames, then click on the sprite frames resource to open it for editing, which will appear in the bottom of the editor window. Here we can see a newly created sprite frame animation named Default, with a frame rate of five frames per second. In the file system panel, search through the asset pack to find the dust particles folder group, select the fall sprites and drag them into the animation frames area. Pressing play to preview the animation, we can see what it will look like. We don't want this animation to loop, turn off looping by cooking the animation looping button. Expand the offset section and adjust the y offset until it is level with the red x axis, which will be our ground. It's important to use the offset field and not the transforms position in order to get the particles to appear on the ground. I'll also change the frame rate to match my character animations, which had a frame rate of ten frames per second. Now when we hit play, the animation will play only once. And we can see how it will look in the game in relation to the character. The purpose of this animation will be to play once when the character lands on the ground and disappear when it is finished. These types of effects look best when they exist independent of the character, as if the dust is part of the world and should not follow the character around. Let's right click on the dust particles node and save this branch as its own scene. This doesn't really belong to any of our existing folders. Let's make a new folder for it named dust. Name this particular scene, fall dust cooking on the clapper board, icon in the scene tree. We can open the fall dust scene in order to make the particles disappear. After the animation is complete, we will need to attach a script to the root node, clicking on the ad script button name the new script dust. We don't need to use any of the default templates. Uncheck the template checkbox and make sure the script is saved in the scripts folder. This will start the script off with nothing more than extends animated sprite two D line at the top. But before we actually write any code with the animated sprite two D node selected, look at the inspector panel and switch to the node panel. Signals should be selected by default. This is a list of signals which the node can use to trigger behaviors either in its own script or in other scripts. We can use the animation finished signal to know when the animation is finished. And run a method in our script. Right click on animation finished. Connect to open a new window. Make sure that the dust particles are selected as the recipient of the signal. Then click Connect. You'll notice that Do has automatically generated a method in the script which will be triggered when the animation is finished. There's a green connection icon to the left of the method declaration to let us know that this method is being triggered by a signal. Also in the scene tree, the signal icon is displayed next to the dust particle node to let us know that this node has a signal connection. The only thing we need to do in the script when the animation is finished, is tell the engine that we are done with this node and it can be removed. This is done using a built in method called free. We also want to tell the script to automatically play the animation when it is added to the scene. Overriding the underscore ready method, we can simply call when this node is added to the tree, it will play once and remove itself when it is finished. We can now duplicate this scene to create the similar dust particle scenes for jump and run particles in these new scenes, replace the sprites in the animation with the correct sprites from the asset pack. We now have three different dust particle effects we want to generate under different conditions for our character, but they can all use one method. Switching back to the character scene, we can now delete the dust particles node since it is not meant to be part of the scene. Then switch to script view and open the character script. Let's add a new private function called spawn dust, which will take a parameter named dust. The type of this parameter will be a packed scene allowing us to use the scenes we just created as the argument for the method. First, we need to instantiate the scene, then change its position so it is in the same location as the character. Next, add it to the scene tree by first getting the character's parent node, then adding the dust as a child node. By making the dust a sibling of the character, it will exist in the world independent of the character and not follow them. As soon as it is added to the scene tree, the animated sprite will play its default animation, then Q itself to be removed when the animation is finished only a fraction of a second later. To trigger the jump dust particles, we can call this method directly from the jump method, passing in jump dust as an argument. Then declare what the jump dust is at the top of the script as an exported variable of type packed scene. Selecting the character's root node and switching back to the inspector panel. We can then populate it in the inspector by clicking and dragging the scene into the exported field. The run and fall particles do not have a simple place in our script where they can be spawned. However, what we can do instead is select our character's animation player, open the ground animation, and add a new track. This time a call method track. Then we can access the character's root node and call the spawn particles method at the start of the animation. By adding a keyframe. Selecting the key frame will allow us to pass arguments to the method which we can then populate. By clicking and dragging the fall dust. We can do the same thing with the run dust particles, adding them to the run animation. Remember that the run animation will loop, so new particles will spawn every time the animation loops. For the fall and jump particles, it doesn't really matter which way the character is facing. But for the run particles, it is important that they appear to move behind the character. We can set the animated Steph property to match that of the character at the moment of its creation. Let's try it out. Running creates dust every 0.6 seconds of continuous running. Jumping and landing also create their own unique dust clouds. For another bit of polish, we can also add sounds to our animation tracks, Switch back to the character scene and add a new node to the scene tree, an audio stream player two D node. With this node in the tree, we can now open the jump animation and add a new audio playback track. Selecting the audio stream player node to be the target. Placing a keyframe at the start of the animation. We can then populate this keyframe with an audio stream. Browsing through the sounds provided in the battle sounds packed by Luke Sharps. There are a few appropriate sounds to choose from which fit this character nicely. Import the sounds you like into and place them into a designated sound effects folder to keep your project organized. Then populate your animation keyframe accordingly. To get the run animation looping over shoe sounds. Make sure that you modify the start offset and end offset to select a sample which is shorter than the animation. Let's try it out now. The character makes a grunting noise as they jump, An impact sound when they land, and footstep noises while running. Throughout this first section of the course, we have created a fully animated character with both audio and visual effects and fun platforming mechanics. In the next section, we'll start working on building levels for our game. We'll see you in the next section. 22. 2-1 Tilemap: Hello friends. In the last section, we created a fully animated character with platforming mechanics. If you've completed the assignment, you should now have a full cast of four characters. And we'll have figured out that you can duplicate the player node to control more than one character simultaneously. If you were able to complete the intermediate challenge, you'll also have some AI scripts controlling one or more of the characters. With the more advanced challenge, you'll probably have all of the character nodes, child to the player node, with the character being controlled, able to be switched with the button press. In this section, we'll build a level for our game. Our first lesson, we'll start with building the level terrain. Add another node to the main scene. The node we are looking for this time is tile map. A tile map will allow us to quickly add and modify sprites in our level, which will be organized into tiles of a specific size. For a tile map to work, it needs a tile set. As you can see in the inspector from the drop down, Label tile set, select new tile set, then click on the tile set resource to expand it, exposing some fields we will need to edit our tiles are square. But you can see that there are a number of other options to make working with other tile shapes just as easy. The first thing we need to change is the tile size. The tile size of the asset pack I'm using is 32 pixels in both width and height. It is important that you set this property before adding any tiles to the tile set. Because we are using this tile map for terrain, we'll also need to add a physics layer for collision. A terrain set will make editing terrain much easier. The terrain set can hold multiple terrains. We need to add a terrain to the terrain set. You can think of each terrain as a different biome or construction material. Let's name this first terrain island. Each terrain type can be assigned to a different color to distinguish them from one another. Since we're only going to be using one terrain type per now, we can just use the default color. This color won't be used in the game only while we are editing the terrain. It is only for our benefit as a developer. With those changes made, we can turn our attention to the bottom of the editor window where a new tab has opened for the tile map. The message tells us that we need to configure a tile set first switch to the tile set tab at the bottom. Here we can add the tiles provided in the asset pack to this tile set. Either by clicking on the plus button or clicking and dragging the image file from the file system. Tab code will offer to automatically create tiles for us. Select Yes. If you're sure you've set the tile size correctly, otherwise select no. The tiles should now be lighter and have an orange border. Selecting the eraser tool will allow you to remove tiles from the tile set by clicking on them. Likewise, turning off the eraser tool will allow you to add tiles to the tile set by clicking on them. Switching back to the tile map tab, we can now select and draw any tile from the tile set into the two D view by clicking Goode provides an orange grid matching the tile size to make it easier. The tile map editor also provides all the usual tools for selecting painting lines, rectangles, bucket filling. You can also eye drop, select, erase, rotate, flip, and randomized tiles. Make a basic floor, Place your character over it and position the camera to view the results. Then play the scene. You'll notice that the terrain has no collision yet. Switch back to the tile set tab. Switch to select mode and group select all the tiles by clicking and dragging over them. Let's first add collision to our tiles by expanding the physics section. Then physics layer zero. This tool will allow you to create complex collision shapes for each tile, but we only need basic squares. Clicking on the ellipse icon, select Reset to default tile shape, or alternatively press the key to simply make the collision shape match the shape of the square tiles. Now all of our tiles will have collision, just like the Codell icon we were using as the scene floor. This is great, but building levels by populating individual tiles into the tile map will be extremely tedious. Fortunately, Godel provides a very easy to use terrain editor. Switch to paint mode. This allows us to paint properties onto the tiles. The property we want to paint is the terrain property. Particularly in terrain to zero, the island terrain. You may want to expand the panel or zoom in on the tile area. For this part, each tile is divided into nine smaller squares which we can paint to the terrain color by clicking or erase by right clicking. Every tile which is part of this terrain should have its middle square filled in. In order for the terrain editor to work as intended, we need to paint the edges of every tile which is meant to be drawn next to another tile. When you're done, there should not be any duplicates in this tile set. Every tile should have a unique pattern. Switch back to the tile map tab. Switch to the terrains tab at the top. And our island terrain should be listed as an option selecting that you'll see every tile from the tile set listed, along with two extra options, continuous mode and path mode. Select continuous mode, then draw terrain freely in the two D view by clicking and erased by right clicking. Each tile will automatically correctly connect to its adjacent tiles. You should be able to draw terrain of any shape you can imagine and the proper tiles will automatically be selected for each tile position. If there are any inconsistencies, double check your terrain property painting for errors. Using this tool, we can quickly and easily generate the terrain for every level in our game. We now have basic terrain in our game that we can use to build the foundation of our levels. In the next lesson, we'll add some decorative vegetation to make the environment feel more alive. I'll see you in the next lesson. 23. 2-2 Decorations: Hello friends. In the last lesson, we set up basic terrain with collisions and terrain editing. In this lesson we'll add a few decorations to our terrain to make it more interesting. Like the tile map switch to the tile set tab at the bottom of the editor window. There's another tile set graphic in the asset pack which belongs in this tile set named front, palm, bottom, and grass. Let's add that to the atlas. These decorative elements don't really need any physics or terrain editing. The grass can simply be drawn over areas randomly about your level where you think it will look nice. The roots, however, are meant to be drawn over terrain tiles. But if we try to do that, it will replace the terrain instead. To accomplish this, we need to add another layer to our tile map for these roots. Selecting the tile map in the scene tree, we can collapse the tile set resource and expand the layers section. Here we have one layer which has no name. Let's name this layer terrain, then click the Add Element buttoned, Add Another Layer, and name this one roots. To make this layer drawn in front of the terrain, we can edit the z index, increasing it to one. Since the terrain is on layer zero, the roots on layer one will always be drawn over top. The drop down in the upper right of the tile map tab now contains our two different layers. This allows us to add root tiles to the root layer, which we can then paint over the terrain tiles on the terrain layer. When each layer is being edited, it will appear in full color, while all other layers will be faded. But these roots also need trees. Let's also build the trees. If you want trees to have collision and be an immovable object that acts like terrain, the most appropriate node type to use would be a static body two D, which we will name Palm Tree. This is the same node type we originally used for the Godot icon. This particular node can still have collisions, but will not be moved by collisions with other objects. It will remain static. This tree will have an animation. So let's add an animated sprite, two D as a child node of the palm tree. Create a sprite frames resource for the animated sprite. Then open the resource for editing. Click and drag the palm tree images into the animation. Change the frame rate and hit play to preview the animation. This looks good. Let's make sure this animation automatically plays by default by clicking on the Autoplay button at the top of the panel. Let's save the Palm tree node as its own scene and sort it into a new scene folder for decorations. Now the palm tree can be edited in isolation, and all changes made to the palm tree scene will apply to all copies of the palm tree With the palm tree node selected, Click and drag it to move it around the level and position it over the roots. We can make this a lot easier by turning on grid snapping with the button at the top of the two D view. We can also configure the snapping options by clicking on the ellipse icon. Let's make sure that objects snapped to multiples of 32 pixels to match the tile size. But the palm tree doesn't want to line up because the origin of the tree is in its center. For the tree to line up with the tiles, the origin needs to be in the corner selecting the animated sprite, two D node. Adjust the offset to have the sprite draw 16 pixels, or half of a tile down into the right of the origin. Now the palm tree can easily be moved around to match the terrain tiles. The static body needs a collision shape. In order to collide with anything, we need to add another child node, a collision shape, two D. To make this palm tree more interesting. Let's also make it function as a platform for the player to jump on. Set the collision shape to be a segment shape two D, this is just a line which we can edit by moving the two points. Make the line segment line up with the top of the palm tree. Let's try it out. It functions as a platform, but it would be nice to be able to jump through the bottom instead of colliding with it. I would like the player to not hover so far off the edge before falling. Adjusting the grid snapping settings to eight pixels or quarter tiles. I'll make the line segment only cover up half the full length of the tile. If you want to have the player able to pass through the bottom of the platform and land on top of it. There's a simple built in implementation for that behavior. In Godot, simply check the one way collision checkbox in the collision shape two D properties. This draws an arrow in the editor showing us in which direction the collision will be applied. That is much better. Now I can jump through the bottom of the palm tree platform and slide off the edge instead of standing on an invisible barrier. Something that might be bothersome to some players who like the pixelated art style in particular is that the player is not being drawn on the exact same pixel offsets as the environment. If I position the character next to some grass, you can see that the pixels of my character do not always line up with the pixels of the grass in the project settings. We can adjust these rendering settings to force all images being drawn on screen to be drawn at exact pixel coordinates, which is what the pixel art fans would prefer. These settings are hidden by default. Click on the advanced settings toggle under Rendering. A new option for two D is revealed. Here we have options for snapping transforms and vertices to pixels. This might cause the player to hover one pixel above the floor. If that's the case, adjust their collider so they stand cleanly on the floor. Now when we hit play, the character and everything else in our game will always be drawn snapped to pixel coordinates. We now have grass and animated palm trees decorating our pixel perfect island. In the next lesson, we'll add a script to our camera, which will follow the player allowing us to make levels that are larger than one screen. I'll see you in the next lesson. 24. 2-3 Camera: Oh friends. In the previous lesson, we decorated our island with vegetation. In this lesson, we'll have the camera follow the player around the level. The easiest way to accomplish this would be to simply child the camera to the player. But this approach is very restrictive and can cause motion sickness. Camera movement should be more subtle and show the player what's ahead of their character, having the player character in the camera as siblings, we will need the camera to react to the player's actions and have its own scripted behavior in response. Let's start by creating a new script for the camera. We can just call it camera and make sure it's saved in the scripts folder. This camera will need to know what it is following. Let's export a private variable which we will call underscore subject. The type of this doesn't need to be a character body two D. Instead it can be something more generic like a node two D. If you look in the scene tree, you'll notice that the nodes have different colors, most of which are blue. These blue nodes are all node two D's, but are more specific types of node two D's, including the camera itself. There are two D characters, two D static bodies, two D animated sprites, et cetera. Selecting any of them, you'll see in the inspector that they have the properties labeled node two D as well the transform property which contains their position, rotation, scale, and skew. By setting the type of our subject to node two D, the camera will be able to follow anything in our scene that qualifies as a node two D. Since we only need to know that it has a position for the camera to follow it, Click and drag the player character into the exported field for our camera subject. In the process method, which will run 60 times per second, we can simply set the position of the camera to the position of the subject. This will be the same behaviors when the camera was childhood to the character without the vertical movement, severely reducing motion sickness. It would be more helpful if the character wasn't centered in the camera's view though. But instead, it should look ahead of the character and slightly up so that the player can see more relevant parts of the level. Like with the animated sprites, we can add an offset to our camera script to shift it from its original position. We'll make this an exported private variable, underscore offset with the type of vector two. A vector two contains two floats, an x and a y value. It is used to define anything in two dimensions, including the position variables that we've been working with. Now the process method can simply add the x portion of the offset to the camera's X position. If we position the character exactly at the scene origin, we can move the camera to give us an idea of where we think it will look good. Then use the camera's current position as the offset value. Alternatively, you could define the offset in tiles and multiply it by Google Ppt in the ready method. Now the camera will follow the player's horizontal movement while looking ahead to the right. But what if we don't want our levels to be so linear? What if the player wants to go left? The camera should look to the character's left too. The camera will need to react to an action performed by the character. We have two functions in our character script, which are called whenever the player faces left or right, but these are called constantly with every input. Let's only call these functions when the character actually changes direction. To do that, we can export a private variable to store whether or not the character is currently facing left. As a Boolean. The face left and face right methods will set this value to be true or false accordingly. Then at the start of the physics process, we can add conditions to only call face left if the character is not already facing left, if they are facing left. Now we have our face left and face right methods only being called when the player chooses to change their direction. We should also call the appropriate face left or face right methods during the ready method based on the value of the exported variable. This also has the benefit of making this function work with the characters whose sprites are facing left. By default, the camera script can now react to the character changing directions using signals. At the top of the character script, we can create a custom signal which we will name Changed direction, and add a parameter telling the camera whether the character is currently facing left. Now the face left and face right methods can tell this signal to emit passing in whether or not the character is now facing left or not as an argument. With the character notes selected in the scene tree. Switch to the node panel, Right click on our new signal and select Connect. Then select the Camera. Note from the list. The camera will listen for this signal. We can rename the method which will be called as a result. To put it in terms that are easier to understand within the context of the camera, let's name it on Subject changed Direction. The method is added to the camera script automatically. Now we can change the cameras offset to look left or right. Since we know which direction the character is facing To preserve the value of offset, let's create another private variable named look Ahead distance. Which starts off as a copy of underscore offset X set during the ready phase with at on ready. Then we can set the look ahead distance to be the X offset, but multiplied by negative one if the subject is facing left or positive one if they are not. Then use the look ahead distance in the process function to set the camera's position. Now the camera will look ahead of the character no matter which direction they're facing. But what if we want our levels to go up and down as well? We can use a similar method to have the camera react to the subject emitting a signal. This time moving the camera when the character lands at the end of their jump, adjusting the camera to a new height in the character script. Let's add another signal called landed and pass a parameter called floor height, which will be a float. How do we know when the character lands? Well, we have the handy is on floor method. If we store this value in a private variable, we'll call it was on floor as a Boolean. We'll record it here. Above move and slide. Then after move in slide, we can check if the character wasn't on the floor and now is on the floor, which means this is the exact moment when they landed. Let's call a new private method here called underscore landed. Writing a definition for this method, we don't really need to do anything else here right now, besides emit the landed signal passing in our Y position as the new floor height. Telling the camera to listen for the signal, the camera can then call a new method called on subject landed. All we need to do is adjust the value of the camera's Y position to be the new floor height plus the Y offset. We now have the camera following the player, allowing us to make levels that are larger than what we can fit on a single screen, but the movements are jarry. In the next lesson, we'll make the camera move gently between these positions using tweens. I'll see you in the next lesson. 25. 2-4 Tween: Hello, friends. In the last lesson, we move the camera around, following the player as they move right, left, up and down. In this lesson, we'll have the camera gently sweep between these positions. The simplest way to gradually adjust values over time is to use a tween. Let's declare two new private variables. At the top of our camera script, we have two different signals triggering two different behaviors in our camera script. We want these to stay separate from each other. The first variable will be called look ahead tween, the second floor height tween. Both are of type tween. Starting with the look ahead tween, when our subject changes direction, we can set the value of look ahead tween to create tween. This is a built in method we can use to create our tweening behavior quickly and easily. We then tell this look ahead tween to tween a property starting with which node the property belongs to which is itself. Then we designate in quotation marks the name of the property. We will tween the value of look ahead distance to become this value we already calculated over a duration of time. For now we'll say 1 second. This looks better. But if the player changes direction while the camera is panting, we shouldn't have two tweens created at the same time competing over control of the camera. It doesn't appear to be causing any issues. But we can eliminate the possibility by first checking if the tween already exists and is running. If this is true, then we should kill it before starting another one. This tween is currently linear and has a duration of 1 second. But we can easily customize it to create a wide variety of effects. First, let's export a float variable called underscore duration and give it a default value of one. Then plug this variable into the tween method call. We can now adjust the speed that the camera will pan by simply changing the value of this variable in the inspector. Remember that you don't need to stop the game to adjust values in the inspector. I think this should be a bit slower in case the player turns their back to an enemy, but doesn't want them immediately removed from view. For example, to change how the camera moves over time, we can add easing and transition types to the tween, causing it to move slower or faster at the beginning or end. Even bounce or move beyond the defined limits. Let's export a new private variable named trans type. The type of this variable will be tween transition type. Then when we create the tween, we can also call another method, set trans pass our transition type as the argument to this method. We can do this because both the create tween and set trans methods return the tween. As a result, the create tween method creates the tween and returns it, which is then used to call the set trans and returns the tween again, which is then assigned to our variable, selecting the camera in the scene tree and looking at the inspector, you'll see that the transition type default is linear, meaning that the value progresses evenly over the duration from the drop down. There are a variety of options to alter how the value will change over time. We can also add another variable called easing type, similarly typed tween ease type. This will alter the transition to affect only the beginning of the end of the tween or both. Just like with the transition type, we can also set the easing type in the same line of code. When we created the tween, try experimenting with different durations, transitions, and easing types to see how they feel. We can use the same technique to gradually adjust the camera's current floor height over time after the subject lands. Instead of using a hard cut, first we need to store the current floor height in a private variable. Then when the subject lands, we can copy most of the same code from when they change direction, only changing the tween variable from look ahead to floor height and also changing the property name that we're tweening the value. We will tween two is the same as the method parameter. Then we can edit the process method to set the cameras y position to be the floor height plus offset y. Now the camera will gently pan up or down after the subject lands adjusting to a new floor height. If you want these two behaviors to have different durations, transition types or easing types, that is as simple as exporting more variables for them. I would like the horizontal painting to be slower and more gentle, but the vertical to be quicker and more reactive. I'll have a longer duration for the horizontal, but also have the ease type to be both in and out. For vertical, I'll have a shorter duration and only ease out. The camera moves faster at first and slower after we. Depending on which version of do you're using, there might be a problem with moving both the camera and the character at the same time, creating a jittering effect. To fix this, try opening the project settings. Looking under display window for V sync at the bottom and disable the setting. Now we have our camera, showing the player exactly what they need to see in a smooth, gentle manner. In the next lesson, we'll add an animated background to our scene. I'll see you in the next lesson. 26. 2-5 Background: Hello friends. In the previous lesson, we finished our camera's behavior script, so it follows the player character. In this lesson, we'll add an animated background to our level. The level background needs to give the impression that it is very far away. Otherwise, the environment will appear very flat and two dimensional to the player, we can create an illusion of depth by adding a child node to the camera. A node two D, it will have a position value as well as a Z index, a name background. Then expand the ordering section under canvas item and set the Z index of this node to be a negative value. The level terrain is using the default Z index of zero. A negative number will be drawn behind depending on how many layers of depth you want in your environment. You may want to put the background z index farther back than just negative one. I'm going to put the background at negative ten, leaving negative one through negative nine available for anything that needs to be in between the background and the terrain. Even though I'm not planning on doing that, it's just better to leave the possibility there. Now, every child node we add to this node will automatically follow the camera and be drawn behind everything else in the level. The asset pack contains several sprites we can use to assemble a background environment. We can simply click and drag the images for the background into our scene. And Godot will automatically turn them into sprite two D nodes group selecting all the new nodes. Make them all children of the background node. By dragging them into it, I'll just stretch the sunset, the sky and the water images so they cover the entire viewport of the camera. Let's make the background its own scene so it can be edited in isolation and save it into the scenes folder. Then click on the clapper board icon to open it up. In the same folder, there are some sprite animations to make the water twinkle. Let's add three animated sprite two D's into our seam. We can then populate each of these with a sprite frames resource. And populate the sprite frames with each of the three sprite animations. Also, make sure that they autoplay their animations looping with the correct frame rate, then position each in the water where they will look nice. When you're done, you can save your work and see how it will look by running the main scene. Next, let's add some clouds into the sky. These aren't animated, so we can just drag them into the two D view to make sprite two D nodes. If you want to adjust how the sprites are layered, instead of adjusting the Z index value of each sprite, we can also use the scene tree to re order the nodes. Nodes with the same Z index will be drawn from the top of the scene tree to the bottom. Simply organizing the list of clouds by their size will also a sort their order and put the smallest cloud in the back and the largest cloud in the front. Wow, wow. This largest cloud is also already larger than the camera's viewport and has these hard edges. It's designed this way to be looped around on itself using a technique called parallax scrolling, duplicating the sprite node. We can place two of them in our scene and move them gradually to the side. Then when one moves off screen, we can reposition it to the other side, causing it to loop infinitely in the background. This will further add to the illusion of depth that the background is far away, but also create the illusion that there is wind. Let's add a script to the root node of this scene, which will create the parallax scrolling effect. First, we'll need to get a reference to the child nodes which we want to move, we can use at and ready to store these in variables, making sure that we put the exact names of the nodes after the dollar sign in their assignments. Let's also export a variable for scrolling speed, which is a float based on the palm tree animation. It is implied that the wind will be blowing to the left. Let's use a default value of negative 100 in the process method. We can then add a scrolling speed multiplied by delta to the exposition of the clouds, causing them to move left at a constant speed. But we're going to do this to five different clouds. So it would be better to make this method taking a node two D as a parameter along with the distance it is being scrolled as a float. Then we can just add the distance to its position. Now the process method can call this method, passing in each cloud along with the scroll speed multiplied by delta. To calculate the distance per frame, we can further improve the illusion of depth by also having the clouds move at different speeds, With the larger clouds nearest to the player moving faster and the smaller clouds further away moving slower. But avoid using speed multipliers which are multiples of each other. This will form a very obvious pattern and break the illusion if one cloud speed is exactly half of another. For example, the player will notice it helps to use prime numbers for. The last thing we need to do is check if any of our clouds have moved completely off camera, then move them over to the other side. If we position one big cloud in the middle, the other is now where it will be when we want it to loop around, which is also the pixel width of the image. Let's make this width value exported variable float type with a default value of 448. Checking if the position x of a cloud is less than with times negative one. We can then move it to the right by width multiplied by two to put it on the other side of the second big cloud. This will also make the other clouds periodically loop around on their own two. Let's see how that looks beautiful. However, as soon as your player resizes the game window, the illusion is broken. Opening the project settings under display window, we can set a desired resolution for our game. More importantly, we can change the stretch mode to stretch canvas items, which is everything in our two D game. We definitely want to keep our aspect ratio the same even if the player resizes the window, A new feature recently added. We can also restrict stretching to only scale by integer amounts. This can stop our pixels from being drawn at inconsistent sizes. Once you've decided on a resolution setting, make sure your background fits the new settings, and it should be impossible to see outside your background. Now we have a nice cloudy sunset in the background of our level. In the next lesson, we'll add water into the foreground. I'll see you in the next lesson. 27. 2-6 Water: Hello, friends. In the previous lesson, we added an animated background to our scene. In this lesson, we'll add water into the foreground. For this lesson, I've downloaded and modified another sound effect for water splashing. This sound effect was created by Yin Yang Jake 007 on Freesound.org Just like the background, we can start by creating a root node for the foreground. This time using an area two D node and name it water. Then set at z index to a positive number, so it will always be drawn in front, leaving room for extra layers in between. The assets for water in the asset pack have an animation for waves and a flat square for everything else. Let's add an animated sprite two D node for the surface of the water. Create a new sprite frames resource. Add the sprite frames autoplay loop and then set the frame rate, add an offset or move the animated sprites transform so that the water's origin is in the upper left corner. This will make it easier to line up with the tile map and also provide the Y value of zero being the water surface. Then also add the bottom sprite as a sprite two D node. While the bottom can easily be stretched to fill any area, the surface will need to be duplicated and repeated to keep the scene tree organized. We should create another node two D, to act as a collapsible folder holding these animated sprites. The area two D needs a shape to define how its collision will work. Water physics needs two different behaviors. When something is on the surface of the water and when it is under the water, we can use a line segment drawn over the surface of the water, since that will tell us if something is touching the surface or not. To make things easier, make sure that the origin of the water object is in line with the surface collider. Let's also quickly duplicate one of our dust particle scenes to create a splash scene. Then delete the sprite frames in this scene and replace them with the splash one sprites from the asset pack. In order for the water to react to collisions, we'll need to create a water script. This script will need to react to two signals when a body enters it and one body exits it. We can simply connect these signals to the script itself using the default names. The body parameters of these methods are of type node two D, as you can see from the signal list. But in order to define how our characters will behave in relation to the water, we need to know if this node two D named body is a character or if it is something else. We'll have to give our character script a class name before the word extends. In the first line, add class name, character. This is now a word that other scripts can use to refer to this script as a general type. Back in the water script, when a body enters the water, we can now check if the body is a character, Then call a method we haven't defined yet, which we will name enter water and pass in the y position of the water, which is the water surface in the body. Exited method. We can perform the same check to see if the body is a character. Again, when a character exits, meaning that it is no longer touching the line segment covering the surface of the water, One of two things could be happening. Either they are now above the surface of the water or they are below the surface. Since we know the Y position of this node is the surface of the water, the body also has a Y position. We can compare the two values to determine which case this is. But also adding global PPT divided by two or a two tile. If the body position is less than or equal to the water surface, that means the body has stopped making contact with the surface of the water and is entirely above the surface of the water. Since pixels per tile is defined as an integer, but position y is defined as a float, Godel will warn us that decimal values will be ignored. We can remedy this by casting the integer value into a float value here and the character is exiting the water. Otherwise, the character is below the surface of the water. And we should call a different method, which I will name dive. Switching to the character script, we can add these three method definitions to our public methods. Enter water, which takes a float value representing the surface of the water as a parameter. Also, dive and exit water. The purpose of these public methods is to let the physics process and jump methods know where the character is and how they should behave. We'll need to add some new private variables. The water surface height as a float, and two booleans telling us if the character is in the water and if they are below the surface. Each of our new methods can now set these variables appropriately. Enter water sets the water surface height tells us that we are in the water but not below the surface exit. Water will set is in water to falls. Dive will simply set below surface. To be true for the physics, we need to consider whether the character will float or sink, as well as how much being in water restricts their movement. We can add a new category of exported variables to our script named Swim. For the sake of simplicity, the value which determines whether or not a character floats, we can call density and give it a default value of negative 0.1 This value will be in comparison to the density of water. A value of zero will have perfect buoyancy, less than zero will float, greater than zero will sink to restrict movement. We can also define a value for drag, which will be multiplied by forces to reduce their effectiveness. And use a default value of 0.5 For starters, when an object first reaches the surface of the water, there is an impact force reducing their velocity In the enter water method. If our velocity y is more than zero, we can multiply it by drag To simulate this impact force, just like we did with the ground in air physics, we can first check in the physics process, if the character is in the water, then apply water physics, making sure to pass delta, changing if to else on the next line, checking if they are on the floor. Horizontal movement in the water will behave much the same as on the ground, but with the deceleration and acceleration also multiplied by drag to reduce their effectiveness. Since I copied this line from above, I need to change deceleration to acceleration. The vertical movement will depend whether the character is below the surface of the water or if their density is greater than zero. In either of these cases, we will need to move their Y velocity towards buoyancy, which is gravity multiplied by density, and also apply drag to slow down. The rate of change is calculated using gravity times drag times delta. If the character is touching the surface of the water, then we want to make them bob up and down. Which can be divided into two situations with another if statement. If the characters center of buoyancy is above or below the surface of the water, then adjust the y velocity to move up or down accordingly. We can simplify this to be if the position y of the character minus one quarter of a tile is less than the surface height of the water. For simplicity, we can just copy the formula from above multiplied by negative one if they are below the surface of the water to move in the opposite direction. The last thing we need to do is alter how jumping works while in the water. If the character is in the water and below the surface, then the jump velocity should be affected by drag. If the character is not below the surface, then they should have the full jump force so they can easily jump onto land. We can also emit the landed signal here to adjust the camera. Also when they enter the water to also the stop jump method should be disabled while in the water. While we have the character script open, let's copy the spawn dust method and use it to create a splash method. In the water script, we will need a reference to the packed scene, which contains the splash. Renaming our variables and methods accordingly. Since the water is creating the splash and the water doesn't move, the splash can be childed to the water, no problem. The splashes y position will default to zero, which is already the water surface. And its x global position can be set to the value passed into the method as an argument. This will be the position of the body which entered the water to create the splash. We can set the splash X position to match this exactly. The water also needs an audio stream player two D to generate the splash sound effect. Populated with the modified file I downloaded from Freesound.org The script can get a reference to this child node during the ready phase, then tell the sound effect to play. We can generate a splash anytime a body enters the water passing the body's position. And also when a character body chooses to exit the water, positioning the water where the player can access it and remembering to populate the splash packed scene in the inspector, we can give it a quick test and make any adjustments we wish to the character's density drag or the calculations of buoyancy or the popping at the surface until it feels good. With the water fully functional, let's make it encompass the entire level's foreground, stretching the bottom, duplicating the surface, and editing the collision shape to match the floor we created in the very first lesson may still be in your way too. Now we have the water in the foreground of our level and characters can swim in it. In the next lesson, we'll structure our level and add boundaries. I'll see you in the next lesson. 28. 2-7 Boundaries: Hello friends. In the previous lesson, we added water into the foreground of our scene. In this lesson, we'll set up the structure for our levels and our boundaries. First, the tile map is currently triggering the splash noise When we run our scene, adding a condition to the body entered method can return if the body is a tile map, preventing this code from running. In this case also, some of the water animations may not have been synchronized when running the scene, which is only a temporary issue caused by having the animations playing in the editor. If you're seeing a seam on the scrolling clouds, you can also reduce the width property by one pixel. We should also adjust the remaining characters colliders so they can stand cleanly on the floor. Our scene tree is now full of many different components. The label and floor nodes are no longer relevant. Let's delete those. We should separate all the nodes that will be used to build different levels into one branch, making all of our decorations into children of a node two D. These become easier to organize, do the same thing with our enemies, making them all children of a node two D to keep them organized. Since these are all components of our games level, we can create a new area two D to hold them and name it level. Then make the tile map decorations, enemies and water children of the level node. For the sake of simplicity, let's temporarily set the level's origin to be the player's starting location and move the player to the scene origin. Then adjust all the child nodes of the level to match save the level as its own scene, which belongs in a new folder named levels. We can name this level one, one. The player character Camera and background will be used for every level since the asset pack does not contain any other assets for backgrounds, depending on how you plan to design your game, the background may also be part of the level. We can now open the level one one scene. Since we made the root node of our level into an area two D, that means we can give it a shape. Let's define our level as a rectangle. And adjust the size and position of the rectangle to define boundaries to which the player and the camera will be confined. And adjust the D bug color of this collision area to be more transparent. It doesn't affect our view of everything else. Creating a new script for the level, we can get a reference to the collision shape two D node during the ready phase. The purpose of this rectangle is so the player and the camera will know where to stop. We'll need to get the minimum and maximum values allowed within the confines of this rectangle. Let's write two methods, get min and get max, which will be public and return a vector two. The minimum value will be the collision shapes position minus half of its size. But to access the size, we need to first access its shape, then the rectangle, then the size, and repeat for the maximum value. To avoid repeating this code multiple times, we should also define this as a variable, name it half size. Returning to the main scene. The purpose of this scene is to facilitate communication between the player character, the camera, and the current level, allowing us to easily swap out the level with a new one as needed. You can rename this scene and its root node to reflect this purpose. In a simple game like this, you can call this the main scene scene, or the game scene. If your gameplay loop includes other gameplay besides platforming, you may want to name the platforming scene to distinguish it from other gameplay scenes. To manage the rules of how this gameplay scene will function, we should give it a script. The name of the script will usually be the name of the scene followed by the word manager. This manager's job is to make sure that all of the child notes have all of the information they need to do each of their unique jobs. In order to prevent the player character or the camera from leaving the boundaries of the level, they need to know what those boundaries are. Since this scene will be capable of running any level, it will need to request the information about the level's boundaries from the level script and pass that information to the player character script as well as the camera. At the top of the manager script. Let's first get references to the level, the player and the camera inside the ready method. We can then get the boundaries from the level and set the boundaries for the player and the camera. Now both the character and the camera scripts will need public methods for setting these boundaries, then also enforce these boundaries on themselves. Starting with the character, we can simply create two new variables of type vector two and store the minimum and maximum values. Write a set bounds method which takes two vector two and sets the values of the private variables. Then at the bottom of the physics process, we can restrict the character's position to be contained within these limits using the clamp method, providing the current value a minimum and a maximum. It's up to you if you want to impose these restrictions on all characters in your game or just the player character. But I think that the enemies should be free to leave the level boundaries in my game. I'll make this last step contingent on whether or not these boundaries have been set or not by also adding a Boolean variable named is bound. When the set bounds method is called on the player character, it will also set this variable to true, but other characters will remain unbound. The camera will be slightly more complicated since the camera itself also has a shape. Copying the same variables and set method into the camera script. We can edit the values of min and max to accommodate the size of the camera's view. We can retrieve this value using get Viewport wrecked size divided by zoom and reduced by half. Then add this value to the minimum and subtract it from the maximum. It's almost always better to store any calculated value in a variable rather than calculate it more than once. Then we can clamp the camera's position the same way we did the characters. Let's try it out. The cameras view is contained within the level boundary as is the character's origin, and it works on all sides. We can keep all of Roger on screen by applying the same logic, using the size of the sprite. But because the sprite isn't centered about the origin of the character, we need to calculate the x and y values differently. Now Roger will only be allowed where the entire sprite will remain on screen. Throughout this section, we have developed many of the features that will be used to generate levels for our game. In the next section, we'll add collectible treasures and a user interface to our main scene. I'll see you in the next section. 29. 3-1 Data: Hello friends. In the previous section, we built many of the structural components We need to build levels of our game. In this section, we'll create collectible treasure for the player to collect and disperse it through our levels. If you completed the assignment, you should have two basic levels built with different terrains, decorations, and boundaries. As you completed this task, you probably also made adjustments to be a better fit or feel for your game. For example, I slowed down the scroll speed of the clouds to negative 32 pixels per second because I didn't like how they looked when the camera tweeened. As the camera turned around, I reduced gravity by about half of what it was before and altered the values for all the characters, locomotion and swimming. I also made a small correction to the splash sound effect in the water script. Since the audio player two D node reduces the volume based on proximity to the camera, the sound will get more quiet the further you were from the beginning of the level. To fix this, I set the global exposition of the audio stream player node to the exposition passed into the method the sound will originate from the same location as the splash at full volume. While tutorials should always be the last thing you build for your game, I'd like to take the opportunity to go over some level design principles for intuitive learning. For the first island level, I started the player off with an immediate obstacle that they must jump over, followed by a higher obstacle and an even higher one. After that, this should be sufficient for the player to understand that they can hold down the jump button to reach the top of the second, but not the third obstacle. I introduced the tree as a one way platform in a safe environment, and require that the player learn how to use it before reaching the next section of the level. Here the same trees are available, with slightly more risk being introduced, having to jump from tree to tree, and potentially falling in the water. If they fail, the risk isn't real, though only perceived by the player. I've created three different paths from this part, with the easiest being the path forward, and the other two potentially leading to rewards. All are plainly visible, teaching the player that they should be looking out for more branching paths like this in the future, the next time I hit something like this, the player will see the reward first, but be required to turn back to get it again, teaching the player what they should be looking for. This is the first time I used a background tree. Because I didn't want the player to think that they could jump on this tree, fail, and falsely learn that all trees are not platforms. By this point, the player has experience using foreground trees as platforms. This tree is positioned to be jumped onto from the tree to the left or from the ground. This teaches the player that only background trees are not platforms to proceed, they must ignore the background tree and jump from the ledge. Instead, in case the first tree didn't work, I followed it up with a second tree meant to lure the player into trying to jump onto it. And instead, following. Here's another secret cave. But this time the player can't see it. If they have learned from the previous parts of the level that they should explore into the water, they will be rewarded. All of these entrances into the water are clearly marked with rays of light, two, which help grab the player's attention and make the water look inviting. I have placed foreground and background trees together to test the player's ability to jump up to the highest tree. The trees are further distinguishable by their coloring and layering in front of or behind the player. Using consistent colors or lighting to attract player's attention is called using visual language or affordances to tell the player that they can or should do something at that location or using that object. Many games use these techniques to indicate climbable ledges, breakable objects, interactable NBC's. Or to tell you when you should use a specific weapon or ability. Moving the first level out of the way, replacing it with a ship level and renaming the nodes. I can then play the other level instead. By the time the player reaches this level, they will have a good understanding of the platforming mechanics and don't need to be taught. I instead focus on creating the overall look and feel of a pirate ship, shaping the entire level to represent a hull. And added extra tiling to hide the background until the player reaches above the water level. I decorated specific rooms and dead ends with barrels and bottles, And positioned staircases in a thematic way and prevented the player from ever leaving the ship. Before the player can collect any treasure, we will need to create a script to know how much treasure they have. We can put this script in the Autolodes folder and name it Data. But instead of extending node, this time we need to extend. We can remove the template. The purpose of the script will be to hold all the information about a player's progress in the game. To get started, let's just add an integer, which will be the number of coins the player has collected, and another integer to represent the number of lives the player has remaining. Exporting these variables will allow us to view them in the inspector while the game is running. If we need to, the default value for an integer is zero, which is fine for a player's coins as a starting value, but not so nice for their lives at the start of the game. We should define exactly what this resource will hold when it is first created. Underscore in it, we can set the initial values for each variable, as well as perform any other logic we want. As part of the resource initialization, I would like players to start my game with zero coins and three lives. In order to reference this resource by its type, we need to give it a class name. Let's name it Data with a capital D. As our game becomes more complicated, this data resource will contain many more variables of different types to track the players progress. Now we have a place to store this information, but we need the scripts in our game to be able to access it freely. Like we did with the global auto load, we can create another auto load whose responsibility is to access and manage the data. Let's name this file will contain a variable called data with a lower cased of type data with an upper case D. The purpose of the script will be to give the rest of the game access to the current data file, but also manage the data file. Here we will need to write methods for starting a new game saving and loading two. We're really only interested in creating a new data resource. We should set the value of data to be data, new data new will create a new data resource and automatically trigger the init method we just wrote, setting the lives to three instead of zero. For now, we can simply call the new game method when this node is ready. Opening the project settings, switch to the auto load tab, Then add the new file script to the list of auto loads. The default node name will work fine if we run this scene. We can switch back to God while the game is running. Then switch from local to remote in the scene tab. This will show us the scene tree for the game that is currently running. Selecting the file auto loaded node, and looking in the inspector, we can see that it has a data resource. The name of the data resource is object ID, followed by a long number. Clicking on the resource, we can view and edit its contents. Any of our scripts can access this information easily. To demonstrate, let's open the game manager script. And after doing this usual stuff with the level boundaries, simply print out the value of filed lives Running the scene, we can see number three printed into the output panel. We now have a custom resource set up to store our players information that we can access at anytime. In the next lesson, we'll create coins that the player can collect. I'll see you in the next lesson. 30. 3-2 Coins: Hello friends. In the previous lesson, we created a custom resource to track the player's progress and data. In this lesson, we'll create collectible coins. We can disperse throughout our levels for the player to collect. For this lesson, I've imported a set of coin clicking sounds from Freesound.org made by Val Inspire with a Creative Commons license. Let's start by opening our first level and creating a new node two D folder for treasure. Coins are physical objects that exist in the world. We'll need to detect collisions. We may also want them to be affected by gravity. The node which defines these behaviors best will be a rigid body two D node. Let's rename it to silver coin in order to be able to see our coin. Let's first add an animated sprite to it. Create a new sprite frames resource. Find the silver coin sprites in the asset pack and populate the default animation. Set this default animation to autoplay, looped and set the frames per second. We can also add a second animation to this animated sprite by clicking on the add animation button name. This animation effect, then populate it with the coin effect sprites from the asset pack. This animation should not be looped. This is the animation which should play when the coin is collected before it will disappear. Switch back to the default animation. So we can see the coin size and shape clearly in the editor. Now that we can see our coin, as with all physics objects of these collisions, we will need to give it a collision shape, creating a circle shape resource. We can resize it to fit the size of the coin you may need to turn off grade snapping. Collisions with coins also typically generate sound effects. We should add an audio stream player to de node to it as well and populate it with the coin Cl sound effect. Let's save the silver coin branch as its own scene and put this in a new scenes folder named treasure. Like everything else, coins will need a script to control how they behave. We should start organizing our scripts into designated folders. I'll create a nude folder for treasure scripts. We can start our script by grabbing references to the sprite and audio player nodes during the ready phase With the coins root node selected, connect the body entered signal to itself so the coin can react to collisions with other bodies. When a body enters the coin collider, we should first play the sound effect. Then we want to check if what the coin collided with is anything besides a character, and if it is not a character, return so it is ignored. If this is indeed a character, we can tell the animated sprite to play the effect animation. Then this node to be removed from the scene. With a free, this code will all run in a single frame. We won't get to see the animation play out. We can use a new command here called a weight to pause this code until something happens. The thing we want to await will be when the sprite animation is finished with the coins root node selected. We'll need to change a few of the default settings for the rigid body node. By default, the body entered signal will only happen when the colliders overlap. But since physics are being applied to both the character and the coin, this will not happen. The characters collider will push the coin collider instead. We can change these settings to allow the signal to happen when the colliders make contact. By setting contact monitor to true max contacts reported to any value greater than zero, but we should really only need one next. Expand the deactivation section. Most people wouldn't want pixel to rotate, so we can lock the coins rotation by clicking on this checkbox. Collectible coins in most games fall into one of two categories. Those that hover in the air and those that are tossed around after breaking a box or defeating an enemy. We can make the first option by setting the freeze property to true and changing the freeze mode to Kinematic. Now the coin will not be affected by physics, including gravity, but will still collide with other objects. If we want to turn on gravity or have the coin tossed around, we simply set freeze to false and apply whatever forces we want to it. We also want to make sure that our coins are only collected by the player character, not the enemies or any other characters. The simplest way to achieve this is using collision layers. So far everything in our game has been using the default collision layer, layer one. Using different collision layers, we can easily control which objects react to or ignore other objects. Let's let the default layer, layer one, represent the terrain. Since most, if not all, objects will need to collide with that, by default, we may want to have different types of environments with different types of collisions in the future, let's just let the world use the first eight collision layers opening Rogers scene. We can change his collision layer to layer nine and let the second block represent our player collision layers. Likewise, we can put the enemy characters on layer 17. And let the third block represent our enemy collision layers. Finally, the coins can be on layer 25, with the fourth block representing treasure. The mask section of collision layers are what this object will collide with. The only thing we want the coin to collide with will be the environment. And the player which we have set to layers one and nine coins will now ignore collisions with enemies as well as other treasure. I will make the player character collide with enemies, enemies collide with the player as well as other enemies. We should also open the project settings and give each of these collision layers names so we can easily remember what we've set them aside for. The names will be displayed as a tool tip when hovering over the collision layer in the inspector. There is a second set of coin sprites in the asset pack for a gold coin two. Let's duplicate our silver coin scene and rename it to gold coin. And replace the silver coin sprites with gold coin sprites if we want different coins to have different denominations. We can also add an exported integer value to our script and give it a default value of one for my game. I'll make gold coins have a value of ten silver coins. While unlikely, it is possible that after the player collides with the coin, they could collide with the same coin a second time before it disappears. To prevent this, we should set the collision mask of the coin to zero, removing any possibility that it will collide with anything after it's been collected. Placing one of each coin in our level, the player can now collect them. We can also place water on a separate layer from the terrain and have it collide with both characters and treasure, and name the layer in the project settings. We now have collectible coins of varying value that the player will be motivated to collect throughout our game. In the next lesson, we'll create a user interface with a counter to show the player how many coins they have. I'll see you in the next lesson. 31. 3-3 User Interface: Hello friends. In the previous lesson, we created coins of different value for the player to collect. In this lesson, we'll display how many coins the player has on the user interface. In the main platform max scene, we can add a user interface for displaying all kinds of important information the player needs. This information should be independent of the camera and always displayed in front of everything else. Will you might be tempted to make this a child of the camera like we did with the background. There is a no type for creating this easier called a canvas layer. Every two node n arsene has a draw order based on its set index and its position in the scene tree. But after everything has been processed by the camera into a single image, all of that becomes the default layer, layer zero. A canvas layer will by default, draw a whole new image onto layer one. Over that, canvas layers are populated with a new node type. We actually used one in the very first lesson. These are called control nodes and are marked in green. To display numbers on the screen, we could use a label node, which can display any text that we want, but it wouldn't really fit our pixel art aesthetic. And our asset pack comes with nice number sprites, so let's use those instead. We can add control nodes to the canvas layer called texture Rets to display these sprites for us, let's add a texture for the one digit, another for the ten digit, and populate them both with zeros. By default, you will need to set a limit on how many digits you want to display on screen. Following the conventions of games like Mario and Donkey Kong, I'll cap the number of coins at 99 and give the player an extra reward for every 100 collected. We should also add an icon texture to tell the player what this number means and populated with the image of a coin to avoid manually rearranging individual control nodes. On the canvas layer, there are also nodes provided by Godot, whose purpose is to organize their child nodes for us. Let's add a horizontal box to the canvas, name it coin counter, and set our other nodes as children of the box. They are automatically rearranged to fit horizontally within the box. I'll position this counter 32 pixels away from the corner. And increases scaled two, it's much easier to notice and read. We can then edit the settings of the individual controls to determine how they will be drawn in relation to their parent container. I would like the icon to be displayed, fitting proportionally to its width. And scale up to fit the size of the parent container. The digits, I would like to double in size so they're easier to read. Knowing that there are five pixels wide, I'll set their custom minimum width to ten pixels. Fit them proportionally to their height. And keep their aspect ratio while also keeping them centered in the parent. Notice how the canvas controls are being drawn here in the water. But if we hit play, they are displayed in the upper left corner of the window. If you recall from the first lesson, the image being drawn on screen by default is this blue rectangle. If it helps, you can hide the level, character and camera while working on the canvas by clicking on the icons. Remember to unhide them when you're ready to test your game. Try experimenting with how your counter is displayed on screen, and check how it looks while playing. To make the counter work, we'll need to write a script for it. I'll put this in a new scripts folder for UI and name it Counter. Since the nature of a coin counter has nothing to do with the organization of a horizontal box, I'll have it extend the more generic type of control. Instead, we will need references to each of our texture recs that we wish to change set during the ready phase. We will also need a list of textures to swap them with, representing each of our numbers 0-9 We can store these in an exported array of texture two D's named underscore digits. An array is similar to a list, in this case a list of two D textures, or pictures of numbers looking in the inspector. We can click on this exported array to expand it and give it a size of ten. The array elements are conveniently numbered zero through nine. These are the indices we use to access the individual elements of the array. Populate each array index with the matching digit from the asset pack. This script needs a function we can call to set the number which is being displayed. I'll call it set value and take an integer as a parameter. Knowing that this counter is only meant to display a number 0-99 Let's first enforce this rule. By clamping the value between these numbers. We can set the texture being displayed by the ones texture k, to be digits at an index. What is the index? It is the same as the digit itself. But how do we extract the one digit? We can use an operator common in programming called modulus, represented by the percentage sign, which returns the remainder of a division value. Ten will return the one digit, which is the array index of the texture we want displayed. We can then also set the tens digit by performing division instead of modulus. Now we need the player colliding with our coins to somehow update our user interface. But these exist in different scenes, making signals or method calls somewhat difficult. To bridge this gap, we can delegate this responsibility to the game manager since it is easily accessible as the root node and has access to all the children. Opening the coin script. When the coin is collected, we can get a reference to the scene root using dollar sign root followed by game which is the name of the scenes root node. Then call a method in the game manager script which we haven't written yet. We'll collect coin and pass in the value of the coin being collected. Switching to the game manager script, we will need a reference to the coin counter during the ready phase. The type of this doesn't need to be a horizontal box. Since we aren't accessing anything specific to that node type, we really only care that this is some form of control node. First, we can give this collect coin method of definition, taking the integer value of the coin as a parameter. Next, we will add the value of the coin to the file data. Then update the counter on the UI, setting its value to the file data's new coin value. Also, this updating of the counter should happen when the seam is first loaded too. Let's also test the counter by setting its value to something random like 77. Running the scene, we can see that it was indeed set to 77. And when we collide with a silver coin, the counter goes up by one. Collecting the gold coin increases it by ten as well. Feel free to test setting the counter to any random number, a negative number, or something higher than 99. But remember to delete this line. When you're done, God gives us a warning that we're dividing by an integer. Clicking on the warning takes us to the coin script, where we are indeed dividing by an integer, and decimal values are being ignored. Since this is on purpose, we can add an extra line here at integer division. To ignore this warning, we now have the user interface displaying how many coins the player has collected. In the next lesson, we'll add a collectible life item and track that as well. I'll see you in the next lesson. 32. 3-4 Lives: Hello friends. In the previous lesson, we created a coin counter to display on the user interface. In this lesson, we'll add a collectible life item to our game. Let's start on our first level scene. The asset I would like to represent, the player's lives in my game is a golden skull. And I don't think it would look good to have it affected by forces like gravity. Unlike coins, I want it to appear more ominous and mysterious. It will always be something that floats until it is collected. We'll use an area two D node to define its basic properties and rename it to Golden Skull. Then add an animated sprite. Two D, create a sprite frames resource and populate it with the golden skull sprite assets. Autoplay loop and set the frames per second. Then like the coin, add a second animation named Effect and populate it with the skull effect sprites. Switching back to the skull and getting a good view of it in the editor, we can add a collision shape to it, which will be a circle. I'll adjust the sprite one pixel to the left and apple bit so it's better centered. And adjust the Circle glider to fit. Add an audio stream player two D node. The sound effect that I've selected for the skull will be hud, open, made by a new age soup. But I trimmed it down slightly in an audio editor, it's still longer than the animation, so I'll need to add an empty frame or two on the end of the animation so the sound can finish. Then save the skull branch as its own scene position, the skull where it can be collected during our test, open up the skull scene and add a script to the root node. Many of the behaviors of the skull will be very similar to the coin script we wrote previously. Let's start by copying and pasting the coin script into the skull script. My skull script doesn't need a value, since every skull will represent one life. But it will still have a sprite and a sound effect when a collision happens. We can still do all of the same logic except the part where we tell the game manager that the player collected a coin. Let's separate that into a separate private method called underscore collect and call the method from the same spot. Switching to the coin script, we can make the same changes to the format. Now everything in these two scripts is almost identical except the contents of this one collect method and they extend different node types. If we select the coin and the skull, we can see that they both have properties of a collision object two D. We don't want to write this exact same script Every time we create a new type of treasure to add to our game, we can define a more abstract script named treasure and extend collision object two D. Here we can write all the common behaviors of the various types of treasure for our game, copying all of the contents into the new treasure script. The default behavior of the collect method can be empty since treasure is too abstract of a concept to know what we should do with it when it's collected. The purpose of this method is simply to tell Godot that everything that is treasure can be collected. Give this script the class name treasure. Since both coins and skulls are different types of collision objects, we can make them extend treasure and gain all the useful benefits we put inside of the treasure script. Now in our coin script we have coin specific things like value. We can override the behavior of being collected instead of doing nothing to instead tell the game manager that a coin was collected, a method which is overriding another method is indicated with this blue arrow. You may have noticed that this arrow appears anytime we have overridden the ready method. Likewise, when the skull is collected, it will tell the game manager that a skull was collected. Now, no matter what kind of treasure is collected, these same behaviors will automatically happen for all of them. But we must be careful and make sure that all treasures have these child nodes, and the animated sprite must have an effect animation. Treating different types of objects as all having one similar set of behaviors is called polymorphism. All coins and skulls can be treated as treasure. The only difference will be what they do when they're collected. Any new kinds of treasure we add can also follow this pattern. Switching to the game manager script, we can simply add a collect skull method, increasing the player's lives by one. When this happens, duplicating the coin counter reference, we can add a lives counter reference, then also update the UI when a life is added. Since the ready method is doing two different unrelated tasks, we should separate them into different methods to keep them organized. Let's write private nit boundaries and It UI methods which perform each of these tasks in isolation and are called by the ready method. I'll follow the conventions set by Mario and Donkey Kong, awarding the player with an extra life after they've collected 100 coins. When filed coins is greater than or equal to 100, subtract 100 coins, and add one life, and also update the lives counter. Next, we can duplicate the coin counter node on the canvas layer and rename it to Lives Counter. To put this in the upper right corner, I'll change the layout direction property to right to left. Since my coin counter was 32 pixels from the left side of the screen. I can mirror this by subtracting 64 pixels to add the same padding on the right side. Reversing the layout direction also reversed the ordering of the child nodes. I like the icon being on the right side, but the one and tens digits are reversed. I'll drag them into the correct position. I've edited the zero one dog to fit better on the UI by removing the particles above the skull image to create this zero zero dot Png to use as the icon texture. Lastly, in the cases where the coin is not frozen, I want it to remain stationary while it's being collected. Currently, Rogers collision with the coin adds force to the coin's rigid body causing it to move while the effect animation plays in the coin script. In the collect method, we want to access the freeze and freeze mode properties of the rigid body two D. But these are inaccessible to this script since it is extending collision object two D and Godot doesn't like us changing collision settings while a collision is happening. We can solve both of these issues by using a built in method named call deferred. The call deferred method will tell Godot to execute this after the collision is finished. Processing call deferred takes a string argument of the name of the method we want to call. In this case set free enabled the value we want to set it to, which is true. Then I also need to set freeze mode to a value which is defined inside the rigid body. Two D class freeze mode, static. A static rigid body will not move from either forces or collisions, which is what I would like. This will stop the coin from moving after it's collected with the skulls root node selected. Set the collision layer to the treasure layer and the collision mask to the player layer. Also connect the body entered signal to the skulls on body entered method. We now have a life counter and the player can gain more lives by collecting skulls or coins. In the next lesson, we'll create a treasure chest full of pirate booty. I'll see you in the next lesson. 33. 3-5 Chest: Hello friends. In the previous lesson, we added a collectible skull treasure to our game. In this lesson, we'll create a chest full of treasure that the player can open. I will have a treasure chest be a stationary object that appears to be in the background so the player can walk in front of it. When they do, the chest will open and throw some amount of coins in the air. Starting from the level scene, let's add an area two node to the treasure folder. Having more complicated behaviors than other items in the game. An animated sprite won't be sufficient. Like our characters, we will need to use a sprite two D node, then use an animation player to control it and an animation tree to control the player. Let's first set the default sprite for the sprite two D node. I'm using the chest sprites from the merchant ship folder, not the one from the Palm Tree Island folder. I want one where the chest isn't locked, just closed inside the unlocked folder. I'll pick sprite number three. We can also add a collision shape, which should be a rectangle and stretch it out to cover the entire chest. And an audio stream player to add some sound effects. Rename the branch node chest and save this as its own scene in the treasure folder. Our test will need a script to control it, which should also be in the treasure scripts folder. The chest will have an exported variable to know if it is open or not. Since the default value for a bullion is false, the chest is not open. The chest will also need to know what's inside it. Let's add an integer variable to specify the total value of all the coins inside the chest and give it a default value of one. It wouldn't make sense to allow this number to be a negative number or some ridiculously high number. We can restrict the range of values of the exported variable by adding underscore range and specify both a minimum and a maximum value. Now this number can't be set to anything negative or way too high. We can also add a variable named underscore booty as an array of treasure to represent the actual coin nodes inside the treasure chest. In order to make these coins, we'll need packed scenes of both the silver coin and the gold coin. Inside the ready method, we can then write a simple algorithm to instantiate the coins needed to add up to the total value. While the total value is greater than ten, we can reduce the total value by ten and instantiate a gold coin. This newly instantiated coin can be added to the booty array with push back. This will repeat until the total value becomes less than ten or will be skipped entirely. If it was already less than ten, then repeat the process. As long as the total value is more than zero, we can reduce it by one and instantiate a silver coin, then push it onto the back of the array. By the end of this process, the total value will be zero, and the chest will have a bunch of coins representing that amount ready to spawn. When the player opens the chest, we can then go through the booty array one item at a time using a for loop, set each item's global position to the same global position as the chest, but also moved up one tile. Turn the freeze property to false physics will be applied to the coin. We can apply a random bit of force to each coin to make them scatter up into the air when the chest opens. To do that, we'll need to create a random number generator variable and initialize it with a random number generator new during the ready phase. Then add an impulse to the item. The direction of the impulse should be up one tile multiplied by a random number. I'll set my random range to be 5-10 Then also add vector two, right one tile, and multiply by a random number between negative one and positive one. Negative numbers will make it go left instead of right. This should produce a satisfying fountain of coins. When we need to add the item to the scene tree, I would prefer to make it a sibling of the chest, not a child. I'll get the chest's parent first and then add the coin as a child of that. When this is done, we can clear the array since the chest is now empty. Selecting the animation player, we can start by making a closed idle animation, which only needs a track for the sprite two D, sending its texture to the same sprite it already has. Then reduce the length of the animation to 0.1 seconds. Duplicate the closed idle animation and create an open ideal animation. And change the sprite to number eight. We can then make a closed animation changing the sprite, counting down 8-4 so the animation length will be 0.5 seconds. We can also add an audio track to these animations and have the chest play closing. Sound The sounds I'm using for opening and closing the chest were created by the frisbee. If piece on Freesound.org duplicating the closing animation. We can make an open animation simply reversing the sprites and changing the sound effect. But in the open animation, we can also add a method call track to the animation. Adding a key frame during the frame when the lid is open, we can call the plunder method to spawn the coins, switch the animation tree, set the advanced expression base node to be the chests root node and the anim player property to the animation player. Then create a new state machine for the animation tree. We can add all four of our animations to the state machine and connect them with a cycle of transitions. The transition from closed idle to open will be triggered by is open, then open to open idle at the end of the animation. Likewise, open idle to close happens when naught is open, close to close idle at the end of the animation. This structure allows us to initialize the chest as either open or closed when the scene starts based on the value of is open as well. By making more than one transition from start and setting their conditions, select the root node and populate the coin packed scenes by dragging them from the file system into the inspector. We also need to set the collision layer to put the chest on the treasure layer and have it look for collisions on the player layer. And set the Z index of the chest to be behind the player. Switch to the node panel and connect the body entered signal to the chest itself. Adding an on body entered method, if this body is a character, then we should set is open to true, which triggers the open animation, which in turn triggers the plunder method spawning the treasure. Place a treasure chest somewhere in your level. Try clicking the Is Open toggle to open and close the chest and edit the total value of coins which will be spawned. When the chest opens, hip play and try opening the chest and collect your hard earned coins. We now have a treasure chest which spawns a burst of coins for the player to collect. The next lesson will add a lock to the treasure chest and a key the player can use to unlock it. I'll see you in the next lesson. 34. 3-6 Lock & Key: Hello friends. In the previous lesson, we created a treasure chest that spawns a fountain of coins when opened. In this lesson, we'll lock the chest and hide a key somewhere in the level that opens it. Let's start by duplicating the silver coin scene to make a key scene. Open up the new key scene, select the animated sprite and swap out the sprites of the coin for the key sprites. And the key has its own effect animation too. I'll just change the keys sound effect to a different coin. Sound The key will need a new script inheriting from treasure saved in the treasure scripts folder. All we need to do is tell the game manager script when the key is collected. The treasure script will handle everything else. Replacing the script on the root node with this new key script is as simple as clicking and dragging it onto the node. Since it is still a treasure script, the signal behavior is still connected to switching to the game scene. I will have only one key per level in my game. Instead of counting keys like we've done with coins, I'll just use a single texture to indicate whether or not the player has the key. I'll add a texture wrecked to the user interface, populate it with the default key. Sprat, doubled in scale to be more visible and position it below the coin. Then click on the icon to hide it, since the player doesn't start with the key in the game manager script, we can set a reference to this texture in the ready phase when the player collects the key. We can set a variable in the file data that the player has a key to true. Also set the visible property of the key icon to true. We should also create another method for when the player uses the key to set filet has key to false and hide the icon on the UI. Switching to the data script, we can add the has key variable and set its default value in the init method. Place a key somewhere near level and try picking it up. In order to lock the chest, we'll need to add another bulling variable so the chest knows whether or not it is currently locked. We can then alter the logic in the collision code. If the chest is locked and the player has the key, then set is locked to false and tell the game manager that the player has used the key. If the chest is not locked, set is open to true. I'm not using eLseF here because I want the chest to both unlock and open in one collision event. Selecting the animation player, we will need to add more animations. Let's start by duplicating the closed idle animation to make a locked idle animation. And change the sprite to the idle sprite. Then duplicate the close animation to create a lock animation. Changing the sprite 3-2 to one, shortening the length of the animation to 0.3 seconds, and playing a different sound. This time I'm using key twist in lock made by Karen Keegan on Freesound.org We can then duplicate this animation to also create an unlocked animation reversing the sprite order. Switching to the animation tree, we can add these new animations to the state machine. And connect them. With a similar loop of transitions like we did with open and close. The chest will transition from closed idol to lock. When is locked is set to true, then from block to locked idle at the end of the animation. Likewise, it will change from blocked idol to unlock when is locked is set to false, then to closed idol at the end of the unlocked animation. We can then also start the chest in the locked idle state if is locked is true, but the conditions for starting the chest as closed and locked can both be true. We'll add the condition for closed idle, that the chest must be not open and not locked in the level scene. We can now alter the chest's locked state by clicking on the toggle. Keep in mind that a locked chest must be unlocked before it can be opened. An open chest must be closed before it can be locked. This works, but I don't like that. The lock simply disappears. The asset pack has an unlocked padlock as a separate asset, so let's use it. Duplicate the key scene To create a padlock scene, change the type of the animated sprite two D node to a sprite two D node, since the padlock has no animations, rename the nodes accordingly and populate the sprite with the padlock asset. Change the collision shape to a rectangle and resize it to fit the shape of the lock. Remove its collision with the player, and reduce the Z index of the padlock to match the chest. I'll also make the default setting of the phrase property false, since I always want the padlock to be affected by physics. And remove the script by clicking on the script button with a red X on it. The padlock is not treasure and should not be collected by the player. Opening the chest script, we can add an exported packed scene for the padlock, just like we did with the plunder method. We can define another method to throw the padlock. Since the plunder method could be dealing with quite a lot of coins, we instantiated them during the ready method. Then when the player opens the chest, the coins already exist in memory and are simply being added to the scene tree. This is a more responsible way of instantiating large amounts of nodes. But since the padlock is just one single thing, we don't need to be concerned about instantiating it at the moment when it's needed. Inside the throw padlock method, we can define a new variable for the instantiated padlock. Then perform the same logic as the coins repositioning the lock to match the chest location. Applying an impulse force and adding it to the scene tree, I'll remove the randomization of the upward force. It just gets tossed to the side a little bit. Switching to two D view, I'll quickly add the padlock image to the scene so I can reposition it where I want it to start, then look at its transformed values to get the x and y positions. After writing down negative four and negative seven, I can delete the sprite node, switch back to the script view, and set the padlocks initial position to be the chest position plus vector two, negative four, negative seven. Now the padlock will appear in the exact position where it looks like it matches the locked sprite and will be tossed aside. Remember to populate the packed scene by dragging the padlock from the file system panel into the inspector, select the animation player, switch to the unlocked animation, and add a method call track during the frame when the padlock has disappeared, we can call the throw padlock method. Now when the player collects the key and touches the treasure chest, the padlock is tossed aside, the chest opens, and the player is showered with coins. We now have a key that can unlock our treasure chest. In the next lesson, we'll add an end goal to our levels. I'll see you in the next lesson. 35. 3-7 Map: Hello, friends. In the previous lesson, we locked the treasure chest and added a key to unlock it. In this lesson will create an end goal for our levels. I'll use the small maps as the goal for my levels, since this will easily imply to the player that Roger is following each map segment to find the next to assemble a complete treasure map. It's a simple enough concept that I won't need to explain it. And it also provides a framework for level structure. Let's start by duplicating the skull scene to create a small map. One scene rename the root node. Select the animated sprite and swap out the skull sprites. For the small map, one sprites. I'll use the in and out sprites together to create the effect animation. Then change the collision shape to rectangle and resize it to fit the sprite. I'll use the paper sound made by brevceps as the sound effect. Just like with all other treasure, we can give it a treasure script named Small Map Inheriting from treasure. All we need to do is tell the game manager that the map was collected. Switch the script on the root node for the new small map script. Then duplicate this scene three times to create small map. Two, three, and four. Swapping the sprites in the default animation for the matching sprites from the asset pack for small map four. However, I'll change the effect animation since when the player collects this piece, they have completed the entire map. After the in effect plays, I'll play the big map unfolding animation followed by the idle animation, the folding animation, and then the out effect. This will let the player know that the small maps have combined to form one larger map and that their objective is near. When the player collects the small map, the level is over. And I would like to reward the player with a short fanfare followed by the screen fading to black before returning to a level selection menu. Let's switch to the game scene in two D view. We can cover the screen in black with a node called Color Wrecked and name it, fade in the inspector, change the color to black. Then expand the layout section and select full wrecked from the anchors. Preset dropdown to make sure that this is always in front, either make sure it is positioned at the bottom of the user interface branch or give it a higher Z index value than everything else. We don't want this to block mouse inputs on UI controls. Behind it though, Also expand the mouse section and tell the color wreck to ignore mouse input. Now the entire screen will be black, which is ideally how every scene in our game should start. It's in our way as we develop this scene. Let's have it hidden by default to make it easier to copy into other scenes. Let's save it as its own scene, then open it up to get this black rectangle to fade, it will need a script which belongs in the UI scripts folder. Just like we used tweens to move the camera, we can also use tweens to adjust other properties over time, such as color. First, let's define two colors at the top of the script, one for black and one for clear. Black has red, green, and blue values of zero and an alpha value of one. While clear has an alpha of zero, alpha is a measure of transparency. We'll also need a private variable for the color tween. Let's start by fading to clear since the rectangle is currently black. Just like with the camera, it's a good idea to first check if the tween already exists and is running, and if so, kill it. Then create the tween. There's no need to bother with transitions or easings here, linear is fine. Then tween a property on this node itself, the color property, with the target value of clear over a duration of 1 second. We will want to know when this behavior is complete, so we can return a signal from this method to let us know when the color tween is finished. Specifying a return type for a method declaration in Gudo script is done after the parameters indicated with an arrow. Since fading to black will be identical except for changing the color, Let's change this method's name to fade and take a color as a parameter, then use that color as the target value. We can then write fade to clear, to simply call fade passing in clear as an argument. Likewise, write fade to black. Calling fade, passing black as the argument. Both of these methods can return the same signals returned by fade. Switching to the game manager script, we will need to set a reference to the fade during the red phase. The very first thing we should do when the scene is loaded is set the visible property of the fade to true, so the player won't see anything but black. Then when all initialization is complete and the game is ready for the player to start playing, we can tell the fade to fade to clear and await the signal for when it's complete. At that point, we should give the player the ability to start playing the game. Let's set a reference to the player node during the ready phase and call a method we haven't defined yet. Set enabled passing true as an argument. Switching to the players script, we can add a private Boolean variable named underscore is enabled. Also define the set enabled method, Taking a Boolean parameter which sets the private variable. Then check this value before processing any inputs returning. If the player is not enabled back in the game manager when the player collects the map, we can then remove control from the player by setting enabled to false. I would like to play a victory fanfare here too. So I'll add an audio stream player node named Fanfare and populate it with a short music track. The fanfare I have selected is Game Success Fanfare Short by L Boss on Freesound.org After the player has been disabled, we can play the victory fanfare. Wait for the fanfare to finish. Wait for the fade to fade to black. Then switch scenes. Place a goal at the end of your level. Hit Play. The scene is loaded with a black screen and fades in. The player can't move until the fade in is complete. Collecting the treasure at the end of the level removes control from the player, triggers the fanfare and fades to black. We now have a way to end our levels and a nice gentle screen transition. In the next section, we'll give the player health and let them take damage. I'll see you in the next section. 36. 4-1 Damage: Hello friends. In the previous section, we created a bunch of different treasure for the player to collect. In this section will give the player health, allowing them to take damage and die. If you completed the assignment, you should have your levels populated with treasure for the player to collect and placed strategically to manipulate their behavior if you completed the challenges. You may also have an exported array of packed scenes in your chest script that adds extra treasure items to the booty array and spawns extra treasure items. Or have a minimum and maximum coin value, with the chest generating a random integer between them. Then instantiating coins that equal that random value. You may have all seized the color diamonds to create new treasure and given them a unique purpose for your game to give characters some health. Let's start in the character script, where we can add a new exported variable to set the characters maximum health. This should be restricted to only be a natural number. Something 1-100 should be fine. I'm probably only going to have a tax deal, one damage at a time, 100 will be a lot, and I'll set the default value to five. We can then also declare a second variable representing their current health. To keep things simple, I'll assume that when the characters are loaded into the scene, they are at full health, setting their current health equal to their max health During the ready phase, We can then write a public method which deals damage to the character, taking the amount of damage as a parameter. For now, we'll just reduce the current health by the damage amount, then print out the current health so we can see the result. Most games like this include a brief period of invincibility after taking damage. The simplest way to achieve this would be to turn off collisions during that time. But the character's collider isn't just taking damage, it's also colliding with the environment. We can separate these responsibilities by adding another child node to our characters, an area two D, called a Rt box. The Rt box's only responsibility is to be detected by damage sources and be turned on or off without affecting other aspects of the character. It will also need a collision two D child node to determine its shape. To differentiate it from the character's normal collisions, we can change the color of the Rt box to something else like green. It doesn't necessarily need to be identical to the character's capsule, but it's a good place to start with the hip box node selected. Change the collision layer to be layer ten, making this the player hurt layer. Anything we want to hurt, the player should mask layer ten to look for the player hurt box. To test this out, we'll need something simple on our level which can hurt the character. We'll create a new packed scene using the spikes asset. This will be a static body two D node, since it won't move or be affected by physics. Add a sprite two D node and populate it with a sprite asset. Add a collision shape to it and make it a rectangle. This will be a walkable solid surface that the characters collider will treat as if it were part of the terrain. It should span the entire width of the tile, but only come up to about a quarter of the tiles height. This will also prevent the player from getting hurt if they touch the spikes from the side instead of the top. This is a part of the level but not the terrain or water. Let's make it layer three, a new layer for hazards. We can then add another collision node to deal damage, which will be an area two D and let's rename it to hip box. Depending on how precise you would like to be with your hip box, you may want to use a custom shape here. Let's add a collision polygon two D node as a child of the hip box in the inspector. We can see that the polygon is a packed vector two array. Clicking on it to expand it, the array has a size of zero which is currently empty. We can simply click anywhere in the editor to add a vertex to the polygon. I'll add one at each spear point and another near the right edge to give it some volume. Then click on the initial vertex to close the polygon. This is now a custom collision shape that if the character touches, they will get hurt. But notice how it's divided into two smaller shapes, red and purple. That is because collision detection in video games is complex and requires a lot of computation, it is much easier to detect collision inside of a convex polygon than a concave polygon. Concave polygons will be divided into convex polygons by Godot. By having the collision polygon match the height of this third spike, we have doubled the amount of computation required to detect collisions with these spikes, since the engine needs to check if the character is touching the red polygon or the purple polygon. To simplify this, let's remove the vertex of the third spike, which in our array is element number two. The polygon is now convex and completely colored in red. And we can simplify this even further by removing the last vertex. This hip box needs to look for the player hurt layer layer ten if you want enemies to take damage from spikes two, also layer 18, Save the spikes branch as its own scene. You could choose to put this in its own folder labeled traps or hazards, but since there are no other assets that would fall into those categories, I'll just save it as a decoration. I will, however, make a new scripts folder named environment, then move things like camera level, parallax, and water into it before adding a new script named Hazard. Then attach this script to the root node of the spikes. The purpose of the script will be to react to a character's hurt box colliding with the spikes. Hit box, selecting the hit box switch to the node panel and connect the area entered signal connecting it to the spike's root node. This will change the name of the method to be on hit box area entered, which is a little more descriptive of what's happening. Getting the parent of the area gives us the character, then we should tell that character to take damage. Since this script could be used for any number of hazards or you may want to adjust its damage on the fly, let's make the amount of damage dealt into an exported variable and default value of one should be fine. Give it a range so it can't be set to something negative or zero. Open the project settings and name the collision layers, Hazard, player hurt, and enemy hurt. Place spikes somewhere in your level and try jumping on them. You can see in the output panel that Roger now has four health remaining with each collision, the number is reduced by one. Also, the player and other characters can be configured to walk on top of the spikes or through them based on their collision masking with layer three, we now have a spike hazard that damages the player. In the next lesson, we'll have the character react to taking damage. I'll see you in the next lesson. 37. 4-2 Reaction: Oh friends. In the previous lesson we created spikes that damage the player. In this lesson will make the character react to taking damage. You probably noticed when we are making characters that there are hit animations in the asset pack. Let's implement those now. In the character scene with the animation player selected, add a new animation named hit. Populate the hit animation from the spikes from the without sword folder. Also add a sound effect if you like selecting the animation tree. Edit the without sword state machine. We can add the hit animation here and transition to it. If the character is hit then transition back when they are not hit opening the character script will need to create the is hit variable of boolean type, then set it to true when the character takes damage. The value needs to be set back to false to transition the character out of the hit animation back to movement. The animation itself can perform this function. But in order for the animation to access it, the variable must be exported. Let's make a new category for this in health named Combat. We can then add a property track to the hit animation to set the value of is hit back to false at the end of the animation, the character will now play the hit animation once when they take damage. This will interrupt any movement animations that were happening because it is transitioning out of the movement layer of the state machine. Let's try it out. It will be nice if the character continues to take damage without requiring them to leave the hit box collider and enter it again. If they stay on the spikes, they will continue to take damage. Also, there should be a brief window after taking damage when the player is invincible. We can solve both of these problems with one solution. Turning off the player hurt box and turning it back on again, selecting the hurt box node. The properties at the top of the inspector panel labeled Monitoring and Monitorable can be used to determine if collisions happen or not. Since this is a hurt box, it is passive and isn't looking for anything. Monitoring can be set to false. Its purpose is to be found by hit boxes. It should be monitorable. Turning monitorable to false will prevent hit boxes from colliding with this hurt box and turning it back to true will trigger a new collision with the spikes which have a hip box. We can then do the opposite. Set it to monitor for the pert layers but not monitorable. There is a simple node type in Godot for timing purposes, a timer, which we can add to our character and name it Invincible. The default time is 1 second, which is fine, and we want this to only count once at a time. Check the one shot checkbox. During the ready phase, we can set a reference to the character's box and the timer when the character takes damage. We can set monitorable to false, Start the timer, await the time out signal, and set monitorable back to true. But Godot won't let us turn the collider off during a collision, we will use set deferred to tell Godot to set monitorable to false after this collision is complete. If you want to have other things in your game that make the character invincible for a set time, We can also make this into a public method taking a float time as a parameter. Then pass this into the timers start method. Now the take damage method can call the become invincible method, passing 1 second as a parameter. But I don't want enemies to become invincible, just the player. I'll add an exported combat variable for the amount of time the character is invincible after taking damage restricted to be non negative with a default of zero in the take damage method. I'll then check if this value is not zero before calling the become invincible method, using this time as a parameter. If enemies aren't going to use this timer node, they shouldn't have it in their scene tree. Instead of setting the reference to the timer using ready, I'll instead use the ready method. Check the value of invincible duration. And if it is not zero, then set the reference to the timer. Now only the player character needs to have the timer node and will have an invincible duration value set higher than zero. But the enemy characters still need to have Rt boxes added to them. Otherwise, their scripts will try to set references during the ready phase and cause an error because they don't exist. Their herd boxes will also belong on layer 18 instead of ten. Then give Roger an invincibility duration longer than 0 seconds. Trying it out, the character standing on the spikes will continue to take one damage every second as we see it counting down on the output panel. Lastly, I would like the character to get knocked away from the source of the damage. Let's modify the take damage method to also accept the direction of the force as a vector two. Then set the character's velocity to be this direction multiplied by five tiles. The hazard script will then need to calculate this direction and send it to the character when hurting them. This can just be the characters global position minus the hazards global position. For the hazard to know its global position, it must extend no two D. But we don't want distance to be a factor here, just the direction. Putting this in brackets, we can call the normalized method. Normalized, We'll take the vector and make it longer or shorter to make it have a length of one. Let's try it out. The character hitting the spikes is hit with a backward force, has a hit animation, and becomes invincible for 1 second before getting hit again. We now have characters reacting to getting hit. In the next lesson, we'll add the player's health to the UI and give them a potion item to recover health. I'll see you in the next lesson. 38. 4-3 Recovery: Hello, friends. In the previous lesson, we had our character react to taking damage. In this lesson, we'll add the player's health to the UI and create health potions. First, let's make a health gauge. The assets in the asset pack are divided into three separate images for the gauge and a flat red color for the fill. The health gauge itself will just be a basic control node with two children, one for the background and another for the fill. The background node can be a horizontal box Automatically sorting the three background images for us, which are all texture wrecks, Populate the textures with the assets from the asset pack. You can hide the other branches of there in your way. Selecting the background horizontal box, expand the theme override section in the inspector and set separation to zero pixels so the images are drawn without any gaps. The fill is just another textuect with this flat red color that we can manually resize and fit into the gauge. Selecting the health gauges root node. Let's scale it up four times to make it more visible. I think it would look good in the bottom left corner, I'll set the anchor presets to be bottom left. And adjust the pivot offset y to be at the bottom of the gauge, which is 40 pixels. Then set the x position of the gauge to 32 pixels to add the same padding as the coin above just to layout and check out looks while playing the game. Zooming in on the new health gauge. Select the Fill Textureect. To use the fill, we can set the expand mode to ignore size, allowing us to manually set the size to whatever we want. Click and hold on the size X value and move your mouse left, reducing the X value, which we can see, also makes the gauge look like it's depleting. When the X value is zero, the gauge is empty, and when the x value is 75, the gauge is full. We can use this to display any amount of health the player has by turning it into a percentage of 75 pixels. Creating a script for the health gauge. We'll name it Gauge and save it in the UI scripts folder. We can get a reference to the fill during the ready phase. Like the counters, a gauge really only needs one method to set the value being displayed. It would be best to take this value as a percentage with a float type. All we need to do to display this percentage is set the size of the fill to be 75 multiplied by percentage. A percentage in programming is usually represented as a number 0-1 unlike in math where it is 0-100 This simplifies our calculations to be more efficient. If we want to make this script more flexible, we can export the value of 75 pixels as a variable named max pixels and set 75 as the default value. Switching to the character script, we can create a new signal for when the character's health value changes and give it a parameter which is the percentage of the character's remaining health. Then when the character takes damage, we can emit that signal. To calculate the percentage of the character's remaining health, simply divide current health by max health, But both of these values are defined as integers, which means that the result will always be either zero or one. If we change one of their types to float, the result will then be a float two. We can then connect the player character's health changed signal to the health gauge. But we don't want to call a new method. Clicking on the pick button, we'll present a list of the health gauges methods we want to call set value. In order to do this, both the signal and the method should have the same parameters. In our case, afloat, Remember to unhide the other branches. When you're ready to test, let's try it out. The gauge starts full, but jumping on the spikes reduces the gauge by one fifth each time. Remember to position the fade at the bottom of the UI branch if you want it to be drawn over everything else. Now let's help the player out with a health potion to recover that lost health. Like we did through the last section, we can simply add a new treasure item using the red potion assets and create a new script for it inheriting from treasure, copying one of the other treasures. Rename it red potion and open it up. Rename the root node to match replace the animation sprites with the red potent and the effect sprites with the potion effect. I'll center the sprite and change the collider to a capsule to better fit the image. I'm using my gulp recording made by Miley Joe Moss, 1,996 for the sound effect of the potion. The different colors of the potions probably won't just be adjusting a variable, but instead have a completely different function. And we'll need their own unique scripts. Instead of having a generic potion script, I'll name this red potion inherit from treasure, then swap the script that is attached to the root node. We can export an integer variable for the amount of health that the potion recovers as an integer. I'll set mine to have a value of three. I don't want to bother the game manager with relaying this information from the potion to the character since the character collided with the potion. Instead, I'll make it small change to the treasure script, storing the character that collided with this treasure in a variable. Then, after verifying that the body is a character, save the body as the character variable. Now the potion script can directly communicate with the character when it is collected. When collected, the red potion will call a recover health method on the character passing the amount recovered. Switching over to the character script, we can add this recover health method to the public methods, taking an amount of health to recover as a parameter, adding the amount of health recovered to the current health. We should also cap the current health at max health using the min function, then emit the health changed signal to update the health gauge on the Y. We can combine these two lines and perform them in one statement. Place a health potion in your level, try taking damage from the spikes, then collect the potion to recover lost health. We now have a way for the player to know how much health they have remaining, and an item to help them recover lost health. In the next lesson, we'll add a checkpoint to the level. I'll see you in the next lesson. 39. 4-4 Checkpoint: Hello friends. In the previous lesson we added a health gauge to the UI and a portion to help the player recover lost health. In this lesson, we'll set locations where the player should respond after dying. I'm going to delete the other level from the game scene. Now, since we'll be editing the structure of levels and all levels will require this new structure to function properly, other levels will need to be edited to. So far we've been using the scene origin as the location where the player will start, then expecting them to make it all the way to the end without dying. You may instead want your levels to be longer and give the player checkpoints where they can respond instead of starting back at the beginning each time. Let's add another folder to the levels seen hierarchy named checkpoints. We can then add a basic empty two D node to this folder named start position it where we want the player to start the level. If you prefer. You may also want the level trigger to be in this folder and rename it to something like end to make a checkpoint. We'll also create an area two D node in this folder named middle. Give this checkpoint an animated sprite node. I'm going to use the flag assets for my checkpoint since the checkpoints origin point is the location where the character's origin will be set and the character's origin is at their feet. The checkpoints origin should be on the ground where the character's feet will be positioned. With that in mind, I'll position the flag so the flagpoles base is at the origin. Adding a collision shape, I'll just use a line segment covering the flag pole so the player must actually make contact with the flag pole to trigger it. I'll also add an audio stream player to de node, which will play Game Reward by a Yen Ba on Freesound.org Save the checkpoint branch as its own scene. I'll put mine in the root scenes folder since it will be included in every level of my game. Opening the new checkpoint scene, I'm going to edit the z index of my flag to be drawn behind the character while being very similar to the behavior of a treasure item. I wouldn't logically think of this as treasure and I don't want to refactor the treasure script to fit this into it. I'll create a new script from scratch and put it in the environment scripts folder. Grab a reference to the audio stream player two D node during the ready phase and connect the body entered signal to react to the player colliding with the flag. Play the sound effect and then set the collision mask to zero to stop any more collisions from happening. Then we want to set a variable in the file data to know that the player has reached the checkpoint. You may want to have this be a Boolean if you only ever want to have one checkpoint, like a typical Mario game, or an integer if you want to have multiple checkpoints, more like a Donkey Kong country game, an integer is more flexible and can also be used for the single checkpoint system. So that each checkpoint will then need a unique integer to identify it, which the game manager will use to know where to respond the player. Let's define a variable as an integer to hold this number. Then set the value of filed checkpoint to be this ID number. When the player touches the checkpoint, we could export the variable to set each one manually, but that would be prone to error and more work for us in the long run. Instead, I'd like to delegate this responsibility to the level script. First, we need to make sure the collision mask of the checkpoint is set to collide with the player. And give this script a class name so it can be identified by the level script. Switching to the level script, if we can safely assume that all levels will have this checkpoints folder, then we can use that to set a variable not to the checkpoint folder itself, but to an array of nodes. We can set the value to be checkpoints folder, giving us a list of every node in the checkpoints folder. Then using a four loop, we can count from zero to the size of this array. If the note is a checkpoint, set its checkpoint ID to its position in that list. The level now contains a list of all checkpoints where the player character could be spawned and every checkpoint knows its position in that list. It will be the game manager's responsibility to load the level and move the player to the appropriate checkpoint before gameplay starts. Let's also add a method to the level script so the game manager can request this information named get checkpoint position. Taking the checkpoint ID as an integer parameter and returning a vector two position. I'll start with a fail safe case of just returning vector two zero. Before using an argument to index an array, we should check that it is a valid array index, that it is both greater than or equal to zero and less than the size of the array. Then we simply return the checkpoint array index at the checkpoint ID and get its global position. Switching to the game manager script. After all initialization has been handled, but before fading in, we should spawn the player. We can now set the player characters global position by asking the level the location of the checkpoint, passing filed checkpoint as the argument. Lastly, we need to add the checkpoint variable to the data resource with the default value of zero. The player will start at the top child node of the checkpoints folder, which is the empty start node. Since we aren't using the body parameter passed into the checkpoints collision Godot would prefer it were flagged as optional by preceding it with an underscore. Place the checkpoint somewhere around the middle of your level while making sure that the level start is the top node in the checkpoint folder. Hitting Play, nothing will have changed, but we can now move the player's start location more easily. Also, if we edit the default value of checkpoint in the data script, we can spawn the player at the flag instead. We now have a checkpoint system in place so the game manager knows where to spawn the player. In the next lesson, we'll add player death and have the player respawn at the last checkpoint touched. I'll see you in the next lesson. 40. 4-5 Death: Hello friends. In the previous lesson we created a checkpoint system so the game manager can spawn the player at different positions. In this lesson, we'll add character death and respawn the player when they die. Starting in the character script. Just like we capped the health at max health using Min when the player recovers. We also need to stop current health at zero when they take damage, setting current health to max of either current health minus damage amount or zero. We can then emit the health changed signal and set the knock back velocity. The rest of this method will be contingent on whether or not this damage has killed them. We need to check if current health is zero. If it is call a new method, die. If the character is not dead, then the is hit variable will be set to true and they may become invincible. Before we write the die method, we should declare a Boolean variable to know if the character is dead or not. Also create a signal to emit when the character dies so the game manager can react to it. In the die method, we can set the new boolean variable is dead to true that we can use in the animator Like we did with is hit and emit a signal that the character has died. It would also be a good idea to turn off the character's herd box so they stop taking damage. But this is still something that is probably happening during a collision. We will need to defer this until the end of the current frame. Setting the collision layer of the character to zero and the collision mask to one will prevent any future collisions with anything other than the terrain. A dead character will not collect treasure or trigger a checkpoint. Finally, setting direction to zero will cancel any movement input that has been given at the moment of death. In order to respond the player, we also need a public method to revive them from being dead, setting is dead, back to false current health to max health. We then need to restore the character's collision setting the Rt box monitorable property to true. This isn't triggered by a collision, more likely the game manager's logic. It's fine to just set it directly. We can store the values of the collision layer and the collision mask in variables during the ready phase, then restore them to their original values when reviving the character. Since we will be reviving the player character after repositioning them back at the checkpoint, it would also be a good idea to omit the landed signal here, which will correctly position the camera. We changed the character's, we should also omit the health changed signal to We also don't want the character to be able to do anything while they're dead. Starting with the face left method, we should first check if the character is dead and if so return preventing this from happening. And do this for any methods that should not be executed while the character is dead, including face right, run jump, and stop jump. I would also like to make an addition to the game manager script. When spawning the player, we are setting their position probably on the ground or near the ground at a location in the level. You can imagine that there is a possibility that the player character will die and fall from a great height. At the moment when this respawn method repositions the character, the character would have a very high velocity. In order to prevent the velocity from persisting and potentially breaking the rain collision, we should set their velocity to zero at this time. Switching to the animation player, we can add the dead hit and dead ground animations. Remember to use the assets from the without sored folder. Dead hit should have a cry of pain from the character while Dead Ground places an impact sound from hitting the floor. With the high probability that these sounds will overlap, it would be a good idea to separate vocal sounds from general sound effects. Adding a second audio stream player two D node, we can name one voice and the other sound effects. We can then keep vocal sounds restrained to only being able to play one at a time, while also allowing sound effects to play simultaneously without interruptions. Setting the max polyphony property of the sound effects to a value greater than one will also allow multiple sound effects to play together two. This format also allows us to adjust the volume settings of voices and sound effects independently selecting the animation tree. Add these new animations into the without sword state machine. First, playing the dead hit animation followed by dead ground. Dead hit is played when the character is dead. Then dead ground will be played after dead hit has completed, only if the character is on the floor. In order to revive the player, we need these animations to also return to movement. When is dead becomes false in the game scene, select the player character node and connect the Did signal to the game manager. Let's name this method on player Did. When the player dies, one of two things could happen. Either they respond at their last checkpoint or they've run out of lives and have hit the game over state. First, checking if file data lives is equal to zero. We will then call a game over method, giving game over a definition. For now, we can just print out game over. If lives is not zero, then we can reduce it by one, Update the UI, then call a different method. Return to last checkpoint. To return to the last checkpoint, we should await, fade, fade to black. Spawn the character at the last checkpoint reached, revive them, then await faded to clear. In both of these cases, I would like to play a short jingle like with the victory fanfare. Let's add three exported variables to the game manager script of type audio stream, which will be named Victory, Death and Game Over. I'm using scene ending music for death and sad, or scary scene change. Music for game over, both made by Dominic Trace from Freesound.org We can then tell the fanfare node to play the appropriate sound for each situation. Playing the victory theme when the player collects the map at the end of the level. Playing the death theme when they die and the game over theme when they run out of lives. It would also be prudent to disable player input at the start of return to last checkpoint and enable player input at the end. I've set the players starting lives to one and Mac's health to one. For this demonstration, we now have the player character able to die and respond at the last checkpoint they reached. In the next lesson, we'll give the enemies attacks to hurt the player. I'll see you in the next lesson. 41. 4-6 Enemies: Hello friends. In the previous lesson, we gave the player character a death animation and had them respawn after dying. In this lesson, we'll add attacks to the enemy characters that can hurt the player. I'll use Fierce Tooth as an example for this lesson. But all characters will need to have their node structures edited to match before running any tests. Selecting the animation player node, we can start by adding the same hit, dead hit, and dead ground animations for the enemies as we did with Roger. Then also add anticipation and attack as well. In the animation trees state machine, we can recreate the same hit and death animations as we did with Roger. Structuring the state machine in layers. Like this allows the enemy getting hurt or killed to interrupt their attacks. Editing the attack layer, we can then add the anticipation and attack animations. Here add a transition from movement to anticipation, anticipation to attack and attack to movement. The transition from anticipation to attack will happen at end, as will the transition from attack to movement. But the transition from movement to anticipation, which sets off the chain of animations, will happen when the character wants to attack in the character script. Let's add the wants to attack bolin to the combat variables. Then add a public method named attack which sets its value to true. Each time this method is called, the enemy will want to attack once like the is hit variable needed to be set back to false, otherwise the animation would loop. We also need to set the wants to attack variable back to false during the animation. The wants to attack variable will need to be exported so the animation player can access it. Switching back to the animation player during the anticipation animation, we can set the value of wants to attack back to false. This is sufficient to trigger the animation sequence for this enemy to attack. But like the spikes, there needs to also be a hit box looking for the player's hurt box. Select the attack animation with the first frame selected. That this is what's showing in the editor with a good view of the character. Let's add another area to D node to the scene tree named hit box and give it a collision shape. To distinguish this collider from the blue environment collider and the green Rt box, we can give the hit box another color like red. Select a shape that you think will best fit the area being targeted by the attack. I'll use a capsule, then resize it to fit the size and shape of the targeted area. Be sure to leave the hip box centered on the character and only move the collision shape off center. There's also an effect animation. Let's add an animated sprite toting node as a child of the hip box. Create a sprite frames resource and populate it with the attack effects sprites. Unlike other effect animations, we do not want this to autoplay. And also the usual ten frames per second frame rate, it also should not loop. Also add an empty frame on the end, reposition the sprite node so it looks like the effect is emanating from the attack. When you're done, set the default frame to be the last empty frame, so it will be initially loaded into the scene as not showing anything. But then when we tell it to play, it will play the animation once and disappear again. We can set the hit boxes collision layer to be layer 19, which will be the enemy hit layer, and have it mask the player hurt layer layer ten. Since it is an active entity, it is monitoring for hurt boxes. Nothing is looking for hit boxes. They are typically not monitorable. However, we don't want this to be monitoring until the enemy actually attacks. The default value of monitoring will also be false. In the character script. It would be a good idea to grab a reference to the hip box during the ready phase. We need to add a hit box node to every character to satisfy the character scripts requirements before testing and set the monitoring property to false. Just in case back in the attack animation, we can add the hit boxes monitoring property to the animation, setting its value to true during the first frame, back to false during the second frame. Then also add a call method track for the effect animation, telling it to play during the first frame of the attack. While the animations are divided into anticipation and attack, there are actually three phases to an attack, an contact, and recovery when dealing with enemies. The anticipation phase is how the enemy telegraphs that they are going to attack, giving the player time to react. Followed by contact, which is the exact moment when the collider is turned on and the enemy actually hurts the player. Finally, recovery, which gives the player time to react to being hit or retaliate. Connect to the area entered signal of the hit box to the character script. The only area we will allow to collide with a hit box is a Rt box. Thanks to the collision layering, all we need to do is ask the Rt box area for its parent, which will be a character, and tell that character to take damage. For now, just deal one damage in the direction of the player's global position minus this enemy's global position. Then normalized, we should export the damage amount as a combat variable so it can be modified for each character in the level scene. Find your enemy and attach a timer node to it. And adjust the timer to something a bit longer, like two or 3 seconds. And set it to autos, start. Connect this timer's timeout signal to the enemy's attack method. Now this enemy will be instructed to attack once every time the timer reaches zero, and it will repeat indefinitely. When you're ready, hit play to see the character auto attacking and try letting it hit you. The this works as long as the enemy character doesn't turn around. Let's set the sprite nodes flip H property to true to simulate the enemy facing right. Now the attack animation will face right, but the hip box and the effect animation are still facing left. Selecting the hip box in the transform section, click on the chain icon to unlink the x and y values so they can be edited separately. Then click and drag from the scale x property, moving your mouse to the left. As the value approaches zero, the hip box is so thin it disappears. But as it becomes negative, it is mirrored about the y axis. We can use this in the character script to flip the hip box. The same time we flip the sprite in the face left method. Set hip box scale x to one if the sprite naturally faces left, l negative one and vice versa. In the face right method, we can flip our enemy's initial facing direction with the exported variable. To test this out, we now have our enemy characters attacking the player. In the next lesson, we'll add a game overscreen. I'll see you in the next lesson. 42. 4-7 Game Over: Hello friends. In the previous lesson, we gave the enemy's attacks to hurt the player. In this lesson, we'll add a game over screen. This will be a control note over the UI canvas, probably drawn over everything else, but still underneath the fade, named Game Over Menu. I'll use a vertical box to sort everything easily, starting with a label that says Game Over so the player quickly understands what's happening when the player runs out of lives. I'll just present them with three options retry from the beginning of the level, go back to the level selection menu or exit the game. I'll add three buttons for each of my three options, Select and exit. I'll scale up the whole thing four times and reposition it to be in the center of the screen. Using anchors, selecting each of the buttons, connect the pressed signal to the game manager script, creating three new methods which will be called when the player presses the buttons. First, we will need a reference to the game over menu set during the ready phase. And set its visible property to falls to hide it. Then when the game over state is reached, we can set its visible property to true. Then pressing any of these buttons should hide the gameover screen menu by setting its visible property back to false. If the player would like to start over from the beginning of the level, we will need to reset a bunch of variables, respond all the enemies treasure, and checkpoints, et cetera. We can simplify this by just unloading and reloading the same level. Unloading is easy since we have a reference to the level node. We can just call underscore level free. In order to reload the level. However, we'll need to know which level was loaded. Opening the data script, we can add two new variables, one for world and the other for level, both with an initial value of one. If you don't want to organize your levels into worlds, you can ignore that variable while we're here. We'll also need to reset these other values when the player starts over from the start of the level adding a public retrying method, we can set coins to zero, lives to three, checkpoint to zero, and has key to false. Back in the game manager script, we can call file data to reset the players progress. Then we can set the value of level to be load, which takes a string argument representing the file path to the resource we want to load. Searching through the file system tab, find your level, right click and select copy path. Then paste this path into the quotation marks. And follow the load call which returns a resource with instantiate to turn that resource into a node. Then add that node to the scene tree with add child, but this will only ever load level one one. We can replace the ones in the file name with the variables from our file data, but the variables are integers. And this is a string cast the integers to strings using STR bracket. As long as every level is inside the levels folder and is named in the same format, it will be loaded by simply setting the world and level variables in the file data. We can then spawn the player, turn off the player controls and revive them. But we don't want the player to see any of this happening. We should start by fading to black. Then at the end, await fade to clear and turn the player controls back on. The player will be at the start of the level which has been completely reloaded anew and they will retry with three lives. For now, if the player wants to return to the level selectional menu, we can just fade to black and reset their file data, since we haven't built that scene yet. But leave a comment or printout statement here so we know in the future to implement this feature. If they press the ex It button, we can await, fade to black. Then call get tree quit to close the game. Alternatively, you may want to have this return to the game's title screen when we have one. For testing purposes, I'll just have the game overscreen visible. By default the Quit button works. The level select button doesn't do much yet, but that's intentional. The retry button works too. But this menu looks bad and doesn't fit the aesthetic of the game. Let's use the asset pack to make it better. I'll start by changing the label to a basic control node named Banner and fill it with texture wrecks, populating them with the letter images to spell game over and sort them using two horizontal boxes. Resetting the size and changing the separation to two pixels between each letter. I'll add in five more texture Ts and use the small banner images to assemble a banner, rearranging them to fit centered about the banner's origin point and have the words written on the banner. I'll then tell the banner to center itself inside the parent vertical box, selecting the game over menu node. Expand the theme section and select New Theme from the drop down. Then click on the theme resource to open it up in the bottom panel. This display shows us several different UI elements and how they will look using this theme resource, which we can edit. Let's add button to the theme. Under the style box tab, there are five options for different button states. Adding all of them to the theme. We can then change how the button looks in each state. Starting with normal, add a new style box texture, click on the style box to open it, then populate it with the green button. One image. The buttons in the preview are now green, as are the buttons in our game. But they're stretched and ugly. Then expand the texture margin section, adding a few pixels of margin space. The image now looks better. The images in this asset pack have a larger bottom margin than the other sides. Since the game over menu is using this theme resource. All of its children also have the same theme applied when hovering or focusing on a button. I'll swap its texture with the yellow button. We can see how this behaves by hovering and clicking on buttons in the preview. When disabled, I'll use the same green button texture, but modulate the color, multiplying the RGB and alpha values all by half so it becomes more gray and faded. When pressed, I'll use the same yellow button texture, but do the same thing, modulating with gray RGB values. But leave alpha at full opacity, removing the text from the buttons. I'll replace them with icons instead. Then child each button to a horizontal box paired up with another horizontal box to act as the button's label. Each label horizontal box will have multiple texture Recs for each letter of the word I want to spell out, telling the horizontal box to shrink and center vertically. For level select, I'll just use an empty text direct as the space. I would like more space between the buttons and their labels. So I'll group select the horizontal boxes and edit their separation values to be 14 pixels. Then I'll put all three buttons in another vertical box and place that inside a panel container node named wood. And also add a panel node to the panel container named paper, Reopening the theme. In the bottom panel, we can make more changes to panels and panel containers. Adding the panel container to the theme, we can give it a style box as well, using prefabs Three as the image. I want wider margins on this panel so the buttons don't look so crowded near the edges. Container nodes automatically resize to fit their contents. Let's also add the panel to the theme. Panels are similar to a texture wrecked, but also have texture margins like the buttons. And I'll use prefab nine as its texture. This has quite wide margins at 20 pixels. And unlike the button images where the inside was just a flat color, the paper and wood have texture that is being stretched. Expanding the axis stretch section, we can set the textures to tile instead of stretch to space things out more, I'll give the wood panel a minimum width of 160 pixels and the paper a custom size of 120 by 100 pixels. Positioning the paper at the right side of the wood and the buttons vertically centered. The words look like they are written on the paper. And remove the custom minimum height of the banner. Now we have a thematic game over screen. In the next section, we'll give the player a sword so they can fight back. I'll see you in the next section. 43. 5-1 Sword: Hello friends. In the previous section, we allowed the player character to take damage and die. In this section, we'll give the player a sword and attacks of their own so they can fight back if you completed the assignment. All of your levels will now have the checkpoints folder. And all of your enemies will have hit death and attack animations. All of your enemies will be able to attack, The player take damage and die if you completed the challenges. You might also have your user interface and game over menu tweening in from off screen. As well as green and blue potions that effect to the character in unique ways. Let's start with a bit of housekeeping. I would like to sort the character and players scripts into a new scripts folder named characters. This main game scene will be used for every level, not just for the first level. So we can delete the level node in the game manager script. We won't be setting the value of level using at on ready. In the ready method. After setting the fade to be visible, we should then load the current level. Writing a new private method. Load level we can use the same code we wrote in the retry button pressed method to load the level and replace that with a method call. Then also move it boundaries and it UI into load level. They will be updated to match the new values. Also add a line to nit UI to set the visible property of the key icon to whether or not the player has the key. Now whatever world a level is set in the file data, that level will be loaded when the game starts. If the level is reloaded or changed, the boundaries and UI will update to match. So far everything we've done in our character script has been applicable, or at least flexible enough, to be applied to any character. However, the asset pack only has the human carrying the sword. To separate these behaviors from the character script, we can create a new script that inherits from character, which will contain behaviors that can only ever be applied to the hero of our game saved in the new character scripts folder, and replacing the character script on the root note of Roger. This script will need an exported Boolean variable to tell us whether or not the hero is currently holding a sword. We can also give this script a class name so other scripts can easily check if something is a character or a hero. I'll also have a private reference to the sword that is equipped. Then add a new public method that other scripts can use to tell Roger to equip a sword. Taking the sword as a parameter, setting the local private variable and setting his sword to another public method, telling our hero to drop the sword. If they don't have a sword to drop, we can ignore and return. Otherwise, setting has sword to falls, telling the sword to be dropped. Passing the hero's global position as an argument, the sword knows where it should be. Since the hero no longer has a sword, the sword variable will be null, which means empty. When the hero dies, we will override the character's behavior of die to check if the hero has a sword and if so drop it, then we still want the rest of the die code to be run too. Instead of copying and pasting, we can use super die to call the inherited definition of die. Following the same process we've used to create all of our collectible treasure. Let's make an equivocal sword for the player character. I want my sword to have physics applied. Sometimes I'll make it a rigid body two D like the coins, but my sword will be more complex than typical treasure items with multiple states and more things to change than just the sprite, more like the treasure chest. Giving it a sprite two D node. I'll set its default sprite to be sword, idle, zero one. Adding an animation player and the animation tree, I can create the idle animation so the sword will spin. Then add a collision shape to the branch, giving it a capsule shape size to fit the swords sprite. I'll put this on layer 26 to keep it separate from other items and have it only collide with the train or the player like the coins. I'll have it unable to rotate frozen by default, with its freeze mode set to Kinematic so it doesn't move, but can still have collisions. And report collisions on contact with up to two at a time selecting the animation treat. I'll set the Anim player property to be this animation player and create a new state machine for now. This will just have the idle animation playing by default. And also add an audio stream player to node, which I will populate with the unsheathed sound effect, saving this branch as its own scene. You might want to put this in a weapons or equipment folder, but since there are no other assets like this, I'll just keep it in the Scenes folder. I moved the sword off of the scene origin, so I'll reset its transfer and property to reenter it. Now we need to create a script for the sword. While this behaves similar to treasure, it's different enough that I would rather not refactor the code and instead just inherit rigid body two D, connect the body entered signal to the script. Thanks to the collision layers, it's pretty safe to assume that the only thing that can cide with the sword is Roger. But I'll check just to be sure if the body is a hero and can equip the sword. We'll need to define this method and have it return a Boolean value. Then we can tell the hero to equip this sword, passing itself as the argument, and become invisible so the player can't see the sword anymore. Since the character sprite will draw to make the physics of dropping the sword easier. I'll also unfreeze the ridge body with set deferred. Grabbing a reference to the audio stream player two do during the ready phase. We can also play the sound effect. When this happens in the hero script, we need to write the equipped sword method returning a Boolean. We only need to say if the hero doesn't have a sword and is not dead. Under these conditions, the hero should be able to equip the sword. Then when the hero drops the sword, they call a dropped method. Writing that definition, we can take the position where the sword was dropped from as a parameter of type vector two. I'll need a random number generator initiated during the ready phase to give a random float between negative one and positive one. I'll set the sword's global position to be that position plus half a tile up. Apply an impulse force of up eight tiles plus right multiplied by a random number similar to the effect of the coins. And finally set visible to true so that the player can see it. We can now duplicate our animations to create new ones where the hero is holding the sword, starting with idol, then run, jump, fall ground and hit. Now we can connect our heroes without sword state machine to the width sword state machine based on the value of has sword opening the width stored state machine. This top layer will contain the attack state machine connected to the hit sword animation, since when the player dies, they will drop the sword inside the attack state machine. For now, just add the movement state machine and connect it from start, adding in the jump, fall, and ground animations, as well as the locomotion state machine, connecting them together in the same ways as everything else. And finally, completing the locomotion state machine two, placing the sword somewhere in your level. The hero will now be able to pick it up and all the animations will still work the same, only with the sword equipped. And when they die, the sword is dropped. We now have a sword item that the player can pick up and equip. In the next lesson, we'll add sword attacks. I'll see you in the next lesson. 44. 5-2 Attack: Hello friends. In the previous lesson we added a sword that the player can equip and drop. In this lesson, we'll add an attack button and the attack animations for the player. Let's start by opening the project settings the input map tab, and adding an attack button. I'll use the left mouse click J button on keyboard and left face button for gamepad. Accommodating a variety of plays styles in two physics layer names. I'll also add player hit, enemy hit, and sword layer names. Then in the player script, during the input event, if the attack button is pressed, then we should tell the player character to attack. The character script has already been set up to process this input setting wants to attack to true, but players can and will mash buttons even when the desired action is impossible. Setting wants to attack to true will trigger an attack when it becomes possible thanks to the animation tree. But this will happen even if a significant amount of time is passed since the button was pressed. We should set a time limit on how long the attack input is considered valid before ignoring it if the character can't perform the attack during that time, let's add a timer node to the hit box named input buffer and set it's time to half a second and one shot to true. Then in the hero script, we can grab a reference to this node during the ready phase. Overriding the definition of attack, we can set wants to attack to true, start the input buffer timer, await its time out signal. Then set wants to attack back to false. If no attack was triggered within half a second of pressing the button, then the button press will be ignored. The duration of time can easily be adjusted in the timer nodes properties. While attacking, I would like to prevent characters from taking any other actions in the character script. I'll need another bullion variable to know if the character is currently attacking or not. Which I will set during the animations and set its value to false when the scene first loads, just in case, like we did with the hit box monitoring. Then in the same way I check if the character is dead before performing other actions, I'll also add the condition that they must not be attacking. However, I'll change run so that if they are dead or attacking, instead of just returning, I'll set the value of direction to zero. Otherwise behave normally. Characters will have to finish their attacks before taking any other actions. I'll also add the condition to the hit box collision that this character must not be dead and must be attacking to be able to inflict damage. In Rogers two D view, I haven't given Rogers hip box node a shape yet connected the signal or set the collision layer and mask. We can easily connect the node signal of area entered to the method we are already defined in the character script. Then set this hip box to be turned off by default on the player hit collision layer layer 11 and masking the enemy T layer layer 18. Selecting Rogers animation player, we can add an attack one animation populated with the appropriate sprites and setting its length setting wants to attack to false during the first frame, we need to set the value of is attacking to true while the animation plays. Then back to false. After it's done, the character knows not to move or jump. Then set the monitoring property of the hip box to true during the second frame and false during the third. Detecting the collision which will hurt enemies. Using the second frame of the animation as a visual guide, create a new shape for the collision. I'll use a capsule and set its color to red to match my other hip boxes. Then set its shape, position, and rotation to fit the affected area of the attack. Adding tracks to the animation for the collision. Shape nodes, shape, position and rotation. We can add key frames for each during the first frame of the animation. Add an animated so to the hip box to create the effect animations. And create an animation for each of the three attack effects with an empty frame at the end as the default value. Just like we did with the enemy attacks. Position the node ahead of the character so that the sprite animation looks like it will line up with the attack back in the attack one animation, we can add a track that plays the effect animation, passing attack one as the first argument in the play method. Call in the inspector. And also an audio playback track to play a swipe sound effect, duplicating the attack one animation. We can create the attack two and attack three animations, swapping out the sprite textures, changing the argument pass to the animated sprite, and populating the audio playback with a new sound effect. Then create a new collision shape for the different attack animations. Readjusting its positional rotation and shape to match the attacks affected area. Depending on which version of Godot you're using. The editor may not display the collider correctly while you do this, but you can still enter values manually in the inspector and repeat the entire process to make attack three. Make sure you create a new collision shaped resource for each animation. Oh, selecting the animation tree. Diving down into the width sword layer, attack layer, We want to add our three attack animations. I'd like to transition through these three attack animations in order as long as the player keeps pressing the attack button, but transition back to movement from any of them if they stop pressing the attack button. First transitioning out of movement to attack one, if the character wants to attack and is on the floor. Then following the same conditions through the other two attacks, only switching at the end of the previous animation. Attacks two and three will return to movement at the end of its animation. But the transition from attack two to attack three will take priority. If its conditions are met, attack one will transition back to movement if either the character does not want to attack or if they are no longer on the floor. Before testing, it would be helpful to be able to see the collider animating in the debug menu. Select Visible Collision Shapes to render collision shapes while the game is playing. Now if we pick up the sword in our game, the player will be able to perform combo attacks with it, each with different animations, collision shapes and sound effects. And the attacks will hurt and kill enemies too. We now have the player character able to perform a three hit combo attack with a sword to fight back against their enemies. In the next lesson, we'll add aerial attacks two. I'll see you in the next lesson. 45. 5-3 Air Attack: Hello friends. In the previous lesson, we added attack animations for the player. In this lesson, we'll add more attacks that the player can use while jumping. Starting in Rogers scene, selecting Roger's animation player node. We can duplicate the attack one animation to create air attack one and swap out the sprites for that animation. Swapping out the swipe sound effect for a different one. We also need to create a new collision shape for this animation. Adjusting its shape, position, and rotation to match the affected area. When adjusting these collision shapes with an animation, it helps to create a new collision shaped node and adjust that instead. Then copy the values into the animation key frames and delete the new node. When you're done, let's rename the animated sprite two node to attack effects. Then duplicate it to create air attack effects. Be sure to create a new sprite frames resource for this new node and create the two air attack effect animations. The air attack effects aren't positioned the same way as the ground attack effects. So we'll need to reposition the node, deleting the track for the attack effect. We can add a new track for the air attack effects instead, then duplicating this animation. To create air attack two, we can repeat the process, swapping out the sprites, changing the argument past to the effect animation, and switching the sound effect. Then adjusting the collision shape to match the attack. Adding these two new animations to the animation tree, they'll behave very much the same as the ground attacks, only with the condition that the character must not be on the floor transitioning from air attack one to air attack two at the end of the animation, under the same conditions. And back to movement at the end of the second attack, transitioning out of air attack one, back to movement. If the player no longer wants to attack or they are on the floor, I would like to create the sensation of suspending in midair while the player is performing these air attacks. We'll override the definition of air physics in the hero script. If the hero is attacking and their y velocity is greater than zero, which means they're falling, then I will set their y velocity to zero, instead keeping them in the air for the duration of their attack. Otherwise, we can use super air physics delta to perform the inherited behaviors from the character script. But since the player can choose to keep attacking infinitely, they can also choose to stay in the air forever. We can rectify this with another game mechanic, a Cool down timer. Adding another timer node to the hip box named Cool Down. I'll leave its time setting at the default 1 second, but set one shot to true. Grabbing a reference to this node during the ready phase in the hero script so we can reference it in the animation tree. Later in the attack animations, we can add a method call track to each starting the cool down timer at the end of each animation. Calling start on the cool down timer. Again, with each attack will simply reset its time value back to 1 second and start counting down again. In the animation tree, we won't allow the transition into the first attack of the sequence unless the cool down timer is stopped. That way the player will be forced to stop attacking after a maximum of three attacks on the ground or two attacks in the air. The duration of the cool down can easily be adjusted in the timer nodes properties. I would also like attacking an enemy from above to bounce the player. Adding an override to the hero script of the hit box area entered method. I'll first need to check if this hero is either dead or not attacking and then return if they are not on the floor. And the global y position of the area struck by the attack is greater than the global y position of the hero, so the enemy being struck is below. Then I will set their y velocity to be jump force divided by two, creating a bounce that will be smaller than a full jump. And finally, call the inherited definition to inflict damage. Well, when creating the players attack animations, I added the new variable for is attacking, but that variable wasn't included in the enemy attack animations. So let's add that in. While the animation tree state machine lightering helps keep things organized. It also introduces the potential for animations to be interrupted, leaving variables set in ways they shouldn't be. For example, if Roger attacks his attacking variable and hip box monitoring are both set to true. But then he gets hit before the animation completes and those variables are not set back to false. Roger now can't move and any enemies that come near him will be damaged by phantom hip boxes. We can reset these variables when the character takes damage or dies. To prevent this from happening, let's create an attack interrupt method. Resetting the value of attacking and hip box monitoring both back to false, and call this method when the character takes damage if they were attacking. We now have the player character able to perform attacks in the air, suspending gravity, and generating a bounce force on impact. In the next lesson, we'll add AI scripts to have the enemy's patrol in area. I'll see you in the next lesson. 46. 5-4 Patrol: Hello, friends. In the previous lesson, we added aerial attacks for the player. In this lesson, we'll write an AI script to make enemies patrol an area. I've moved the other enemies and position fierce tooth in between two obstacles in my level. And disabled the auto attack timer for the most basic enemy behavior. I would like to have them simply walk forward until they hit a wall and turn around. Much like how we created the player node to control the player character, we can create a child node to enemies to control their behavior. With AI, this node will require two D positioning. So I'll make it a node two D and name it Patrol. Giving this node a script name to patrol. I'll put it in the characters scripts folder and use the default template for a node two D. During the ready phase, I'll grab a reference to the parent node, which is the character being controlled. Let's also declare a variable so we know which direction we want to move as a float type. In the ready method, we can initialize the value of direction based on whether the parent character is facing left or not. But the is facing left variable was marked as private. We should add a public method that returns its value to the character script, so we can improperly access it. Then we can set the value of underscore direction based on the return value of the parent characters. Public is facing left method, This allows us to read the value of is facing left but not change it. In the process method, we don't need delta. We should put an underscore in front of it so the engine can ignore it. The default behavior will simply be to tell the character to run in the desired direction. But before we do that, we should check if the character has hit a wall, which is conveniently included in the character body two de node for us. If the character is on a wall, then we should change the value of direction. We can get the walls normal vector, which is a vector that is perpendicular and pointing away from the walls surface. We're only interested in the x portion of this vector to know if the wall is facing left or right. We can also apply sign to this. The return will be either negative one or positive one. This won't matter in my game, since every wall is perfectly flat. Their normal vectors will be exactly left or right anyway. But this code will work with angled walls. Now two, let's try it out. Fierce Tooth is now walking back and forth between the two obstacles. They even detect the player as an obstacle. Two, anything that the character body to D node collides with that prevents horizontal movement will be detected by the is on wall method. What if we position fierce tooth on top of the platform? They will simply run off the side and repeat the same behavior as before. While I may want this behavior sometimes, I probably don't want this to happen all of the time and may want enemies to turn around if they see alleged. This is slightly more complicated since the detection of ledges isn't provided for us. Adding a child node to the patrol node. We can use a ray cast two D node to detect the presence or absence of terrain in front of a character. I'll position the ray to be in the empty space in front of the character and pointing down at the ground. We want the behavior of this enemy to change based on whether or not this arrow is hitting the ground. When they turn around, reposition the arrow to the other side. Back in the patrol script, we can grab a reference to the cast during the ready phase and call it Floor Re then set its position to be half of a tile ahead of the character in the ready method. Alternatively, you could export a variable if your enemies have different sizes and need to position the ray differently. This is an integer division, but I'm doing this on purpose, so I'll ignore the warning. In the process method. Anytime the character is on the floor and the ray is not colliding with anything, that would mean that the character is facing a ledge. So we can call a method ledge detected. If a ledge is detected, we can easily swap the value of direction between negative one and positive one by multiplying it by negative one. Then reset the position of the ray to be in front of the character's new direction. Instead of duplicating the code, we can turn the code from the ready method into a new method and call it anytime we want them to change direction. Now Fierce Tooth will pace back and forth without walking off the platform's edges. Turning on visible collision shapes in the debug menu will also allow us to see the floor ray at work while this happens. But what if I want to make an exception and have some enemies walk off ledges? We can add a new variable type to our script, An enumeration often shorted to enum, which is just a numbered list. Name it, ledge behavior, and then populate this list with all of our options we want to have. I'll just add two options. The default value at the top of the list will be to turn around, but I also want to have the option to walk off ledges two. You might also want to have things like stop or jump off, et cetera. The convention for enumerations is to use upper underscore case. You may remember using an enumeration already which was defined in the rigid body two D node, when setting its freeze mode property. With the enumeration defined, we can export a variable using the enumeration as its type. Then when a ledge is detected, we can match the value of this variable and provide a block of code to run for each. If the alleged behavior is set to turn around, we should run the same code from before. But if it is set to walk off, then we can simply pass or return. Out of this method, you can imagine how this format can be used to provide any number of alternative behaviors. Selecting the patrol node. The inspector now contains a drop down labeled ledge behavior from which we can select the behavior we want described in terms that are easy for anyone to understand. I'll also move the players start position to get a better view. Let's tell Fierce Tooth to walk off ledges and see what happens. Save the patrol node as its own scene in the character's folder. We can now apply the same behavior script to every basic enemy in our game. Adjusting how they react to different terrain obstacles, using casting and enumerations. In the next lesson, we'll give the enemy's player detection an aggressive behavior. I'll see you in the next lesson. 47. 5-5 Aggression: Hello friends. In the previous lesson, we created an AI script that can be used to make any enemy in our game patrol in area and even change their behavior. In this lesson, we'll write another script that will allow the enemies to perceive the player and try to attack them. Let's start in fierce tooth scene. First step will be knowing whether or not an enemy can see the player. This will be a unique behavior to only those characters we want to be enemies. We should create a new script for enemies inheriting from character. We can then replace the character script with the enemy script on Fierce Tooth's root node. Let's add a Boolean variable to know if the enemy can see the player or not. But how do we know if the enemy can see the player? Much like we did with attacking, we can add another area to node to represent the enemy's vision. And give it a collision shape. A use a neutral color, like white for vision. And make it a large circular area that covers several tiles in front of them and slightly around them on all sides. This represents their entire field of vision. We need to know if the player character enters this area. Let's adjust the collision layering. Putting this on layer 20, a new layer for enemy vision and masking layer nine, so they can only see the player. This area will be monitoring, but not monitorable. And always on by default. But there may be obstacles in the way blocking their vision. We can use a cast node to check their line of sight as well. It doesn't matter where the target is right now, I'll just put it in the middle. But the origin point of the Raycast should be from the enemy's eyes. We can distinguish these two nodes by renaming them for Clarity. Field Division will only be looking for the player. The line of sight will be masked by the terrain and the player as well as anything else you would like to obscure their vision. Next, we can connect the body entered and exited signals of the area two D node to the enemy script. These are nicely named for us to vision body entered and exited. Let's store the hero in a variable as they enter and exit the enemy's field of vision. Thanks to collision layers, only the hero should be triggering this method. But it's always safer to check first, storing a reference to the hero as they enter the field of vision and setting that reference to null as they exit the field of vision. To check the line of sight, we'll need a reference to the line of sight nodes set during the ready phase. Then during the process method, we don't need delta. If the hero is within our field of vision, we'll do some maths, but if they aren't in our field division, then we can't see the player setting it to false. We can set the target position of the line of sight to be the difference between the hero's position and the enemy's position pointing the line of sight directly at the player character. If the line of sight is hitting something and that something is the hero, then we can see the player. Otherwise, it must be hitting nothing or something else, like terrain or an obstacle. We can't see the player turning on visible collision shapes in the debug menu and hitting play. Then returning to the editor, we can switch to the remote scene tree and select Fierce Tooth to observe their variables in the inspector in real time. Now we can see that as the player enters the field of vision, the line of sight starts to track their position. The can C player variable is set to true only when they are within the field of vision and unobstructed by terrain from the line of sight. We also need the field of vision to flip like everything else when the enemy faces left or right. Grabbing a reference to the vision node during the ready phase and overriding the definitions of face left and face right. We can start by calling their super methods. Then add setting the scale X of vision to one when facing left or negative one when facing right. Since the enemies are all facing left by default. Since casts don't use the scale property, we will need to add an extra condition when calculating the target position. If the enemy character is not facing left, then multiply the X of the target position by negative one to mirror it. Once the enemy has seen the player, we want to pause their patrolling behavior and have them chase the player instead. In the patrol script, we can add a private Boolean variable to control whether or not this character is patrolling. And set its value to true by default. Then provide public methods for pausing and resuming this behavior. Setting the value of is patrolling in each case when paused Also call character run zero to force them to stop running in the process method. If this character is not patrolling, then we should return and not run any of this code. In the enemy script, we can get a reference to the patrol node during the ready phase even though it may or may not exist using a method named get node or null passing in the name of the node we're looking for as an argument. Then replace each of these three lines with a method call, telling this enemy whether or not they can see the hero writing this new private method hero. It will take a Boolean parameter of whether or not they can now see the hero if the enemy can't see the hero, meaning that the value up to this moment has been false, but now they can see the hero. This is the exact moment when the player entered both their field of vision and line of sight. Then we should set can see hero to true. If the patrol note exists, then tell it to pause its behavior. Inversely, if the enemy could see the hero but now can't, then we can tell the patrolling behavior to resume in case the hero is behind the enemy. We can also force the enemy to face the player's direction at this moment by comparing their global positions and the enemy's process method. If we can see the hero, then we should run toward them using the difference of the hero's global exposition and the enemy's global exposition to know the direction and apply sign to it. So it's only ever negative one or positive one or zero if they are directly above or below. Back in to view, we can add yet another area to node to save time. Let's make it a child of the hip box node and name this one target. I'll make it yellow to indicate danger and make this shape whatever you think makes sense, but probably similar or just a little bit bigger than the red hit box. Place this on another new collision layer, layer 21, the enemy targeting layer and mask. For the player's Rt box layer ten. This will be monitoring and not monitorable. We can connect to the area entered signal to the enemy's script. We don't need the area two D, so we can flag it with an underscore. Then when the player's T box enters the enemy's targeted area, the enemy will attack. Let's try it out. When Fierce Tooth sees Roger, they give chase. And if they can't see Roger, they will go back to their normal patrolling behaviors. If they catch Roger, they will attack. Our enemies can now see and aggressively chase and attack the player. In the next lesson, we'll create an enemy that can shoot projectiles. I'll see you in the next lesson. 48. 5-6 Projectile: Hello friends. In the previous lesson, we allowed our enemies to perceive the player character and attack them. In this lesson will create a new enemy with range attacks. I've already started creating a new enemy for this lesson, the sea shell. So far, the structure of the node tree is the same. The root is a character body, two D on the enemy collision layer, masking the terrain layer with the sprite two D, animation player and animation tree. A collision shaped node with a capsule shaped resource, a matching Rt box, hip box, target box, and vision. Make sure each are set to the appropriate collision layer, masking the correct layers and are monitoring or monitorable. I'll start by adding a node two D named to Projectile origin, which will mark the exact location where projectiles will be fired from. And a timer node, which will tell this enemy to fire. A projectile set to autos start and it will fire every 3 seconds. The animations have all been populated with the appropriate sprites. Idle, hit, fire, and destroyed. Destroyed is only one frame. Then the second frame sets the visible property of the sprite to falls to hide it, the animation tree state machine has the hit and destroyed animations on the top layer transitioning based on the hit and is dead variables of the character script inside the attack state machine. The Seashell defaults to idle, then transitions to fire when they want to fire back to idle at the end of the animation and don't want to fire. Let's create a new character scripts folder for enemies and put enemy and patrol scripts inside it. Like we created the enemy script by inheriting from character, we can give the enemy script a class name enemy, then create a new script named So Inheriting Enemy. Now this script has all the behaviors and attributes of a character, an enemy, and whatever we put in the shooters script to in order to spawn a projectile, just like we did with spawning coins, we can export a packed scene variable, then also export variables to describe the projectiles behavior, like its speed, which I would like to describe in tiles per second. I'll set it to ten by default. Also the damage the projectile will do when it hits the player, an integer ranging 1-100 with a default of one. The maximum duration, I'll allow the projectile to exist before destroying itself as a float, with the default of 10 seconds. During ready. After performing all the inherited ready methods, I'll multiply my speed measured in tiles per second by Cobolpt to change it to pixels per second. Also grab a reference to the projectile origin node. Using at on ready, we can write a method to spawn the projectile which will be called by the shooter enemy's fire animation during the exact frame when the projectile should appear. Creating a temporary variable to hold the newly instantiated projectile. We can position it at its origin point and add it to the scene tree as a sibling of the enemy. If the enemy can move, the projectile will not be affected by the parent's movement. It will exist as an independent entity of the world. We can then tell the projectile to fire, giving it the information it needs to do its job direction, speed, damage, and duration. This enemy will only fire projectiles left or right, depending on which direction they're facing to trigger the fire animation. Just like with the attack animations, we'll have a Boolean variable wants to fire which is set to true by a public method fire in the sea shells animation player. During the fire animation we can set, wants to fire back to false spawn the projectile during the frame when it looks most correct. To do so in the seashell scene I'll also create the projectile which will be an area two D node. I do not want physics to be applied to my projectiles and would rather calculate their behaviors mathematically. If you want your projectiles to use physics, they should use a rigid body two D as a root node. The projectile being fired by the sea shell enemy is a pearl and put it on the enemy hit layer, masking the terrain and the player t layer. Since these are the only things I want the projectile to be able to hit. And it will need a sprite to draw. And a collision shape, which is the circle. I'll color red. Positioning the projectile where it should originate within the seashell. You may want to reposition the projectile origin node based on how it should look in relation to the shooter enemy. I'll also add a timer node, which will primarily be used to limit the duration that this projectile can exist. I'll set it's one shot to true when the pearl hits something I wanted to break. I'll add a node two D named debris. I'll hide the seashell sprite in collision shape for a better view while I make the pearl debris using debris as a folder I can then add child nodes for each piece of broken pearl as rigid body two D nodes. Since now I would like to apply physics. The debris pieces will have their own sprites and collision shapes. I'll position the top half of the pearl where it matches the original pearl sprite and give it a collision shape to match. Put them on a new layer, layer four for debris and mask only terrain, have it unable to rotate and frozen with freeze mode set to Kinematic. Then duplicate it to create the bottom swapping up sprite and repositioning it to match the bottom of the unbroken pearl. Both the top and bottom debris will be hidden by default. With the node structure complete, we can save the projectile branch as its own scene in a new Projectiles folder and open it up for editing. We can now delete the pearl from the seashell scene and reset its position to be centered about the origin. Next, add a script to the pearl's root node named Projectile, saved in the enemy scripts folder. During the ready phase, I'll grab references to the child nodes. I know I'll need to access like the sprite, debris and timer. Having already written the fire method call in the shooter script, we can give that a definition. Accepting a direction as a vector, two speed as a float, damage as an integer, and duration as a float. We will need to store all of these values in private local variables, except the duration. The duration we can simply use to set the timer. If the duration given was anything more than zero, value of less than or equal to zero would be considered unlimited duration. I'll also need a private local variable to know if this projectile has been destroyed or not In the process method, if this projectile has not been destroyed, then add to its position direction times speed times delta. This will make the projectile move in a straight line at a constant speed. Which is the expected behavior of projectiles in most video games. Connecting the area entered in body entered signals to the script. The only body this projectile should clide with is terrain. If this happens, it will tell the projectile to break if it enters an area which should be the player's hurt box. I'll first try getting the area's parent, which should be the player character. After verifying that this is the hero, I'll tell them to take damage, passing the damage amount and direction normalized as arguments, then break the projectile. Adding in the break method, I'll connect it to the timer's timeout signal. It will be called automatically 10 seconds after the projectile is fired. If it didn't hit anything when the projectile breaks, I would like for a few different things to happen over time, which could be done with an animation player, but I would rather do it with relatively simple code. First, I'll add an exported variable for the texture two D, which shows the projectile being destroyed. And swap the sprake for this one D is destroyed variable to true. The projectile stops moving and it's collision mask to zero, so it won't trigger any more collisions. Then I want to reuse the timer node, which is currently being used to trigger the break method on the timeout signal. Since this is the break method, the projectile has struck something and that behavior is no longer necessary. I'll get the timer's timeout signal and disconnect it from the break method. Then restart the timer with a new time, 0.1 seconds, which is the frame rate I've been using for all of my animations. Awaiting the timeout signal is 0.1 seconds later, I'll set the sprites visible property to false, then tell the debris to scatter. Then wait ten more seconds before telling the engine that this projectile is no longer relevant and can be removed from the scene tree. Now we can create a new script to scatter the debris attaching it to the debris node, which I'll put in the environment folder. This script only needs one variable, an array of nodes which are its children. When told to scatter, we can iterate through this array with a for loop following the format of how other languages would write it. For each loop, we can refer to each member of the pieces array as a piece, Then tell it to become visible, unfreeze, and apply an impulse force to it. Since the debris pieces are already distributed to their original positions relative to the unbroken hole, we can simply use their position as the direction of the impulse force, then multiply it by one tile. Of course, you can experiment with different amounts of force being applied to scatter the debris. May be normalizing the direction, so their distance from the origin isn't a factor. When the sea shell is destroyed, we can do the same thing as with the pearl creating the debris. Node two D, this time with four children. For each of the four broken shell sprites copying and pasting the nodes, they will already have the correct settings. Positioning each at the exact location where it will match the unbroken shell sprite and adjust their collision shapes as well. Then attach the debris script to the debris node. Finally, connect the timers timeout signal to tell the sea shell to fire every 3 seconds. Selecting the sea shells root node, we need to populate the packed scene containing the projectile and set the sprite faces left and is facing left to be true. Yes. Then add a method call track to the destroyed animation for the debris to be scattered. At the same moment when the sea shells sprite becomes invisible, let's try it out. The shell shoots pearls every 3 seconds which collide with the terrain and break generating debris, which is automatically removed. After 10 seconds, these pearls can hit and damage the player. And the player can also destroy the sea shell by attacking it with the sword. We now have an enemy that can shoot projectiles at the player. In the next lesson, we'll add a boss enemy to our game. I'll see you in the next lesson. 49. 5-7 Boss: Hello, friends. In the previous lesson, we added a new type of enemy that can shoot projectiles. In this lesson, we'll add a boss enemy encounter to our game. I've gone ahead and created a new level for the boss encounter, which is a pit that once the player jumps into, they will not be able to get out of the level. Checkpoint is right before the boss and the sword is there, so they will have already. The totem pole is made of three shooter enemies, which are almost exactly buckets of the sea shell from the previous lesson. Except that they mask the enemy collision layer for stacking purposes. The blue totem has a custom collision polygon making it difficult for the player to stand on top of it, but still capable of jumping over it. In their projectile is a wooden spike which is a duplicate of the pearl with only the sprites and collision shapes altered. Unlike the pearl sprites, the wooden spike is not symmetrical in the projectile script. Let's add a new exported variable, flip with direction. Then when firing the projectile, if flip with direction and direction x is greater than zero, we should set the scale x two negative one to flip the sprite, collision shape and debris and set the wooden spikes value of this variable to true, leaving the pearls false. Unfortunately, these totem sprites are not centered. To make the individual totems able to face left or right while staying centered within the totem pole, they will need a sprite x offset. Then overriding the definitions of face left and face right, I will set the sprites offset to be this number multiplied by one if there's sprites face left else negative one and vice versa for face right. I'll then set the value of this variable during ready, before super ready. Since super ready will tell the character to face left or right, I discovered a problem with setting the projectiles position before adding it to the scene tree. So we can fix that by adding it to the tree first. Also, I don't want this enemy to have any knocback velocity added to them when taking damage. In the character script, we can add another combat variable named stagger as a float with a default value of five. The other enemies will still have the same behavior as before. Then when a character takes damage, we can multiply the knockback velocity by this new variable and set its value to zero for the boss, removing the effect. How do we create a boss encounter? Let's start by adding an area toting node to this level, which when the player enters, we'll start the boss encounter, then set it to be monitoring for the player layer. I'll give it a rectangle shape and have it filled the entire arena. I would like the camera to remain still and center during the boss fight. So I'll add a new node type A marker two D node and name it Camera A marker two D node is almost the exact same as a node two D, except that it draws a crosshair gizmo in the editor so we can easily see where it is. If we want the camera to stay locked in place during the bosphte, we will need to be able to override its default behavior at a Boolean variable is following subject with the default value of true in the process method. If the camera is not following the subject, then we can return to avoid changing the camera's position. Let's create a new pan variable to perform this panning behavior using a tween. Then a new public method, pan to marker, which will take a marker two D as a parameter and also the duration of the pan with a default value of 1 second. If the pan exists and is running, we should kill it. Then create a new one and tell it to pan the camera's position to the markers global position. When calling this method, we want to override the default following behavior by setting is following subject to false. Then we can add another method to resume following the subject setting is following subject to true. But if we leave it at that, the camera will hard cut to the subject's position. First, we should check if the camera is currently panning and kill that behavior. If it is, we can then reverse the calculations of the camera position from the process method to instead calculate what the look ahead distance and floor height values would be at the camera's current position. Then emit both the changed direction and landed signals, which will tween the camera gently back to the subject. Back in the level scene, we can also add a canvas layer to the level. Unlike the canvas layer in the game scene, which will be drawn over all levels, this canvas layer will only be drawn in levels with the boss copying the player's health gauge. We can paste it into the boss encounters canvas, then reposition it to be at the top center of the display. And replace the heart with the skull, having it hidden. By default, I'll make sure to only show it during the battle. After the battle is over, I want the level end treasure to reveal itself. I'll have the treasure positioned in an impossible to reach area and invisible in the treasure script. I'll add a simple public method named To Reveal, which will take a new position as a vector two parameter. This method will move the treasure to the desired position, Make it visible. Play the effect animation backwards. Wait for the animation to finish. Then play the default animation, selecting the boss encounter node. Let's create the boss encounter script, saving it in the enemy's scripts folder. This script will need a reference to the camera marker and health gauge nodes set during the ready phase. But also a reference to the camera itself, which we can reach by starting our path from the root node. I'll also grab a reference to the level treasure by first accessing this node's parent, which will be the level. Then get node checkpoints. Alternatively, you could export this as a variable connecting the body entered signal to the script. This will be triggered by the player entering the boss arena area. This is when we should start the boss encounter. Let's also store a reference to the hero in a local variable. When this happens to make tracking the position and behavior easier To start the encounter, I'll first pan the camera to the camera marker and then display the health gauge on the UI canvas. Inversely, to end the encounter, we should tell the camera to resume following the player and hide the health gauge Ending the encounter could happen if the player dies or if the boss is defeated. If the boss is defeated, the encounter should end but also reveal the reward. Repurposing the camera marker as the reward location. We can trigger the end encounter method automatically by connecting the body exited signal to it. Since the player will respond outside the arena, this script will need to know what the boss enemy is. In this example I'm using, the boss encounter is actually three enemies. I'll export an array of enemies. I only want to have one health gauge track the combined health of all three enemies. I'll have the boss encounter script handle the extra logic, creating two new variables for current and max health. Then in the ready method, I can iterate through my array of boss enemies, adding up their max health to get a combined total. Then setting current to be equal to the max. I'll also write a new method here that updates to health gauge. Starting current health at zero and iterating through the array. Adding up the current health of all the boss enemies. To get a combined total, we can then calculate the percentage of total health remaining casting current to a float and dividing it by the maximum. Then set the health gauges value using this combined percentage. If the combined total of health is zero, then the boss has been defeated. We can use the health changed signal being emitted by the character script to call this method. But the health changed signal passes a float argument with it, adding that as a parameter to our method. We can ignore it by preceding it with an underscore and connect the signals during the ready method when we calculate the max health. A common mechanic in games is to have the boss's behavior change at certain percentages of health. If the boss isn't dead yet, let's call a phase check method, passing the percentage as an argument. Since this behavior will vary from boss to bos, leave the body blank along with another empty method. Decide next attack. We now have all the generic boss encounter structures in place. Let's give this script a class name so it can be inherited to provide encounter specific behaviors. Removing the boss encounter script from the node. We can instead replace it with an inherited script, specifically describing the behaviors of the totem pole. In this script, we can define how it decides its next attacks, as well as how and when it changes between battle phases. I'll keep things simple by just having a timer note attached to the boss encounter, which I will grab a reference to with at ready. Start at when the boss encounter starts and stop at when the boss encounter ends. Then connect its timeout signal to decide next attack. The totem pole will decide what to do every 1 second. Adding in a random number generator and an integer to store a random integer. I'll first iterate through each boss in the boss's array, then generating a random number 0-2 I can match the results. I'll ignore zero, meaning that the enemy will do nothing. If it's a one, then they will face left and fire. Or if it's a two, they will face right and fire. To increase the difficulty. As the boss's health gets slower, I'll check when the percentage reaches less than one third and less than two thirds when these thresholds are crossed. I'll set the timers wait time to be slightly shorter so the totems attack more often. But I'll make sure that the time remains longer than the animation, allowing you to finish and return to idle between each attack. I won't forget to populate the boss's array with the boss enemies. Let's try it out. The boss encounter is triggered when the player enters the arena. The camera pans and locks in place, and the boss's health gauge is displayed, which tracks the combined health of all three enemies. If the player dies, they are respond at the checkpoint and the boss encounter is paused until the player re enters the arena. When the enemies are all dead, the health gauge disappears, the camera resumes following the player, and the reward is revealed. We now have a boss enemy which would be appropriate to wrap up a world of levels in our game. In the next section, we'll focus on menus and progression. I'll see you in the next section. 50. 6-1 Pause: Hello friends. In the previous section, we added combat to our game. In this section, we'll add menus and progression if you completed the assignment, all of your enemies will now have unique behaviors. Allowing them to patrol an area of your level, looking for the player, then chasing them and attacking. You should also have a cannon capable of firing a cannonball which explodes on impact. If you completed the challenges, your enemies may also be dropping treasure when defeated. The cannon can be operated by either the player or an enemy, and the seashell also has a bite attack. In this lesson will allow the player to pause the game and open a pause menu. Let's start by opening the project settings and adding a pause button to the input map. I'll use the escape key, the start button on my game pad. All of our input handling is currently being processed by the players script. But pausing the game isn't really anything to do with controlling a character. Any node in our scene tree can override the input method. Pausing the game should be the responsibility of the game manager. In the Game Manager script, we can add an input method which takes an input event as a parameter. If the pause button was pressed, we should pause the game. The pause method can take a bulling parameter, I'll call it, should be paused this way. It can be used to either pause if the argument is true or unpause if the argument is false. Pausing is seen in Godot is very simple, just that the value of get tree paused, or in this case two, should be paused. Then when the pause button is pressed, we can pass the value of get tree pause with a knot operator to switch its value as the argument. But if we pause the entire scene tree, including the game manager, then the game manager will not be able to do anything including receiving input and unpausing the game. Selecting the scenes root node. Looking in the inspector. Under node, we can expand the process section and set its process mode to always, even when the game is paused, the game manager will still be running. Anything you would like to pause in your game, select the node and set its process mode property to pile. The default value of inherit will tell all child nodes to inherit the process mode of their parent nodes pausing Rogers node will also pause the player node. Pausing level nodes will pause all their enemies treasure and everything in them. User interface controls like buttons, will still work while the game is paused. But if you're using Tweens to show or hide them, then they will need to be set to always process two. Let's try it out. When the pause button is pressed, the game pauses. When the pause button is pressed again, it unpaus, this is functional, but I would like to present the player with a pause menu and some options. We can start by duplicating the game over menu and renaming it Pause Menu, grabbing a reference to the pause menu. During the ready phase, we can set its visible property when pausing or un pausing the game. I'll quickly edit the banner at the top of the pause menu to say pause instead of game over. Then change the retry button to resume. I no longer want the resume button to call the on retry pressed method. I'll edit the signal connection. We can actually have this call the pause method directly. But the pause method takes a parameter click on the advanced to goal to add extra call arguments. The argument we need to pass to the pause method is a Boolean. We can add it to the list and its default value is false, which is exactly what we want. Clicking connect the Resume button will now tell the game to unpause. The level select and exit buttons can remain exactly the same as they were in the game over menu. But I would like to add another option to restart this level from the beginning, duplicating the resumed button. I'll change this one to be Restart and edit the button label to make this fit better on the screen. With an extra button, I'll edit the panel style box in the theme editor. This paper image is 128 pixels in size, but has an empty border around it of about 12 pixels on all sides. I can tell Godot to only use the sub region of this image, setting the starting x and y coordinates, the width and height of the subregion to be used. Then I'll need to adjust the individual menus to have the words appear on the paper. The retry button from the game over menu and this restart button are very similar in behavior. Let's try to combine them into one method. The only real change I want to make here is not resetting the player's lives and coins. We can rename this on retry pressed method to restart and have it take a Boolean parameter of whether or not this is a game over with a default value of false. Then pass this onto the file data retry method, which I'll change to be called reset. The level will be unloaded, reloaded, and the player returned back to the start of the level. All the same way as before. But if the player has pressed the restart button from the pause menu, we also need to unpause the game. We can do this when loading the level in the data script. We can edit the retry method, renaming it reset, and taking the game over boolean parameter. Now, only if this is being called from a game over state should the lives and coins be reset. In the pause menu, the restart button can be connected to the restart method. Since the parameter has a default value of false, we don't need to specify an argument here. But in the game over menu, the retry button can be connected to the same restart method. This time specifying true as an argument. Now, all the same behaviors will be used by these two buttons, with the only difference being resetting the players lives and coins if they have run out of lives. Let's try it out. Now. When the game is paused, the pause menu is displayed and pressing Resume hides the pause menu pausing the game. The restart button will return the player back to the start of the level, resetting all the level components back to their original states. The level select button isn't doing anything yet, Since we don't have a level selection menu yet and the exit button exits the game. We can now pause our game and give the player a menu of options while the game is paused. In the next lesson, we'll add a title screen to start our game. I'll see you in the next lesson. 51. 6-2 Title: Hello friends. In the previous lesson, we added a pause button and pause menu to our game. In this lesson, we'll add a title scene and main menu. Let's start by creating a new two D scene named title saved in the Scenes folder. We can copy many of the components from other scenes to put in the title scene. Like the background, I'll set the scale property of the title scenes root node to three, matching the zoom of the game scenes. Camera then reposition the background, fill the screen and grab the animated sprites of the water surface from my level scene. Adding a node two D to hold them as one group. I'll also add in a new animated sprite two D node containing the merchant ship. Populating each with the sprites from the asset pack. We can set their animations to autoplay at the desired frame rate. I'll put the ship behind the water by re ordering their nodes, Another for the sail and one for Roger. To then also add a sprite two D node for the anchor. Adding in a canvas layer node, we can add control notes to the title scene. I'll use a vertical box to hold the title and another one to hold the buttons. The title box will contain two horizontal boxes, one for each word, Jolly and Roger, populating each with five text directs. I'll use the big letters from the asset pack for the title spelling out Jolly Roger. I want the letters to always keep their aspect ratios. I'll scale up the size of the title eight times, so it dominates the scene. Then duplicate and repeat to make the other word. I'll move the pivot to be in the center of the title. Then use custom anchors to make it horizontally centered in the screen and one third from the top of the screen. For now, I'll have my title screen only have two buttons, New Game and Continue. I would like these buttons to look the same way as the ones in my other scene. Using the same theme, but the theme we created is local to the game scene. Switching over to the game scene, select any node that has the theme applied. Like the game over menu. Expanding the drop down, we can save the theme as a resource file, making it available for the entire project. I'll save it in the root folder, naming it wood and paper in the title scene, selecting the buttons control node. The wooden paper theme is now available from the quick load menu and its children inherit the theme. I'll scale the buttons up four times and reposition them in the lower left corner. I'll then populate each button with horizontal boxes full of texture Recs to spell out their labels, keeping the aspect ratio of the letters spacing each letter two pixels apart. And give the buttons a minimum size to fit their contents. Resetting the size of the label, I'll anchor it to the center of the button, then duplicate it to make the continued label. Resetting its anchor. I'll make the buttons just a little bit bigger and reposition them. I'll have the continued button disabled by default since it wouldn't make sense to allow the player to press it. If there's no say file yet, we can drag and drop in the fade as well, since we saved that as its zone scene. Let's see how it looks nice in the file script. Let's add a new method to check if the safe file exists. Returning a bull. For now it can just return false. Just like the game scenes root node has a game manager script. This title scene will need a title manager script too. This script will start by making the fade visible. I'll grab a reference to the continued button using at on ready. Then ask the file auto load if a say file exists to load. If a say file exists, then we should set the disabled property of the continued button to false, allowing the player to press it. Then tell the fade to fade to starting the game. Connecting the button pressed signals to the title manager. We can add methods to handle both buttons. If the player presses the new game button, I'll tell the file auto load to create a new data resource. After awaiting fade, fade to black, I'll load the game scene, which will load the first level of my game using get tree change scene to file, which takes a string argument representing the file path to the scene we want to load. Exploring the file system, we can find the game scene right click and copy its path. Then paste it into the quotation marks. If they press the continue button, I'll tell the file out to load. To load the data resource. I would then like to fade to black and change scenes just like the new game button, but load the level selection scene instead. Let's make changing scenes into a separate method. Change scene, taking a string parameter of the scenes file path. Then both new game and continue button presses can call change scene, but switch to different scenes. By now you've probably pressed the Run Project button by accident instead of the Run Current Scene button at least once and been prompted to set a default scene for your project. If you haven't set a main scene yet, you can click select Current to set this title scene as the main scene. Alternatively, you can open the project settings and look under the application section and set the main scene here using the file browser. If we look under Rendering environment, we can change the default color that is displayed when Cade has nothing else to render, Setting it to black to cover any gaps between fading out and fading in. Now if we hit the Run Project button, the title scene fades in from black. Since no say file exists, The continued button remains disabled, but we can click on the new game button. This fades to black and loads the first level, allowing the player to start playing a new game. Our game now has a title scene which access the default scene for our project. In the next lesson, we'll add in the level selection scene. I'll see you in the next lesson. 52. 6-3 Level Select: Hello friends. In the previous lesson, we added a title screen and a main menu to our game. In this lesson, we'll add in a level selection scene. I've gone ahead and created a basic scene, much like the title scene with just a background animated sprites of Roger and the ship helm, a canvas layer, and the fade. Like we did with the theme resource, we can open any level, select the tile map node, and save the tile set as a resource so it can be shared by the entire project. In the level select scene, I'll add a tile map node and load it with the tile set resource. Then use the tile map to draw the stern deck of a ship with Roger at the helm. Implying to the player that between each level, Roger is sailing his ship between islands. Let's see how this looks so far. Nice to display the levels. I'll add a panel container to the canvas. Scale it up to match everything else, and set its theme to wood and paper. This container will contain a vertical box, which will contain a horizontal box for the title. I'll put four texture Ts in the horizontal box to spell out the word maps, making sure that they retain their aspect ratios and remain centered. I'll also center the title as a whole and reduce the separation between letters. Underneath the title, I'll add a grid container. This works much like a vertical or horizontal box, but organizes its contents into a simple grid. Since the maps are each one quarter, I'll make it a two by two grid setting columns to two. Each grid cell will contain another vertical box containing a button and a panel, which the theme has been set to look like paper. I'll set its minimum size to 36 by 32 pixels, so it's large enough to hold the level name. Using another horizontal box to write one hyphen, one, I'll make sure that the label is anchored to the center of the paper. Feel free to name your levels whatever you want for the buttons. I don't want to use the green button. I can remove it by clicking on the flat toggle. Instead of using these green and yellow buttons, I will set the buttons icon property to be the small map, one texture. I'll make sure that the button stay centered within its grid cell. Under theme overrides expanding the style section. I'll also set the focus style to be an empty style box so the button will remain invisible. I'll duplicate level 113 times to make the other buttons in the grid, Changing the name labels of each one to match the levels. You can design this interface to look however you want, accommodating however many worlds the levels you want to have in your game. But this is sufficient for now setting the panel containers pivot to be in its center. I'll anchor it to be two thirds from the left side of the screen and one, two from the top. And change the button icons to match the different map segments. To make these button icons animate, we can select new animated texture from the drop down. Since there are eight images in the small map animation, I'll add eight frames to this animated texture, then set each frame accordingly. The default values tell this animation to play one frame per second. We can either change the individual frame lengths to 0.1 seconds or set the overall speed scale of the entire texture to ten. The button isn't rendering, so I'll change a property to force it to update. Repeating this process, I'll set each of the four map segments to be animated textures for the respective button icons. I'll remove the excess space at the bottom of the panel container by resetting its size and give the title more space with a custom minimum size. Creating a new script for the level select manager. I'll first grab a reference to the fade using at on. Ready. During ready, I'll set the fade to be visible, then tell it to fade to clear. I'll write a custom method to connect the buttons to On level selected, which will take the world and level as parameters, both represented by integers. Connect the button pressed signal from the level one one button to the level select manager and pick this new method. Then expanding advanced, we can add two integer arguments to the signal connection, the world and the level, both with a value of one. Setting the values of file dot data, dot world and level to be their new values. We can then await, fade to black, and load the game scene. The game scene will automatically handle loading the correct level based on the file data. Remember that in order for a level to be loaded using this method, it must be in the level scenes folder and named using the correct format to be detected. We can then connect the rest of the buttons to the same method, changing the values of the arguments to match the world and level which will be loaded, making sure the fate is drawn over everything else. By positioning it at the bottom of the node list, I'll reduce the separation of the vertical boxes to make them take up less space. Then reset the size and position of the menu for the final time. Let's try it out by running the current scene. After the scene fades in, clicking on the level one one button fades back out and loads the first level. If we do it again, clicking on a different button will load a different level. Our game now has a level selection scene, which allows the player to load any level in our game. In the next lesson, we'll allow the game to save and load player data. I'll see you in the next lesson. 53. 6-4 Save: Hello friends. In the previous lesson, we added a level selection scene that can load any level in our game. In this lesson, we'll have the players progression data save and load in the file script, we already set up many of the methods we'll need to complete for this lesson. In other engines and when dealing with consoles saving, loading is a difficult thing to learn. But for the purposes of our game, the Godot Engine provide simple ways to accomplish exactly what we need. First, we need to know where to store the file. Let's declare a variable named path of type string. Starting the path with user colon Godot will automatically find the appropriate place to store our say, file. On most platforms we can give a name to the file. Let's name it auto save. The extension for our text resource is RS. Since this is a value which should never be changed, I'll declare the constant instead of a variable. This is a more efficient way of storing values you know won't change. Unlike variables which are designed to change, the main purpose being to reuse the same value in multiple places throughout your script without rewriting it every time. The T means text, which means that the file that is created can be opened, read, and even edited in any text editor which isn't very secure. But encryption is very ineffective and generally not worth the extra effort no matter how many measures you take. If someone wants to cheat, they will. I would only recommend bothering with security for online multiplayer games. To check if this file exists, all we need to do is call the exists method of the resource loader passing in the path string argument. To save the game, we only need to call the save method of the resource saver passing the data to be saved and the path for its location. Every time we call save, it will overwrite the existing save data. Likewise, loading only needs to set the value of data to be resource loader load, giving it the same path to the file. This is a simple implementation of a single file autosave. You could easily tie the saving and loading commands to menu buttons. And even create multiple say files using the same process. The title manager is already set up to load the players data when the continued button is pressed. The question is, when should we save it? We can start by saving the data at the same time it's created. Keep in mind that this autosave system only stores one, say, file. Starting a new game will overwrite any existing safe file. So when the new game button is pressed, if there is no existing safe file, we can call a new method to start a new game, creating the new save file, saving it, and transitioning to the game scene. If a say file does exist, we should ask the player for consent before overwriting their existing say file. I'll quickly put together a basic container with the question overwrite, save file, and two buttons for yes and no. And set is visible property defaults by default, grabbing a reference to the confirmation using add on ready. I'll make it visible when the player presses the new game button, but a safe file already exists. Then connect the yes and no button presses to the script. All N has to do is hide this confirmation while yes we'll start a new game. Because of the format of my game, I don't really care about what happens during any particular level. In order to track player progression through my game, I only need to know when they complete or exit a level. To keep things simple, I can auto save the game anytime the player enters the level selection scene. In the game manager script, we have some buttons in the pause menu that are still not functional. Let's add in the transitions from the game's pause menu to the level selection scene. When they press exit, return to the title scene. These methods are accessed from the pause menu. The scene tree is paused when these transitions happen, when a new scene is loaded, the tree remains paused. We'll need to unpause the scene tree when the other scenes are loaded using their manager's ready methods. Since the pause menu now only returns to the title scene, the title scene should have an exit button to close the game. I'll put that in the upper right corner. Connect its pressed signal to the manager script and have it await fade to black before calling Get copying the exit button node, we can paste it into the level select scene and edit its signal to connect it to the level select manager script. And have it await fade to black before changing to the title scene. Let's try it out. After collecting a coin, I can exit the level Returning to the level selection scene, where the progress has been automatically saved, closing the game and running it again. The continued button is enabled because the save file exists to load. Pressing continue leads us to the level selection scene, loading any level. We can see that the coin counter was saved and loaded between sessions, closing the game and running it again. We can try to overwrite the save file and be presented with a confirmation before starting a new game with zero coins. Our game now saves and loads player data anytime the player exits or completes a level. In the next lesson, we'll lock access to levels and unlock them when the player completes a level. I'll see you in the next lesson. 54. 6-5 Unlock: Hello friends. In the previous lesson we saved and loaded the player's progression. In this lesson will lock access to levels until the player completes the previous level to unlock it in our data resource, we will want to track information about each level in our game, which are organized into worlds. We can declare a variable named Progress as an array of worlds containing an array of levels, a two dimensional array, a razor empty. By default, we will need to initialize it to be the correct size for our needs and populate it with starting values. We will need an array for every world and a value for every level in each world. If I had two worlds, the array would look like this, but I only have one. I'll remove the second subarray. We want the first level of the game to be unlocked. By default, I'll change the value 0-1 depending on how many different progress markers you want to keep track of per level. Remembering their numerical codes can be problematic. We can define an enumeration to describe the different markers of progress, starting with the level being locked, then unlocked, then completed. Then initialize the first level to be progress unlocked. Adding in a public method to set a progress marker. We can take the progress marker as a parameter along with a world ID and a level ID. Then set the value of progress indexed at world minus one, level minus one. Since arrays start at zero, but our world and level numbers start at one using the R equals operator with the progress marker, giving these a default value. Assuming that most progress markers will be set for the level the player is currently playing. But still allowing us to set markers for other levels if we want to. Since these numbers are being used to index array, we should validate them to avoid crashes. For these numbers to be considered valid array indices, they should be greater than zero and less than are equal to the size of the array. Since we are subtracting one from these numbers. If the array indices are not valid, we should return. But we can also output a message to tell us or any other developer about this error, with a warning stating that the progress marker index was invalid and display the world of level ID's that were used. This is a bit operation, meaning that it is not treating this number like an integer, but as a series of bits, ones and zeros. If we consider each bit to be one progress marker, then the first marker of progress, the first bit, locks the level, if it is zero, and unlocks the level if it is one. The next bit tells us if the level has been completed, starting with zero, meaning that it has not been completed, but then changing to one to become completed. If the level starts with a value of 0000, unlocking it becomes 0001, then marking it as complete will make it 0011. Since it is both unlocked and completed, we can change individual bits using bit operators, allowing us to encode a large amount of information into a single variable. This or operator will set the value of the bit marked by the progress marker to one. We can likewise set the bit to zero using and equals with the progress marker inverted with the operator adding an additional parameter to the method definition. We can turn the progress marker on or off. I'll have the default behavior to set the bit to one or on, since I don't plan on ever locking anything that has been unlocked by the player in my game. Since a single variable contains 32 bits, we can track up to 32 different bits of information per level. This way, adding progress markers to the enumeration. An enumeration is just a numbered list. The entry at the top of the list has a default value of zero. The next one, then 234, et cetera. We can change these numerical assignments if we want to, Giving locked a value of zero, unlocked one and completed two. But I also want to track if the player opens a treasure chest in my levels. The next progress marker, instead of being three, will be four. We could have as many as 32 different values in this enumeration, each time doubling the value to eight, 16, et cetera, If one in binary is 0012, is 0104, is 100. Each progress marker will be all zeros, with only one bit having a value of one, which is the bit that will be set or unset by the set progress marker method. We should remove locked equals zero, since the proper way to lock a level would be to set unlocked progress marker to off. We'll also need to check the values of our progress markers, accepting the progress marker, world and level ID numbers. Same as the set method, but returning a Boolean, We can return the value of progress indexed by the world in level ID numbers minus one. Then apply the bit end operator with the progress marker. We should also validate that the array indices are valid before using them, just like above, and clarify the warning message to be more helpful. This will return true if the progress marker is on or false if it is off, or if the indices were not valid in the level select scene. We can easily control which level the player has access to by toggling the visibility of the level buttons, the grid container will automatically sort the visible contents. In the Level Select Manager script, we can get an array of the grid containers children using add on ready declaring a new integer variable as the index into the array of level buttons. Then iterating through the worlds in the progress array. Again, through the levels in each world. We can set the visible property of each button in the grid container to match whether or not that level has been unlocked. We'll need to add one to the world and level to get the proper ID numbers from their array indices and increment the button index each time. In the level script, we can export variables to know which level is unlocked by completing this level and set their default values to one. The default behavior will be to unlock the first level, essentially accomplishing nothing but not causing any errors. Then in the game manager script, when the map is collected, we can set the progress marker of the current level as completed. And also set the unlocked progress marker of the level that is to be unlocked by completing this level. Then transition to the level select scene in the first level. I'll set its exported values to unlock the second level. Back in the level script, we can track if the player has opened the chest, getting a reference to the key and chest if they exist. Using at on ready get node or null. Then when the level is first loaded, If they do exist and the player has opened the chest for this level, then we can remove the key and tell the chest that it has already been opened in the chest script. Let's add a public method to be already opened, clearing the booty array. Then setting is locked to false and is open to true when the chest is plundered, Set the progress marker for this level that the chest was opened. Let's try it out. Starting a new game, I can exit the first level to the level selection scene, and only the first level is unlocked. Returning to the first level, I can finish it and will be returned to the level selection scene, where the second level has been unlocked. Returning to the first level again. This time I'll open the chest and return to the level selection scene. Entering the first level one last time to see that the key isn't there and the chest is already open. We now have the players progression through the game being tracked by the, say, file, unlocking access to new levels as they go. In the next lesson, we'll add background music to our game. I'll see you in the next lesson. 55. 6-6 Music: Hello friends. In the previous lesson, we locked access to levels until the previous level had been completed by the player. In this lesson, we'll add background music. Let's start in the title scene and add an audio stream player node to the scene. We could set an audio track here, tell it to autoplay and set the volume. Then do this for every scene in level. But the scene transitions would hard cut our music tracks and sound quite jarring as a result, much like we have the screen fading to black, transitioning music should also be faded to provide a better overall experience. I'm going to leave the autoplay on for now and volume to the lowest it will go. Basically muted. Most game developers who aren't also sound engineers will tend to think of volume as a float, 0-1 with zero being muted and one being full volume. But volume is actually measured in decibels, which do not scale linearly. Doubling decibels does not double volume. The volume scale here ranges from negative 80 to 24 decibels. Fortunately, we do not need to know how this works in order to be able to use it effectively. Let's attach a new script to this music node. When the game first starts, the audio is going to autoplay the track with the volume muted. We can start by gently fading the volume from zero up to the desired level, declaring a variable to store the desired volume. In simpler terms that are easier to understand, a float 0-1 with linear scaling, the audio stream player nodes volume property is named volume DB for decibels. So we can declare another new variable, volume L, for linear, to represent the current volume on a linear scale and give it a default value of zero or muted. In the ready method, we can ensure that the volume stays muted by setting the decibel volume to match the linear volume. Converting it with a convenient conversion formula provided by Gade linear to decibels, giving it the linear volume as the argument. Defining a private method to fade the volume. We can take the target linear volume as a parameter. Along with the duration for the fate effect, with the default value of 1 second. While the linear volume is not equal to the target linear volume, we should move the linear volume towards the target linear volume by a small amount. For this, we can get the process delta time and divide by the duration. Then set volume indecibels to match the linear volume and await the next process frame to do it again. When all this is done, we can emit the signal to let anyone who is listening for it know that the volume fate is finished. The way this code is written, it's obvious that the value of duration is meant to be a positive number. To avoid any possible errors or infinite loops, we should check if the value of duration is anything less than or equal to zero. In that case, we can set the volume, immediately omit the signal, and return. Since music will likely be included in every scene of the game, it would be easier to make this into an auto load script. Moving the script into the auto loads folder. Opening the project settings auto loads tab. We can add this to the list of auto loaded nodes. Then delete the audio stream player node from our title scene. For any scene manager to be able to control the background music with a single line of code, all we need to do is define two public methods, one to start a track and one to stop it. Starting with stop track, we'll take a fade time as a parameter, a float, with a default value of 1 second. This can just call fade. The target linear volume is zero, muted, passing the fade time is the argument for the duration. Then await the volume Fade finished signal before stopping the audio stream. Player node to play a track, we can take the track in question as a parameter along with fade time. Set the stream being played to this new track, tell it to play, then fade the volume to the desired volume for the fade time duration. But what if a track is already playing? We can add a couple of extra checks. First to check if music is already playing, then also check if the track that is currently playing is the same as the track that we want to play. If this is the case, we don't need to do anything at all and can return. We can also use this opportunity to ignore null tracks. Otherwise the music node is currently playing a different track. We should fade out that track before fading in the new one. Calling fade with a target linear volume of zero and awaiting the volume fade finished signal, then the remainder of the method can work the same fading in the new track, avoiding any hard cuts in each of the scene manager scripts. We can export a variable to hold the background music track for that scene. Then in the ready method before fading to clear, we can tell the music to play the music track. I populate this variable with a music track from my imported assets level select scene. I'll also export a variable for the background music and play the track during the writing method. I'll use the same background music as the title scene for the level select scene in the game manager script. When loading a level, I'll request the music track from the level. This way each level can set its own background music in the level script, exporting a music variable and setting a different track from the other scenes. And I'll add music tracks to my other levels too. Lastly, I'll also add music to the boss encounter script, but also declare a second variable to store the track that was playing from the level when the boss encounter starts. I can store the levels normal background music in the second variable, then play the boss. Music When the boss encounter ends, I'll revert back to playing the normal level. Music Populating the boss encounter was something more intense than the normal level. Music When exiting the game, we can also fade out the background music too. When importing background music, it's important that it is designed to be looping depending on where you get your music. Looping may be encoded into the files themselves and already be able to loop for these files. I need to open the import settings and set their loop mode to forward. Then click Re Import, so they will loop. Let's try it out. The title screen fades in with some pirate themed music press and continue. The music keeps playing through the scene transition since the music track is the same for both scenes. Entering the boss level, the music fades out and fades in with a new track entering the boss arena. The levels default background music is replaced with a more intense music track. When the boss is defeated, the music returns to normal. Returning to the level selection scene changes the music again and exiting the game fades the music out before closing the window. Our game now plays background music unique to every scene and level, even allowing for tracks to be temporarily changed. In the next lesson, we'll export the game to be played and tested. I'll see you in the next lesson. 56. 6-7 Export: Hello friends. In the previous lesson, we added background music to our game. In this lesson, we'll export the game to be distributed and play tested. Before we can export Godot will need to download export Templates from the editor menu. Select Manage Export Templates. Select a mirror from the drop down, then click Download and install. These templates allow your Godot project to be exported to a wide variety of formats for distribution. Once the process is complete, you can close the export template manager. In the project settings, we've already given our project a name. You may also want to add a description, a version number, and an icon for best results. Try to use an image that is 256 by 256 pixels, or at the very least has square dimensions. We've already set the first scene to run. If you're working for a studio or a publisher, you can add an image here for that too. You may want to make adjustments to the display settings to better fit the exported project, such as defaulting to full screen instead of windowed. If you change any display settings, make sure you test the game to make sure your game sold displays correctly before exporting. In order to change the game's icon when exporting for Windows, you'll need to download an RC edit executable from Github. I recommend putting this file in the Gio Projects folder, since you'll likely need to use it in most, if not all, of your projects. In the editor menu, open the Editor settings under export Windows, there's an option for adding the path to the RC edit executable setting that Cado will now be able to edit icons for exported Windows projects if you have a package signing certificate, this is also the location for providing that information as well. With all the settings configured, we can now go to the Project Menu and click on Export. Click on the Ad button and select the platform you want to export your project. Two, I'll choose Web First. We don't need to do much to adjust the settings here. Exploring the export path. We should create a new folder named Export, or builds, if you prefer. Then within that folder, create a new folder for each platform. In this case, Web. The most important thing when exporting to Web is that the project must be named index HTML. This is the file name that web platforms will look for when embedding your game. If it isn't there, it won't work. Clicking on Export project, uncheck the export with debug checkbox to remove things like warning messages. Then click Save. When it's done, we can close the window. Once the project has been exported, find it in your file browser. Select all the files that were created by Godot and compress them to a zip file named index zip. This is the file you will upload to embed your game into web hosting platforms like Itch in the embed options of these platforms, Shared array buffer support may be required for the game to run. This is one of the easiest ways to distribute early builds of your games. Platforms like it also allow you to sell your games too. But what if your game is really good and you want to sell it professionally on platforms like Steam? Back in the project export window, we can add another platform, this time, Windows. Here you may want to adjust some of the settings, like setting how the game's icon is resized in a pixel art game Scaling using nearest neighbor will maintain pixelization. You may want to also add your company's name if you have one name and description. Copyrighter, trademarks, et cetera. We'll export this into a separate folder from the web export, making a new folder for Windows and renaming the executable to match the name of the game. If you're distributing this internally for alpha testing, you may want to export a debug build for beta testing, early access or release builds. You'll want to have debug turned off also under the debug settings, removing the console wrapper. Then export the project and save. Once the export process is complete, you can find the exported files created by Godot and your File Explorer, Select the files, compress them to a zip file, and upload the compressed zip to distribution platforms to be downloaded. The same process can be used to also build out to Mac, Linux, IOS and Android platforms. Export templates for other platforms like Nintendo or Playstation are not provided by default. You must be approved by the platform before they will let you use their SDK to build games. Our game is now exported and uploaded to distribution sites like It or Steam to be played by anyone. You now have all the skills required to build a complete pixel platform and game. You can build more levels, tweak and adjust things to your liking, and implement more assets from this asset pack. You could also download other asset packs or create your own assets to keep adding new content. Everything in this project is structured in ways to be edited in isolation. You can modify their individual scenes and scripts if you want to. Every implementation is only a basic template that you can build upon or recreate your own from scratch and integrate into the game. Altering anything from how the camera behaves to how the save files are managed should be easy to change. Thanks to the structure we've built, Go ahead and build your game the way you want to make it your own. Then share it with the class either by uploading the project or sharing a link to your Ch page. Play the submitted projects of your colleagues and leave constructive feedback on their work. Thank you for completing the course and be sure to check out my other courses for continued learning.