IN THIS LEVEL

We’ve got a lot to do, let’s get started!

We need heroes! We’ll be learning how to import a character model, then animate it for movement and combat. In Level 2 you’ll learn how to:

  • Import a Character Model

  • Animate Your Model Using AnimationPlayer and AnimationTree

  • Add a Follow Camera to a Character

  • Capture Input to Move Your Character

  • Playtest Your Game!

By the time we are done, you’ll have a character you control who can walk around in game your dungeon room!

You made it back from your side quest! Whew! It’s time to put me in the game coach! Literally! I’m the hero you’ve been holding out for!

Downloading and Importing a Hero

It’s time to go back to itch.io! This time we need some adventurers.

  1. Download Adventurers Character Pack by Kay Lousberg.

  2. Move the zip file into Projects -> Assets -> 3D folder. (Do not unzip it!)

  3. Open KayKit_Adventurers_1.0_(FREE/EXTRA/SOURCE).zip (Whichever version you have.)

  4. Navigate to Characters-> gltf.

  5. Navigate to Projects -> dungeon-delvers -> assets -> models. (In a second File Manager window.)

  6. Make the folder “characters”. (You should now have dungeon-delvers -> assets -> models -> characters.)

  7. Drag and drop Knight.glb from the gltf folder into the characters folder. (You do not need knight_texture.png - it is embedded in the .glb file.)

When Godot imports the Knight, it will create three new files. It will export the texture, and then make import files for both files. Let’s take a look at our imported knight.

  1. Open Godot. (Wait for all the assets to be imported.)

  2. Find Knight.glb in the FileSystem.

  3. Open the Import tab. (Upper left dock next to Scene.)

  4. Click the Advanced… button.

This is your first up close look at the knight. (It’s Gerard!) You can left-click on the model and drag to rotate it around to take a good look.

On the left-hand side we have an Actions button at the top. Below that we have three tabs: Scene, Meshes, and Materials. Poke around and explore them for a bit. We are only interested in the Scene tab. In it, we have the Rig, which contain all the animation points Kay put into the model in Blender. The points themselves are called Bones, and adding them in is called “rigging” (the skeleton).

Below the Rig, you will see an AnimationPlayer. It contains all the animations for the model that we are about to (re-)import. Click on a few and test them out by pressing the play button. Cool, huh? Let’s take a look at one of the looping animations, something that ends in -ing, like Running or Walking. If you hit the play button, you can see it’s very short. Let’s fix that.

  1. Select the Walking_A animation.

  2. Change the Loop Mode to Linear. (Under Settings on the right-hand side.)

  3. Press the Spacebar to play the animation.

Notice how the animation loops now? We could go in and change all the animations that need to be looped by hand, and then do it again for every character we import. Or, we could be lazy. We could write a script!

While we’re at it, we want to update the layers and masks. We are going to be using a For Loop to make it easier. If you’re not familiar with for loops, check out this tutorial.

Another thing we can solve with a script is all the knight’s equipment. You may have noticed when looking at the model, that he is carrying every weapon and every shield at the same time. So, in our script we will “unequip” these items by hiding them. Then we will put them back as needed by making only the ones we want to see visible.

The script can also rotate the Rig 180 degrees. Unfortunately, the way these characters are exported, Godot considers them facing backwards. So we are fixing this. We are also re-labeling all of the BoneAttachment3D nodes (the animation points) so that they are easily distinguishable from the items attached to them.

Once again, we are giving you the script to copy. This time, instead of explaining it here, we have added comments to help you figure out what’s going on. We’ve also added logging, which actually takes up almost half the code of the script. This informs us of all the changes that were made, so that we know it’s working. When you have a complex import script, you want to know that everything is working. Later on, we will be adding actual logging to our project, but for now, these rich text print statements will do.

In addition to attaching our script, we are going to import our knight as a CharacterBody3D. This is the node type to use for any character we want to move around that has animations, so we will set it up on import. Close the Advanced import window (we’ll be back later, don’t worry.)

  1. Click the Textbox next to RootName. (Nodes section of the Import tab.)

  2. Type “CharacterBody3D” in the Search Box.

  3. Select CharacterBody3D from the Matches below.

  4. Press the Change button.

  5. Attach the import_characters.gd script to Knight.glb for import.. (Refer to Importing Floors in Level 1 for step-by-step instructions.)

  6. Press the Reimport (*) button. (You will see our logging in the Output window.)

  7. Right-click on Knight.glb in FileSystem.

  8. Select New Inherited Scene.

  9. Click on the Scene tab.

  10. Press Ctrl + S.

  11. Save knight.tscn in res://mobiles/characters. (You will need to make the folders.)

Now you can see Gerard standing there. You can even see his face! On the left-hand side in the scene tree (left-hand side, Scene tab), you’ll notice that the visibility for all his weapons and accessories are hidden. (The closed eyelids.) Click on a few and his items will reappear and disappear again. In the next section, we will learn how to use all the animations we just imported.

Character design is an important part of a videogame. Before you can flesh out an engaging story, you need engaging characters. Not just what your characters look like, but who they are. What are their histories? What are their goals? You’re going to need a notebook. (Or Google Doc.) For every main character in your story, write down a minimum of 7 pages about your character.

Need some questions to get you started? You can look up questions for pen-and-paper roleplaying game character creation, or advice for screenwriters or novelists. The goal is when you present your character with any situation, you know how they will respond.

All these answers will help you decide what your characters should look like, how they should act and talk, and what matters to them. The motivations of your characters will drive the story forward.
If you’re wondering why we are using a folder named “mobiles”, it’s an homage back to the first MMO, made in 1978 called MUD1 (Multi-User Dungeon). Technically, players then weren’t considered mobiles, but since we are going to be moving some of them around using AI, and we want to keep the root level from being too cluttered, we are putting them here.

Adding Walking and Running Animations

Now that we’re done playing with the knight’s equipment, scroll to the bottom of the scene tree and click on AnimationPlayer. At the bottom of the screen, the Animation tab will automatically be selected in the bottom dock. Click the Play button for 1H_Melee_Attack_Chop. It kinda looks like he’s headbutting someone. Let’s equip his Round_Shield and 1H_Sword. Play the animation again. Looks better, yes?

The next step is to tie the walking and running animations together, and define the transitions between them. To do that, we are going to use the AnimationTree node.

  1. Select the Root Node in the Scene Tree. (The one labeled Knight.)

  2. Press the + button right above the Root Node.

  3. Select AnimationTree. (If you don’t see it, you can search for it.)

  4. Click the Create button.

  5. Click the Inspector tab in the right-hand dock.

  6. Click the <empty> box next to Tree Root. (AnimationTree section.)

  7. Select New AnimationNodeStateMachine.

  8. Click the Assign button for Anim Player.

  9. Select the AnimationPlayer.

  10. Click Ok.

The AnimationTree tab is now in the bottom dock. You’ll see a Start state and an End state.

  1. Press Shift + F12 to have the AnimationTree window take up the whole center screen. (You can also click the Expand Bottom Panel button (two arrows pointing up) in the lower right-hand corner of the bottom dock.)

  2. Right-click in the center of the open area.

  3. Select BlendSpace2D.

  4. Click on name “Blendspace"2D”.

  5. Change it to IWR. (Stands for Idle/Walk/Run.)

  6. Shift + Click and drag from Start to IWR to connect the two states.

  7. Click the edit icon (little pencil) to open up the BlendSpace Editor.

  8. Select the pointer button in the toolbar. (The arrow, second from left.)

  9. Right-click in the center of the grid (0, 0).

  10. Select Add Animation -> Idle.

  11. Right-click at the far left on the y-axis (-1, 0).

  12. Select Add Animation -> Running_Strafe_Left.

  13. Right-click at the far right on the y-axis (1, 0).

  14. Select Add Animation -> Running_Strafe_Right.

  15. Right-click on the bottom of the x-axis (0, -1).

  16. Select Add Animation -> Walking_Backwards.

At this point two triangles will appear connecting the four points. Let’s take a look at how the BlendTree works.

  1. Press Shift + F12. (Lowers the expanded view.)

  2. Click the Root button in the Path. (Top of the BlendTree window.)

  3. Click the Play button for IWR.

Now the knight should be bouncing up and down in his idling animation.

  1. Click the edit icon for IWR.

  2. Select the Blending Position icon in the toolbar. (Cross with a pointer, first icon.)

  3. Click and drag inside the triangles.

Notice how the animation changes gradually as you move towards and away from the points? Now let’s add the forward movement animations. (We have three walk, and two run animations.)

  1. Press F12.

  2. Put the blending position back cursor in the center again (0,0).

  3. Select the pointer icon.

  4. Right-click at the top of the x-axis (0, 1).

  5. Select Add Animation -> Running_A.

  6. Right-click two sections down on the x-axis (0, 0.8).

  7. Select Add Animation -> Running_B.

  8. Right-click two sections down on the x-axis (0, 0.6).

  9. Select Add Animation -> Walking_A.

  10. Right-click two sections down on the x-axis (0, 0.4).

  11. Select Add Animation -> Walking_B.

  12. Right-click two sections down on the x-axis (0, 0.2).

  13. Select Add Animation -> Walking_C.

When you are done, your BlendTree should look like the picture to the right. You can minimize the BlendTree and test it out to see the new animations in action. (Once you’re done, reset the blending position to (0,0).) Next, we are going to add a camera to our character.

Whenever there’s an Assign button in the Inspector, you can also drag and drop whatever Node or Resource it’s looking for onto the Assign button instead.

The import_characters.gd script should set all Idle animations and all animations ending in -ing to a looping mode of linear. However, due to a bug, they may not stay set correctly. In this case, you can fix the problem manually:

  1. Select Knight.glb. (FileSystem -> assets -> models -> characters)

  2. Click on the Import tab. (Upper-right dock next to Scene.)

  3. Click the Advanced… button.

  4. Scroll down to the AnimationPlayer node.

  5. Click on 1H_Ranged_Aiming.

  6. Change Loop Mode to Linear. (Right Side -> Settings -> Loop Mode)

  7. Repeat Step 6 for every Idle animation and animation that ends in -ing.

  8. Click the Reimport button.

Adding a Follow Camera

We are going to be implementing a third-person camera that follow the character, but also provides free-look. Free-look means mouse movement rotates the camera, and only affects character movement when the character is actually moving. This allows us to see the character models we choose, allows the player to see equipment equipped, and it allows the player to very clearly see everything around a room in 360 degrees.

The first thing we need to do is attach a camera to the player. We could attach it directly, but we are going to attach it to a SpringArm3D node. This will handle issues with the camera getting blocked by things in our dungeon unintentionally.

  1. Right-click on our root node (Knight).

  2. Select Add Child Node.

  3. Select a SpringArm3D node.

  4. Change its Spring Length to “5m”. (Inspector -> SpringArm3d)

  5. Change its y Position to “2.5”. (Inspector -> Node3D -> Transform)

  6. Press Create.

  7. Add a Camera3D node as a child node of the SpringArm3D node.

That’s it!

There are different camera choices you can make in your game about the camera. You can even allow more than one. First-person, second-person, third-person fixed, third-person with free-look, top-down, and 3D isometric are all options. (Not to mention cinematic cameras for cutscenes.)

It’s important to think about what kinds of camera(s) you want to have available for your players. If you’re doing top-down isometric, as opposed to first-person, it’s going to change how you build your levels. It’s also going to affect how fun your game is to play. Frustrating camera angles can cause people to quit playing a game.

Adding a Collision Shape

You may have noticed a pesky yellow warning sign by our Knight node this whole time. It is telling us that just like our floors and walls need collision shapes, our characters do too. We do this by adding a CollisionShape3D node to our knight. In this case, we need it so the player won’t fall through floors or walk through walls. We will also use it later so that our player can pick up items and interact with doors.

  1. Add a CollisionShape3D node as a child of our root (Knight) node. (Note when it is created it’s complaining it needs a shape.)

  2. Change its y Position to “1.2”. (Inspector -> Node3D -> Transform)

  3. Click on the <empty> slot for the Shape property. (Inspector -> CollisionShape3D)

  4. Select NewCapsuleShape3D.

  5. Click on the CapsuleShape3D resource. (Inspector -> CollisionShape3D -> Shape -> CapsuleShape3D)

  6. Change the Height to “2.4m”.

We now have a collision shape for our Knight, and we can put him in our room!

Main Game Scene

Normally in game programming, you have a main game loop, and everything runs off of that. Godot has a main game scene. This is just a scene you create and then tell Godot, it’s the main one. The main game loop still happens, its implementation is just done for us. So, it processes physics interactions. For example, in a second, when we add our knight character to the room, he won’t fall through the floor. We don’t have to write any code for that. It just happens. So let’s make our main scene and test it out.

  1. Select Scene -> New Scene.

  2. Click 3D Scene. (In the Scene tab under Create Root Node:)

  3. Rename the root node “Main”.

  4. Right-click on our Main node and select Instantiate Child Scene...

  5. Search for “room”.

  6. Select environment/rooms/room_01.tscn

  7. Click the Open button.

  8. Drag and drop knight.tscn from FileSystem onto the Main node. (FileSystem -> mobiles -> characters)

  9. Press F6.

  10. Click the Save button. (The Main scene is one of the few things that goes in the root of our project.)

We can see Gerard in the game! Well, his back. It’s also kind of dark. Let’s fix that latter problem.

  1. Close the game.

  2. Click the Edit Sun and Environment settings toolbar button. (It’s the three vertical dots in the toolbar to the right of the sun and world icons that are blue.

  3. Click the Add Sun to Scene button.

  4. Click the Edit Sun and Environment settings toolbar button (again).

  5. Click the Add Environment to Scene button.

  6. Press F5.

  7. Press the Select Current button.

Looks better now, right? You’ll see then Sun and Environment buttons in the toolbar are greyed out, and now we have WorldEnvironment and DirectionalLight3D (our sun) nodes in our scene tree. We also set the current scene as the main scene of our game. (If you need to change it, it’s in Project -> Project Settings… -> Application -> Run -> Main scene.) Now we are ready to add in controls and movement.

You may notice that while our knight is in the room, he is not a child of the room. Instead, he is a child of the Main node. This allows us to change the room the knight is in without having to recreate the knight.

Movement

Now that we’ve got a place for our knight to stand, it’s time to code in some movement. But first, we have to code in movement keys! We do this in project settings.

  1. Go to Project -> Project Settings…

  2. Select the Input Map tab.

  3. Click the Add New Action box.

  4. Type “move_forward”.

  5. Press Enter.

  6. Add the following additional actions:
    move_backward
    move_left
    move_right

  7. Click the Add event button next to move_forward. (Plus sign.)

  8. Press the “W” key.

  9. Click the Ok button.

  10. Add events for the other three keys:
    S - move_backward
    A - move_left
    D - move_right

  11. Click the Close button.

Now that the keys are mapped, it’s time to add a script to use those keys.

  1. Open your knight scene. (Either click on the tab if it’s still open, or double-click on knight.tscn in FileSystem.)

  2. Right-click on the root (Knight) node.

  3. Select the Attach Script…

  4. select CharacterBody3D: Basic Movement for the Template.

  5. Rename the script to “character.gd”.

  6. Press the Create button.

  7. Press Ctrl + S. (Save the default.)

  8. Press F5.

You can now move around with the Arrow Keys and jump with the Spacebar. No, we didn’t set any of these keys up. They are defaults configured by the system. (You can toggle viewing the defaults on the Input Map.) We configured our own because that is Godot’s recommended best practice, and we will be using those. The knight also has no animations when he moves. We will fix that in just a second.

However first, we need to tweak the camera. If you walk backwards far enough, the camera goes through the wall. This is because the walls are on collision layer 2. To fix this, we just have to tell the SpringArm3D to not do that.

  1. Select the SpringArm3D node.

  2. Click “2” for the collision mask. (Inspector -> SpringArm3D -> Collision Mask)

The number 2 should have a blue background now. If you run the game (F5) and back up, you’ll see how the camera gets closer to the knight’s head. Now that we have that working, we are going to update character.gd.

  1. Copy the code from the right into character.gd, overwriting what is in there.

  2. Press Ctrl + S.

  3. Press F5.

You’ll see the camera now rotates with the mouse, allowing you to look around the room and control the player easier. We are almost done with this level!

You can add as many events to each action as you want. For example, you could add the arrow keys for movement as well. If you have a gamepad, you could add the left joystick movement to these actions as well.
The prepended “move” to all our directions may seem excessive, but when we start adding things like “dodge_left”, etc. it will make our code clearer.

Bonus XP: character.gd Explained

Our player_character.gd script is our first in-game script. We will be building on this script, and it will be one of the biggest in the game. Over time we will be dividing it up into smaller scripts. We won’t be covering things we went over in the Level 1 Bonus XP section, so go back there if you don’t see something here. We also won’t be explaining lines that are almost identical.

@export_group("Physics")

The annotation @export_group tells the Godot that all the @export annotations that come after this should be grouped into a category called “Physics”. If you click on Knight’s root node, and then take a look at the Inspector, you will see a section called player_character.gd, and underneath that a collapsed section called Physics.

The yellow in quotes denotes a String, a built-in data type that holds text.

@export var speed = 5.0

The @export annotation tells Godot that we want the value following to be editable in the editor. If you expand the Physics group in the editor, you will find the four values we added. These values don’t need to be here, but they are here for now so that you can tweak them while playing. Trying opening up the game and changing these values and seeing what happens to your gameplay experience.

@onready var spring_arm = $SpringArm3D

The @onready annotation which assigns a variable once the scene has loaded. In this case, the spring arm holding our camera. Without this notation, we would try to load it into a variable before the spring_arm even existed, and it would fail. The notation $SpringArm3D is a reference to a node that is a child of the current scene (or node) this script is attached to.

var direction := Vector3.ZERO

This line declares a variable named direction and then uses an inferred type assignment ( := ). The colon in front of the equals says to not only assign the value to the right into the variable on the left, but to declare it as whatever type is being declared. It is being implicitly statically typed as a Vector3, and set to (0, 0, 0).

This variable is being declared as a class scoped variable. A variable in class scope can be used by any function in the whole script. All of our @export and @onready variables are in the class scope as well. When we can, we pass variables as arguments. However some variables need to be accessed and modified by multiple functions in a class. At times like these, we use a class scoped variable.

Processing Physics

func _physics_process(delta: float) -> void:

This is a system-defined function that can be created to do things related to physics of the game or updating the display in a time-based manner. It starts with an underscore, denoting it as a private function. We will be doing a lot of processing here, even though we are delegating that processing out to other functions to reduce the cognitive load of this function.

The game loop passes every object that calls _physics_process() a value called delta. This value is the change in time since the last time this function was called. Basically, delta keeps everything in synch. By multiplying values by delta, we can ensure that the CPU and video card process just the right amount of change per frame so that things don’t jump around on screen.

You’ll notice our delta argument has a colon ( : ) and then a green float after it. That indicates that the variable delta is statically typed, and is of a certain type: a floating point variable. A float basically is capable of storing a decimal number. In this case, it’s carrying a number less than one, and that is being used to make sure that every fraction of a second, everything only changes as much as it needs to for a steady frame rate.

At the end of our function declaration we have an arrow ( -> ). This arrow means that this function is statically typed to only return a value that matches the type given. In this case, that type is void. Void means this function cannot return a value. Instead, it can only return control to whoever passed it. It is essentially saying, “What happens here, stays here.”.

if not is_on_floor():

This is calling a function already defined by CharacterBody3D. If our character isn’t on the floor, the next line moves them towards the floor. These lines were not changed from the default Godot gave us. They work great!

get_input()

This is a new function we have defined. The whole point of it was to take all the input processing and place it in another function. This will help us later when we want to create NPC versions of characters (for example other knights wandering about town.) It will also help us in making cutscenes, and when we want to do unit testing of our character class. (More on that later.)

velocity = lerp(velocity, direction * speed, acceleration * delta)

Here we are assigning a value to the class-scoped velocity variable. We are doing interpolation on that value using the global function lerp() (linear interpolation). (Lint was already taken.) It gets the transition state between two points - in this case, it determines the amount to move based on delta (the framerate length in fractions of a second), plus our direction, speed, and acceleration.

do_animation()

This custom function will handle the blending of the walking/running animations.

move_and_slide()

This is a built-in function to handle physics collisions. The function move_and_slide() uses the class scoped variable velocity to compute movement and handle collisions. (It is set up in update_velocity(), which is called by get_input(), which we will see in a second.) Right now our collision handling is limited to walls and floors.

if velocity.length() > 1.0: rotate_to(delta)

This line starts with an inline if statement. If you have only one line of execution after and if statement, you can put it on the same line. Typically, you want to put it on another line, as this makes it more difficult to read. However, we wanted you to see this was possible, and we have a reason for it we will explain when we start testing.

As you’ve seen, we are naming our functions so it’s clear what each one does. This one rotates the character, passing in the value delta.

Getting Input

func _unhandled_input(event):

Another built-in, private function. This one handles InputEvents like the physics processor does. When possible, we want to use this function instead of physics process, because it doesn’t get checked every frame. It’s fast enough to pause a game. It’s not fast enough for smooth animations. In this case, anytime an event is caught by the computer, this function grabs that event and processes it, ignoring any events it doesn’t know how to process.

if event is InputEventMouseMotion:

In this line, we are looking for the player moving the mouse. If that happens, we process it on the next three lines. In this case, we are rotating the SpringArm3D node, which then allows the attached camera to rotate.

spring_arm.rotation.x -= event.relative.y * mouse_sensitivity

This line changes the rotation of our camera by subtracting the relative y coordinate of the mouse from the current x value of the SpringArm3D node. The (-=) operator says take our value and subtract whatever follows and then make that our new value. The multiplication by the mouse_sensitivity is to slow the camera movement around so it’s contraollable by a human. You can play with this value in the inspector while you’re playing the game, and see what effect changing it has. (Inspector -> character.gd -> Physics -> Mouse sensitivity)

spring_arm.rotation_degrees.x = clamp(spring_arm.rotation_degrees.x, -90.0, 30.0)

This line is using clamp global scope function. It is a function that takes the value we just set and makes sure it doesn’t go outside the bounds next two values. This prevents the camera from spinning wildly around. It then gets assigned back to the initial value.

func get_input() -> void:

Our function for getting movement input from the player.

update_velocity(Input.get_vector("move_left", "move_right", "move_forward", "move_backward"))

This line calls the function update_velocity(), passing a Vector2 object. That vector is being created by Input.get_vector(). Input is what’s known as a singleton. It is a class that there can only be one of in the entire program. Its method get_vector() takes as arguments our four input keys. If we hooked a joystick up to them, it would handle those too.

Other Custom Functions

func update_velocity(direction: Vector2) -> void:

This function takes a Vector2, updates the class variable direction, and then applies it to the class variable velocity. The reason we separated this function out from get_input() is so that we can directly call this method to move our Knight without user input. This will also allow us to repurpose this code rather easily for NPCs, because the input and movement functions are not tightly coupled.

direction = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).rotated(Vector3.UP, spring_arm.rotation.y)

On this line, we are using the Vector2 input_dir variable to construct direction. We are then rotating it to face whichever way the camera is pointing. This is why if you rotate the camera and press the forward key, the character translates that forward movement to mean the way the camera is pointing, not the way it is currently facing. (The rotation happens below.)

All of the rest of the code in this function (and the last one) deal with vector algebra. They are explained in the Godot Tutorial: Your First 3D Game. We aren’t going to go over this code again. It is very straightforward if you understand vector math. However, vector math is complicated and not necessary to understand how to make games. The whole point of engines like Godot is to put a wrapper around that complicated math and let more people make games. When it’s helpful to understand what’s going on, be assured we will explain it. Godot is still relatively new as engines go, and it still has gotchas.

There are many times in coding, where using someone else’s solution is preferable to figuring out how to code something from scratch. This is one of those times. One way of being lazy is coding yourself out of repetitive work. Another is finding code that gets you out of doing that work. We’ve already done that by both using Godot, and installing plugins to Godot. You’ve done it by copying the code that has been provided in these lessons.

func do_animation() -> void:

This function handles our walk animation. It does more vector algebra. Specifically it takes the character’s velocity and determines what animation frame to ask for from the character’s AnimationTree -> IWR State. It then sets that blend position in the AnimationTree.

func rotate_to(delta) -> void:

This function rotates the character to face the direction the SpringArm3D (and the attached Camera3D) is facing. It uses the lerp_angle() global function which does the same thing as the lerp() function, but for rotation instead of position.

Bonus XP Gained!

Congrats! You’ve finished this deep dive into the character.gd script! Let’s go finish up Level 3!

You can create a node reference by typing it in, or by just dragging and dropping the node into the code editor!
We’ll be talking about the physics engine a lot in this section. It is explained in more detail in the Godot Tutorial, Your First 3D Game.

Godot Tutorial: Your First 3D Game

Cognitive load is one of the measures to determine how complex code is. The idea is if we have too many logical branches, nested statements, or just difficult to read code, that you get lost in it. It then takes you longer to figure out what the code is doing, and longer to maintain it. So, we are teaching you from the beginning how to keep your functions small, and how to separate out responsibility between functions (and later classes), so that you learn good programming practices. The number one mistake of new developers is to put everything into one file.
Variable scope is a simple topic, but using class and globally scoped variable can cause problems. For a video game, these problems are lag and game crashes. Use globally and class scoped variables when necessary, but limit their use as much as possible.
If you’re interested in algebraic vector math, here’s some links to get you started. It is very interesting, but unless you are coding game engines directly, it’s not strictly necessary.
Design Patterns are solutions to common problems that crop up in Object-Oriented Programming. The Singleton is one that is used often. We will be using it to handle our sound volume and our game menu for example. Things that we want to make sure there are only one of in our game.
Remember: If there’s something we didn’t go into enough detail about for you, you can always couple click on it in the code, then right-click and select Lookup Symbol. You’ll be taken to the documentation in Godot which will tell you more.
Variables in GDScript are dynamically typed by default, but can be statically typed. It is good practice to statically type your variables when you can, if for no other reason than your code will run faster.

Godot Tutorial: Static vs. Dynamic Typing

One Last Thing

We’ve added another resource! Did you update your Readme to reflect that?

Add the following two lines to your Readme under the 3D Models header.

### Characters ###
[Adventurers Character Pack](https://kaylousberg.itch.io/kaykit-adventurers) by [Kay Lousberg](https://kaylousberg.com/) ([Pateron](https://www.patreon.com/kaylousberg))

If you don’t have a Readme, or have no idea what one even is, maybe it’s time to go do Side Quest 1! You’ll be glad you did later!

A Final Note

You may have noticed that the wall_doorway.gtlf seems to have lost its door when it was imported into a mesh library. While frustrating, this is ok. It is just a limitation of the GridMap node. In our next Side Quest we will solve this problem.

Attribution is not only the right thing to do, it can help you if you lose assets and need to get them again, you want to hire someone to make more assets to match what you have, and it meets the minimum requirement for using most free assets legally in a commercial game.

Think about all the time and money you’re spending learning how to make a game. The people providing these assets spent just as much time learning their craft. Godot is part of the open-source community, and supporting others with recognition is part of that community.

Level Up!

You’ve made your first character and leveled up again! In Level 5 we are going to be learning about Unit Testing. Unit testing is a way for us to make sure our code works before we even play our game! We are going to show you how to add a door. We will use it to test out the code we’ve written for our character. You will learn how to write unit tests so that all of this functionality is tested automatically for you! Plus, how to create unit tests before you start writing code, as we add functionality to our character.

After that we will be moving on to Level 6 where we will introduce navigation nodes to send our character towards objects. Then we will animate our door to open when the player approaches, and close when the player walks away. We’ll also add door sound effects, and show you how to add keys to doors.

Level 5! You’re really getting the hang of this!