0% found this document useful (0 votes)
12 views65 pages

Course PDF Notes

This document outlines a beginner-friendly course for developing a 3D platformer game using the Godot engine, led by instructor Daniel Buckley. The course covers key components such as player movement, enemy behavior, collectible coins, and level transitions, with an emphasis on practical implementation and understanding of Godot and GDScript. Additionally, it provides guidance on project setup, asset importing, and enhancing game visuals using various Godot features.

Uploaded by

xpetrichorx
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views65 pages

Course PDF Notes

This document outlines a beginner-friendly course for developing a 3D platformer game using the Godot engine, led by instructor Daniel Buckley. The course covers key components such as player movement, enemy behavior, collectible coins, and level transitions, with an emphasis on practical implementation and understanding of Godot and GDScript. Additionally, it provides guidance on project setup, asset importing, and enhancing game visuals using various Godot features.

Uploaded by

xpetrichorx
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Develop a Complete 3D Platformer in Godot

Introduction

Welcome to our beginner-friendly course on developing a 3D platformer game using the Godot
engine. Your instructor for this course is Daniel Buckley. Together, we will explore various aspects of
game development in Godot, including level setup, creating coins, enemies, a player controller, and
more. By the end of this course, you will have a fully functional 3D platformer game.

Course Overview

Our 3D platformer project will consist of several key components:

The Player

The player will be a scene that can be moved around and can jump using various keys on
your keyboard (arrow keys, WASD, etc.).
We will set up input maps to facilitate these movements.
The player will have movement animations, including bobbing up and down and rotating to
face the direction of movement.

Enemies

Enemies will be represented by buzz saws that move from one position to another.
These enemies will be customizable, allowing you to set their movement speed, direction,
and distance.
Upon hitting the player, enemies will deal damage, reduce the player’s health, and trigger
sound effects and screen shake.

Coins

Coins will be collectible items that disappear when the player collects them, increasing the
player’s score and playing a sound effect.
Coins will have a visual effect where they bob up and down and rotate over time to attract
the player’s attention.

End Flag

The end flag will serve as a portal between levels.


When the player runs into the end flag, they will be teleported to the next level, allowing for
a seamless transition between different parts of the game.

Course Requirements

To fully benefit from this course, a basic understanding of Godot and GDScript is recommended.
However, do not worry if you are not fully proficient. We will go through the code line by line,
ensuring that you understand each step. Here are some assumed knowledge areas:

Familiarity with the Godot editor


Understanding of nodes, variables, and functions
Basic knowledge of signals and how functions work

About Zenva

Zenva is an online learning academy with over a million students. We offer a wide range of courses
suitable for beginners and those looking to learn something new. Our courses are versatile, allowing
you to learn in various ways:

Follow the online tutorial

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Introduction

Read the included lesson summaries


Use the included course files

Getting Started

Now that you have an overview of what to expect, let’s dive into the first lesson and begin our
journey into 3D platformer game development with Godot.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Godot Installation and Version

Which version of Godot should you use for this course?

Technology changes rapidly, so to make sure you have an optimal learning experience we
recommend using Godot 4.4 Beta for this course – the upcoming stable release.

Please make sure not to use newer versions of the software than what we recommend, as the course
material provided might not work as expected.

How to Install Version 4.4 Beta

You can download the preview version of Godot by heading to the preview downloads page on the
Godot website: [Link]

Once on the download page, just click the Standard option for whichever operating system is
relevant to your system for Godot 4.4 Beta. This will download the Godot engine to your local
computer. From there, unzip the file and simply click on the application launcher – no further
installation steps are required!

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Game Design

Welcome to this beginner-friendly guide on designing a 3D platformer game using the Godot engine.
Before we dive into the practical aspects of creating the game, it’s essential to outline the game’s
design, mechanics, and key elements. This article will walk you through the fundamental building
blocks required to develop your 3D platformer game.

Game Overview

The game is a 3D platformer where the player’s primary objectives are to collect coins and avoid
enemies. The ultimate goal of each level is to reach the end flag, which teleports the player to the
next level. Here’s a breakdown of the game’s key elements:

Player Character

Movement: The player can move using the keyboard and jump. Inputs for movement will be
defined using Godot’s input map system.
Visual Polish: The player character will rotate to face the direction of movement and bob up
and down to simulate motion.
Health System: The player has a health variable that decreases when hit by enemies. If the
health reaches zero, the player is sent back to the menu.

Enemies

Behavior: Enemies are spinning blades that move from one point to another. Their
movement direction, distance, and speed can be defined.
Damage Mechanics: When an enemy hits the player, the following occurs:
1. The player’s health variable decreases by one.
2. The health UI updates to show the remaining health.
3. Screen shake effect simulates the impact.
4. A damage sound effect is played.

Coins

Collectibles: Coins are collectibles that increase the player’s score by one when picked up.
Animation: Coins rotate and bob up and down.
Sound Effect: A sound effect is played when a coin is collected.

Scoring System

The scoring system will be implemented using auto load scripts or singletons, allowing the score to
persist across levels. This ensures that the player’s score is maintained throughout the game.

End Flag

Level Transition: The end flag is a node placed at the end of each level. When the player
enters it, the next level is loaded.

Menu

First Scene: The menu is the first scene the player encounters.
Play Button: Pressing the play button loads the player into level one.
Quit Button: Pressing the quit button closes the game.

Setting Up the Game

Now that we have a clear understanding of the game’s design and mechanics, we can begin setting

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Game Design

up the game in Godot. Stay tuned for the next steps, where we will dive into the practical aspects of
creating our 3D platformer game.

This overview provides a solid foundation for beginners at Zenva to understand the key components
of a 3D platformer game in Godot. As we progress, we will delve deeper into each element, ensuring
a comprehensive learning experience.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Project Setup

Welcome to this beginner-friendly guide on starting your first project in Godot. This article will walk
you through the initial steps of setting up your project, importing assets, and creating your first
scene. By the end of this guide, you will have a solid foundation to build upon as you continue your
learning journey with Zenva.

Setting Up the Project

Begin by opening Godot and creating a new project. The first thing you will see is the editor interface
with various docks. You can rearrange these docks to suit your preferences. For this guide, let’s
enlarge the FileSystem and Inspector docks to get a better view of our project structure and asset
properties.

Importing Assets

Before we start building our game, we need to import some assets. These assets include audio clips,
3D models, and sprites for the user interface (UI). You can download the provided zip file from the
course files tab, which contains the following:

Audio files (e.g., coin sound effect, take damage sound effect)
3D models (e.g., character models, platformer models)
Sprites (e.g., heart PNG, menu background)

To import these assets, follow these steps:

1. Extract the downloaded zip file to your computer.


2. Select all the assets and drag them into the FileSystem dock in Godot.
3. Once the import process is complete, you should see three folders in your project: audio,
models, and sprites.

Feel free to explore the imported assets by clicking on the folders and previewing the contents. You
can always use your own assets if you prefer, but using the provided assets will help you follow along
with the course exactly.

Creating the Base Scene

Now that we have our assets imported, let’s create our base scene, which will serve as the first level
of our game. To do this, follow these steps:

1. Click on the “New Scene” button in the top left corner of the editor.
2. Select “3D Scene” as the root node type, since we are creating a 3D game.
3. Rename the root node to “Main” for better organization.
4. Save the scene by going to Scene -> Save Scene or pressing Ctrl + S.
5. Create a new folder named “scenes” in the FileSystem dock and save the scene as “Level1”
within this folder.

Additionally, create a folder for our scripts by right-clicking on the res:// folder, selecting “New
Folder,” and naming it “scripts.” This folder will be used to store our scripts in the future.

Next Steps

With our base scene set up, we are now ready to start creating the game environment. In the next
lesson, we will begin adding platforms and other visual elements to our scene. This will serve as the
foundation for our player to interact with as we continue to develop our game.

Congratulations on completing the initial setup of your Godot project! Stay tuned for more lessons as

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Project Setup

we dive deeper into game development with Zenva.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Environment - Part 1

Welcome to this beginner-friendly tutorial from Zenva on setting up a basic environment for a
platformer game. In this lesson, we will guide you through the process of creating a simple level for
your player to navigate. By the end of this tutorial, you will have a basic understanding of how to set
up platforms, configure lighting, and manage physics in your game environment.

Planning Your Level Design

Before we dive into the technical aspects, let’s plan what we want our level to look like. For this
tutorial, we will create a central platform where the player spawns and a clockwise loop of platforms
that get higher, leading to an end flag.

Setting Up the Initial Platform

1. Open your models folder and navigate to the ‘platformer’ section.


2. Select a suitable platform model, such as ‘block grass low large’, and drag it into your scene.
3. Center the platform in the world by setting its position to (0, 0, 0) in the X, Y, and Z axes.

Adding a Camera

To view our environment, we need to add a camera:

1. Create a new Camera3D node.


2. Position the camera at an angle that provides a good view of the platform.
3. Save and play the scene to ensure the camera is working correctly.

Configuring Lighting

To improve the visibility and aesthetics of our scene, we need to add lighting:

1. Create a new DirectionalLight3D node. This will act as the sun in our scene.
2. Adjust the light’s rotation to change the time of day (e.g., daytime, nighttime).
3. Enable shadows in the inspector to add realism to the scene. You can adjust the blur and
opacity of the shadows to achieve the desired effect.

Making Platforms Physical

To ensure that the player can interact with the platforms, we need to give them physical properties:

1. Select the platform model and click on the ‘Mesh’ button at the top of the screen.
2. Choose ‘Create Collision Shape’ and select ‘Simplified Convex’ as the collision shape type.
3. Create a new StaticBody3D node and drag the model and collider as children of this node.
4. Rename the static body and collider for better organization.

Alternative Method for Creating Platforms

There is an alternative method to create platforms with a static body and collider:

1. Select the model and click on the ‘Mesh’ button.


2. Choose ‘Create Collision Shape’ and set it to be a static body child.
3. This method creates the static body as a child of the model, streamlining the process.

Building Your Level

Now that you know how to create platforms, it’s time to build your level:

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Environment - Part 1

Drag in more platforms and position them to create a path for the player.
Use the methods outlined above to ensure each platform has a static body and collider.
Experiment with different models and arrangements to create a unique level design.

In the next lesson, we will improve our environment a bit further before jumping into our player
setup.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Environment - Part 2

Welcome to this beginner-friendly guide on enhancing your game’s visuals using Godot’s
WorldEnvironment node. In this article, we will walk through the process of setting up a background,
adding fog, adjusting colors, and organizing your scene. By the end of this tutorial, you will have a
more visually appealing and organized game scene.

Introduction to WorldEnvironment Node

The WorldEnvironment node in Godot is a powerful tool that allows you to modify various aspects of
your game’s visuals. With this node, you can add fog, adjust saturation, brightness, contrast, glow,
ambient occlusion, reflections, skies, and more. This node is essential for creating a immersive and
visually appealing game environment.

Setting Up the Sky

To begin, let’s set up a sky for our game. A sky adds depth and realism to your game environment.

1. Create a new WorldEnvironment node and select it.


2. In the Inspector, go to the Environment property and create a new environment.
3. Expand the environment properties and navigate to the Background section.
4. Change the mode from Clear Color to Sky.
5. In the Sky section, choose a new sky resource and select a ProceduralSkyMaterial.

By following these steps, you will have a basic sky in your game. However, to make it more
interesting, we can add some fog.

Adding Fog

Fog can enhance the atmosphere of your game by adding a layer of depth and color.

1. In the WorldEnvironment node, scroll down to the Fog section and enable it.
2. Adjust the Light Color to your desired fog color. For this tutorial, let’s choose a pinkish-purple
color.
3. Increase the Light Energy to make the fog brighter. A value of 1.2 is a good starting point.
4. Adjust the Density to control the thickness of the fog. A value of 0.06 works well for a subtle
effect.
5. Enable Height Fog and set the Height to 2m and Height Density to 0.4 for a gradual fog effect
along the y-axis.

Adjusting Colors

To make your game’s visuals pop, you can adjust the brightness, contrast, and saturation.

1. In the WorldEnvironment node, scroll down to the Adjustments section and enable it.
2. Increase the Contrast to about 1.2 for a more vibrant look.
3. Increase the Saturation to make the colors more vivid.

Ambient Light

Ambient light defines the color of objects that are not directly hit by the sun. Adjusting ambient light
can greatly enhance the overall look of your game.

1. In the WorldEnvironment node, scroll down to the Ambient Light section.


2. Change the Source from Background to Color.
3. Adjust the color to a purplish tint to match the fog and sky.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Environment - Part 2

Screen Space Ambient Occlusion (SSAO)

Screen Space Ambient Occlusion (SSAO) adds shadows where two models intersect, creating a more
realistic lighting effect.

1. In the WorldEnvironment node, scroll down to the SSAO section and enable it.
2. Observe the differences in the corners where two models intersect to see the effect in action.

Organizing Your Scene

To keep your scene organized, you can use base nodes as folders to group related nodes together.

1. Create a new base node and name it “Environment”.


2. Drag the WorldEnvironment and DirectionalLight nodes into the Environment folder.
3. Create another base node for your platforms and drag all platform nodes into this folder.

Organizing your scene makes it easier to manage, especially as you add more elements like enemies
and coins.

Conclusion

Congratulations! You have successfully enhanced your game’s visuals using the WorldEnvironment
node in Godot. By adding a sky, fog, adjusting colors, and organizing your scene, you have created a
more immersive and visually appealing game environment. In the next lesson, we will begin setting
up our player. Stay tuned and happy learning!

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Player Scene

Welcome to this beginner-friendly guide on setting up your player character in Godot, tailored for
those starting their journey with Zenva. In this tutorial, we will walk through the process of creating
and configuring your player character, which will serve as the heart of your game. By the end of this
guide, you will have a player character that can move, jump, collect coins, interact with enemies,
and reach the end flag.

Creating the Player Root Node

To begin, we need to create a root node for our player. This node will be of type CharacterBody3D.
The CharacterBody3D node is essential for characters as it provides built-in physics, velocity settings
for movement, collision detection, and various other functionalities that simplify character creation.

1. In your Level1 scene, create a new node of type CharacterBody3D.


2. Rename this node to Player for clarity.

Adding a Visual Representation

Next, we need to add a visual representation for our player. This will be the model that players see
and control in the game.

1. Navigate to your models folder, specifically models/characters.


2. Drag and drop your chosen model into the scene as a child of the Player node.
3. Rename the model node to Model.
4. Set the model’s transform position to (0, 0, 0) to center it on the player.

Adding a Collision Shape

To enable physics and collision detection, we need to add a collision shape to our player.

1. Right-click on the Player node and add a child node of type CollisionShape3D.
2. In the inspector, set the shape to New CapsuleShape3D.
3. Adjust the radius and height of the capsule to fit the player model appropriately.
4. Ensure the capsule is positioned so that the player’s feet are at the bottom of the capsule.

You can use the side view to fine-tune the positioning. If the view is obscured by a purple overlay,
temporarily disable the fog in the world environment settings.

Setting Up the Camera

To ensure the camera follows the player, we need to configure it correctly.

1. Drag the camera node to be a child of the Player node.


2. Rotate the camera around its y-axis to 180 degrees so it faces the direction the player is
moving.
3. Position the camera behind the player for a proper following view.
4. Rotate the player around its y-axis to 180 degrees to face the level.
5. Place the player on the ground by adjusting its position.

Saving the Player Scene

To reuse the player setup in multiple levels, save it as a separate scene.

1. Drag the Player node into your scenes folder.


2. Save it as [Link].

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Player Scene

Ensure the player root node’s rotation is set to zero to avoid warnings. Adjust the rotation in the
main level scene if necessary.

Adding a Script to the Player

Finally, we need to add a script to control the player’s behavior.

1. Select the Player root node in the player scene.


2. Create a new script and save it in the scripts folder.
3. Name the script player_controller.gd.

In the next lesson, we will focus on setting up player inputs and coding the player’s movement and
jumping mechanics. Stay tuned for more detailed instructions on enhancing your player character’s
functionality.

Thank you for following along, and we look forward to seeing you in the next lesson!

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Input Map

Welcome to another informative lesson from Zenva. In this tutorial, we will guide you through setting
up player inputs in Godot. Inputs are essential for mapping specific keys to corresponding actions in
your game, such as moving forward with the ‘W’ key or jumping with the spacebar. Properly
configuring these inputs is crucial before you start coding, as it ensures your script knows which keys
trigger which actions.

Understanding Inputs in Godot

In Godot, inputs are managed through actions. Actions are what your script will listen for, rather than
specific keys. For example, your code will listen for a ‘jump’ action instead of directly checking if the
spacebar is pressed. This abstraction allows for greater flexibility, as you can associate multiple keys
with a single action.

Setting Up Inputs

To set up your inputs, follow these steps:

1. Navigate to the top menu and select Project.

2. Go to Project Settings.

3. In the Project Settings window, select the Input Map tab.

Creating Actions

Actions are the intermediaries between key presses and your script. Here’s how to create and
configure actions:

1. Click the Add button to create a new action. Name it ‘jump’.

2. With the action selected, click the Plus icon on the right to add a new key.

3. Use the filter to find and select the spacebar. Click OK to associate the spacebar with the
‘jump’ action.

Adding More Actions

You will need to create additional actions for movement. Follow the same steps to create the
following actions:

move_forward: Associate with ‘W’ and the up arrow key.

move_back: Associate with ‘S’ and the down arrow key.

move_left: Associate with ‘A’ and the left arrow key.

move_right: Associate with ‘D’ and the right arrow key.

Remember, you can add multiple keys to a single action. This is useful for supporting both keyboard
and controller inputs.

Next Steps

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Input Map

With all your inputs and actions set up, you are now ready to start scripting your movement logic
using these actions. In the next lesson, we will dive into scripting and utilize these actions to control
your player’s movements.

Thank you for joining us today. We look forward to seeing you in the next lesson!

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Player Movement - Part 1

Welcome back to our course on game development with Godot. In this lesson, we will begin working
on our PlayerController script, which will manage all aspects related to our player’s movement. This
script will be crucial for defining how our player interacts with the game world.

Setting Up the Player Controller Script

To get started, ensure you have the PlayerController script open. If you don’t see it, select your
Player node and double-click on the PlayerController script. If the script does not exist, create a new
script attached to the Player node.

Defining Movement Variables

We will begin by defining a few essential variables that will control our player’s movement:

move_speed: This float variable will define how many units the player moves per second.
jump_force: This float variable will define the force applied upwards when the player jumps.
gravity: This float variable will define the downward force applied to the player.
camera: This variable will hold a reference to our camera.

Let’s start by adding the move_speed variable:

extends CharacterBody3D

@export var move_speed : float = 3.0

The @export tag allows us to modify this variable directly from the Godot editor, making it easier to
tweak values without changing the script.

Next, add the jump_force and gravity variables:

@export var jump_force : float = 8.0


@export var gravity : float = 20.0

Finally, add the camera variable with the @onready tag to automatically assign the camera
reference when the node is ready:

@onready var camera : Camera3D = $Camera3D

Setting Up the Physics Process Function

The _physics_process function is where we will handle all physics-related code. This function is called
a fixed number of times per second, ensuring consistent physics calculations.

Let’s create the _physics_process function and add comments for the steps we will implement:

func _physics_process(delta):
# Apply gravity
# Implement jump
# Implement movement

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Player Movement - Part 1

Implementing Movement

We will start by implementing the movement logic. This involves getting the player’s input and
moving the player based on that input.

First, get the movement input:

var move_input : Vector2 = -Input.get_vector("move_right", "move_left", "move_back",


"move_forward")

Next, convert the 2D movement input to a 3D direction:

var move_dir : Vector3 = Vector3(move_input.x, 0, move_input.y)

Now, set the player’s velocity based on the movement direction:

velocity.x = move_dir.x
velocity.z = move_dir.z

Finally, call the move_and_slide function to move the player and handle collisions:

move_and_slide()

Putting it all together, your _physics_process function should look like this:

func _physics_process(delta):
# Apply gravity
# Implement jump

# Implement movement
var move_input : Vector2 = -Input.get_vector("move_right", "move_left", "move_bac
k", "move_forward")
var move_dir : Vector3 = Vector3(move_input.x, 0, move_input.y)

velocity.x = move_dir.x
velocity.z = move_dir.z

move_and_slide()

Challenge: Adjusting Movement Speed

As a challenge, try to modify the code so that the player’s movement speed is affected by the
move_speed variable. Hint: You will need to multiply the velocity components by move_speed.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Player Movement - Part 1

With this setup, you should now have a basic movement system for your player. In the next lessons,
we will continue to build upon this foundation, adding more features and refining the player’s
controls.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Player Movement - Part 2

In this lesson, we will enhance our player character’s movement by implementing gravity and jump
functionality. By the end of this lesson, you will have a character that can move, fall due to gravity,
and jump when the spacebar is pressed.

Challenge Solution

In the last lesson, we issued a challenge to you to adjust the movement with the move_speed
variable we set up. To do this, we simply need to multiply our velocity direction vectors by the
move_speed:

velocity.x = move_dir.x * move_speed


velocity.z = move_dir.z * move_speed

Implementing Gravity

First, let’s add gravity to our player character to make it fall when not standing on a platform. We will
modify the _physics_process function in the player_controller.gd script.

Find the following line in the _physics_process function:

# gravity

Below this line, add the following code to apply gravity to the player:

velocity.y -= gravity * delta

This line decreases the y-velocity by the value of gravity multiplied by delta (the time passed since
the last frame), causing the player to accelerate downwards.

Implementing Jump

Next, let’s implement the jump functionality. We want the player to jump only when the spacebar is
pressed and the player is standing on the floor. Add the following code below the gravity line in the
_physics_process function:

# jump
if Input.is_action_pressed("jump") and is_on_floor():
velocity.y = jump_force

This code checks if the “jump” action (spacebar) is pressed and if the player is on the floor. If both
conditions are true, it sets the y-velocity to jump_force, causing the player to jump.

Adjusting the Camera

Finally, let’s adjust the camera to provide a better view of the player’s surroundings. Back in Godot,
manually adjust the tilt of the camera down to ensure the platform can be seen better. The goal
should be for the player to better understand where they’re jumping too and judge the distances

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Player Movement - Part 2

correctly.

Summary

In this lesson, we implemented gravity and jump functionality for our player character. We also
adjusted the camera to provide a better view of the game world. With these additions, our character
controller now supports basic movement, gravity, and jumping.

In the next lesson, we will improve our player’s visuals by adding rotation to face the direction of
movement and implementing a bobbing effect to simulate movement animation.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Player Visual - Part 1

Welcome back! In this lesson, we will focus on enhancing the visuals of our player character.
Specifically, we will implement two key features:

Rotating the player to face the direction of movement.


Adding a subtle movement bob to simulate the up-and-down motion when the player moves.

Let’s dive into the steps required to achieve these improvements.

Setting Up the Player Visual Script

First, we need to create a new script for our player’s model. This script will handle the rotation and
movement bob effects.

1. Navigate to the player scene and select the model.


2. Create a new script named player_visual.gd and place it inside the Scripts folder.

Defining Variables

We will define several variables to control the rotation rate, target rotation, and reference to the
player node.

extends MeshInstance3D

@export var rotate_rate : float = 20.0


var target_y_rot : float = 0

@onready var player : CharacterBody3D = get_parent()

rotate_rate: This variable controls how fast the player rotates to face the movement
direction.
target_y_rot: This variable stores the target rotation along the y-axis.
player: This variable references the player node to access its velocity.

Creating Functions

Next, we will create the necessary functions to handle the rotation and movement bob effects. We
will start by defining the function structures and then fill them out.

func _process(delta):
_smooth_rotation(delta)
_move_bob(delta)

func _smooth_rotation(delta):
pass

func _move_bob(delta):
pass

_process(delta): This function is called every frame and will invoke the _smooth_rotation and
_move_bob functions.
_smooth_rotation(delta): This function will handle the smooth rotation of the player model.
_move_bob(delta): This function will handle the movement bob effect.

Implementing Smooth Rotation

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Player Visual - Part 1

The _smooth_rotation function will rotate the player model to face the direction of movement. We
will use the player’s velocity to determine the target rotation.

func _smooth_rotation(delta):
var vel = -[Link]

if vel.x != 0 or vel.z != 0:
target_y_rot = atan2(vel.x, vel.z)

rotation.y = lerp_angle(rotation.y, target_y_rot, rotate_rate * delta)

We first get the player’s velocity and store it in the vel variable.
If the player is moving (i.e., vel.x or vel.z is not zero), we calculate the target rotation using
the atan2 function.
We then smoothly interpolate the current rotation to the target rotation using the lerp_angle
function.

Implementing Movement Bob

The _move_bob function will add a subtle up-and-down motion to the player model when moving. We
will use the player’s velocity to determine the movement speed and apply the bob effect only when
the player is moving on the ground.

func _move_bob(delta):
var move_speed = [Link]()

if move_speed < 0.1 or not player.is_on_floor():


scale.y = 1
return

We first calculate the movement speed using the length of the player’s velocity.
If the player is standing still (move_speed < 0.1) or not on the ground (not
player.is_on_floor()), we set the scale to 1 and return. This more or less stops the bobbing
motion from happening, as in those scenarios we wouldn’t want to simulate movement.

In the next lesson, we will complete our bobbing motion and discuss in-depth how we can properly
adjust the player’s y-scale over time.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Player Visual - Part 2

Welcome back! In this lesson, we will continue working on our MoveBob code. Our goal is to make
the player’s scale bob up and down slightly over time while moving on the ground. This effect will be
achieved using a sine wave. Let’s dive into the details.

Understanding Sine Waves

A sine wave is a mathematical function that returns a value based on a given time. The wave
oscillates between -1 and 1, creating a smooth, repetitive pattern. This pattern is perfect for creating
a bobbing effect.

Implementing the Bobbing Effect

To implement the bobbing effect, we need to follow these steps:

1. Create a time variable that increments over time.


2. Use the sine function to calculate the y-scale based on the time variable.
3. Apply the calculated y-scale to the player’s scale.
4. Adjust the amplitude and frequency of the sine wave to achieve the desired bobbing effect.

Step-by-Step Code Implementation


Step 1: Create a Time Variable

First, we need to create a variable that keeps track of the time. We’ll use Godot’s
Time.get_unix_time_from_system() function to get the current time in seconds.

var time = Time.get_unix_time_from_system()

Step 2: Calculate the Y-Scale Using the Sine Function

Next, we’ll use the sine function to calculate the y-scale. The sine function takes a time value and
returns a value between -1 and 1.

var y_scale = sin(time)

Step 3: Apply the Y-Scale to the Player’s Scale

We’ll apply the calculated y-scale to the player’s scale.y property.

scale.y = y_scale

Step 4: Adjust the Amplitude and Frequency

To make the bobbing effect more subtle and visually appealing, we need to adjust the amplitude and
frequency of the sine wave. We’ll multiply the sine value by a small number to control the amplitude
and multiply the time variable by a larger number to control the frequency.

var y_scale = 1 + (sin(time * 30) * 0.08)

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Player Visual - Part 2

Complete Code Snippet

Here is the complete code snippet that implements the bobbing effect:

func _move_bob (delta):


var move_speed = [Link]()

if move_speed < 0.1 or not player.is_on_floor():


scale.y = 1
return

var time = Time.get_unix_time_from_system()


var y_scale = 1 + (sin(time * 30) * 0.08)
scale.y = y_scale

Testing the Bobbing Effect

After implementing the code, test the bobbing effect by moving the player around. You should see
the player’s scale bobbing up and down slightly, creating a more dynamic and visually appealing
movement.

Expanding the Effect

You can expand upon this effect by adding more visual improvements, such as:

Making the player stretch out when jumping and squash back down when landing.
Adding more complex animations based on the player’s movement and actions.

That’s it for this lesson! You’ve successfully implemented a bobbing effect using a sine wave. In the
next lessons, we’ll continue to enhance our game with more advanced features.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Enemy - Part 1

In this lesson, we will set up our enemy in the game. The enemy will move back and forth between
two positions and detect when the player comes into contact with it. This detection will later be used
to apply damage to the player. Let’s get started by creating and configuring our enemy node.

Creating the Enemy Node

To begin, we need to create an Area3D node. This node will detect collisions with other objects
without physically blocking them, acting like a trigger.

1. Create an Area3D node and rename it to Enemy.


2. Add a model to the enemy for visual representation. Navigate to the Models folder, find the
saw model, and add it as a child of the Enemy node. Rename this child node to Model.
3. Set the position of the saw model to (0, 0, 0) to center it on the enemy.

Adding a Collider

Next, we need to add a collider to the enemy so that it can detect when the player comes into
contact with it.

1. Right-click on the Enemy node and add a child node of type CollisionShape3D.
2. Set the shape of the CollisionShape3D to BoxShape3D.
3. Adjust the bounds of the box shape to roughly match the size of the saw model. You can hold
down the Alt key to uniformly size the collider.

Creating the Enemy Script

Now, we will create a script to manage the enemy’s movement, spinning, and collision detection.
With the Enemy node selected, create a new script and save it as [Link] in the Scripts folder.

Let’s start by defining the variables we’ll need for our enemy script.

The move_speed variable is a float that determines how fast our enemy moves.
The move_direction variable is a Vector3 that defines the direction in which our enemy
moves. This vector will also determine the distance our enemy travels. For example, if we
want our enemy to move 2 units down, we would set the y-component of the vector to -2.
The spin_speed variable is another float that determines how fast our enemy spins,
measured in degrees per second.

extends Area3D

@export var move_speed : float = 2.0


@export var move_direction : Vector3
@export var spin_speed : float = 900.0

Next, we’ll define three more variables using the @onready keyword.

The start_pos variable will store the starting position of our enemy, which we’ll set to its
current global position.
The target_pos variable will store the position our enemy is currently moving towards. At the
start of the game, this will be set to the start_pos plus the move_direction. This means our
enemy will start by moving towards a position that is move_direction units away from its
starting position.
Finally, the model variable will store a reference to our enemy’s model node.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Enemy - Part 1

@onready var start_pos : Vector3 = global_position


@onready var target_pos : Vector3 = start_pos + move_direction
@onready var model = $Model

Connecting the Collision Signal

To detect when the player enters the enemy’s collider, we need to connect the body_entered signal
to our script.

1. Select the Enemy node.


2. In the inspector, go to the Node tab and find the body_entered signal.
3. Double-click on the body_entered signal, select the Enemy node, and click Connect.

Setting Up the Player Group

To ensure that only the player triggers the damage, we will assign the player to a specific group.

1. Select the player’s root node in the player scene.


2. In the inspector, go to the Node tab and click on Groups.
3. Add a new group and name it Player.

Checking for Player Collision

In the _on_body_entered function, we will check if the body that entered the collider is the player. If
it’s not the player, we’ll exit the function. If it is, for now we’ll just print to the console (we’ll set up
damage in a future lesson).

func _on_body_entered(body):
if not body.is_in_group("Player"):
return

print("Take damage")

Testing the Setup

Finally, let’s test our setup to ensure that the enemy detects the player and prints “Take damage”
when the player enters the enemy’s collider.

1. Move the enemy to a suitable position in the 3D mode.


2. Press play and observe the output in the bottom left corner of the screen.
3. When the player enters the enemy, the message “Take damage” should appear.

In the next lesson, we will work on moving the enemy between two points and spinning the model
inside. Stay tuned!

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Enemy - Part 2

In this lesson, we will focus on implementing the movement and rotation of the enemy in our game
using the Godot engine. By the end of this lesson, you will have an enemy that moves back and forth
between two points and rotates over time. Let’s get started!

Setting Up Enemy Movement

To begin, we need to make our enemy move towards a target position every frame. We’ll use the
_process function to achieve this. Here’s how you can set up the basic movement:

1. Open your enemy script.


2. Inside the _process function, get the enemy’s current global position.
3. Use the move_toward function to move the enemy towards the target position.

Here is the initial code to move the enemy:

func _process (delta):


global_position = global_position.move_toward(target_pos, move_speed * delta)

The movement speed is controlled by multiplying move_speed by delta. The delta parameter
ensures that the movement is frame-rate independent, making the enemy move a small distance
each frame.

move_speed * delta

Switching Target Positions

To make the enemy move back and forth, we need to switch the target position when the enemy
reaches it. We’ll use a condition to check if the enemy has reached the target position and then
switch it.

1. Check if the enemy’s global position is equal to the start position.


2. If true, set the target position to the start position plus the move direction.
3. If the enemy’s global position is equal to the start position plus the move direction, set the
target position back to the start position.

Here is the code to switch the target positions:

if global_position == start_pos:
target_pos = start_pos + move_direction
elif global_position == start_pos + move_direction:
target_pos = start_pos

Rotating the Enemy

Next, we’ll make the enemy rotate over time. We’ll rotate the enemy’s model along its Z-axis. Here’s
how you can do it:

1. Get the enemy’s model.


2. Increment the rotation along the Z-axis by the spin speed multiplied by delta.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Enemy - Part 2

Here is the code to rotate the enemy:

[Link].z += deg_to_rad(spin_speed) * delta

Converting Spin Speed to Radians

Godot uses radians for rotation behind the scenes, even though the inspector shows degrees. To
convert the spin speed from degrees to radians, we use the deg_to_rad function.

deg_to_rad(spin_speed)

Saving and Positioning the Enemy

After implementing the movement and rotation, save the enemy as a scene. Then, position the
enemy in your level. You can duplicate and move the enemy to create multiple instances.

Drag the enemy into your scenes folder and save it.
Position the enemy in your level.
Duplicate and move the enemy to create multiple instances.

By following these steps, you will have an enemy that moves back and forth and rotates over time.
This adds dynamic behavior to your game and makes the enemy more engaging. In the next lesson,
we will focus on making the enemy deal damage to the player.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Damage

In this lesson, we will implement a damage system for our player character. This system will allow
enemies to deal damage to the player, reducing their health points. When the player’s health
reaches zero, the game will restart the level. Let’s break down the steps to achieve this:

Setting Up Player Health

First, we need to add a health variable to our player controller script. This variable will keep track of
the player’s current health points.

Open the player_controller.gd script.


Add an exported variable for health at the top of the script:

extends CharacterBody3D

@export var health : int = 3

The @export keyword allows us to modify the health value directly in the Godot editor if needed.

Creating the Take Damage Function

Next, we need a function that will handle the logic for taking damage. This function will subtract the
damage amount from the player’s health and check if the health has reached zero.

Add the take_damage function to the player_controller.gd script:

func take_damage(amount : int):


health -= amount
if health <= 0:
_game_over()

This function takes an amount parameter, which is the amount of damage to be dealt to the player.
It subtracts this amount from the player’s health and checks if the health is less than or equal to
zero. If so, it calls the _game_over function.

Handling Game Over

The _game_over function will handle the logic for restarting the level when the player’s health
reaches zero.

Add the _game_over function to the player_controller.gd script:

func _game_over():
get_tree().change_scene_to_file("res://Scenes/[Link]")

This function uses the get_tree().change_scene_to_file method to reload the current scene,
effectively restarting the level.

Calling Take Damage from the Enemy Script

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Damage

Now, we need to modify the enemy script to call the take_damage function whenever the enemy hits
the player.

Open the [Link] script.


Modify the _on_body_entered function to call take_damage on the player:

func _on_body_entered(body):
if not body.is_in_group("Player"):
return

body.take_damage(1)

This function checks if the body that entered the enemy’s collision area is the player. If so, it calls
the take_damage function on the player, dealing 1 damage.

Handling Falling Off the Level

Finally, we need to handle the scenario where the player falls off the level. We will add a check in the
player controller script to call the _game_over function if the player’s Y position falls below a certain
threshold.

Add the _process function to the player_controller.gd script:

func _process(delta):
if global_position.y < -5:
_game_over()

This function checks every frame if the player’s Y position is below -5. If so, it calls the _game_over
function to restart the level.

Testing the Implementation

With these changes, our damage system should now be fully implemented. To test it:

1. Run the game and have the player get hit by enemies to ensure the health decreases and
the game restarts when health reaches zero.
2. Have the player fall off the level to ensure the game restarts when the player falls below the
threshold.

By following these steps, you have successfully implemented a damage system for your player
character in Godot. This system allows enemies to deal damage to the player, reduces the player’s
health, and restarts the level when the player’s health reaches zero or if the player falls off the level.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Coin - Part 1

Welcome back! In this lesson, we will focus on creating and implementing coins in our game. These
coins will serve as the foundation of our scoring system. By the end of this lesson, you will have
coins that the player can collect, which will increase their score and disappear upon collection.

Creating the Coin

Let’s begin by creating our coin. The process is similar to how we created our enemy, using an
Area3D node.

1. Create an Area3D node and rename it to Coin.


2. Move the Coin node up slightly to position it out of the way.
3. Add a 3D model for the coin:
Navigate to the Models folder, then to Platformer.
Find the CoinGold model and drag it into the scene.
Make the CoinGold model a child of the Area3D node.
Rename the model node to Model for clarity.
Set the position of the Model node to center it on the Coin node.

Adding a Collision Shape

To ensure the coin functions properly, we need to add a collision shape:

1. Right-click the Coin node and add a CollisionShape3D child node.


2. Create a new SphereShape3D resource and resize it to fit the coin model.

Positioning the Coin

Position the coin in the scene where you want it to appear. This will help us test the coin’s
functionality later.

Creating the Coin Script

Next, we will create a script to handle the coin’s behavior, including detecting when the player
collects it and increasing the player’s score.

1. Create a new script named [Link] and attach it to the Coin node.
2. With the Coin node still selected, go to the Signal tab and add an _on_body_entered signal –
which we will use to detect the player.
3. In the script, the _on_body_entered function checks if the body entering the coin’s area is in
the “Player” group. If it is, the coin will be destroyed using the queue_free function.

extends Area3D

func _on_body_entered(body):
if not body.is_in_group("Player"):
return

# Increase score (placeholder for now)


queue_free()

In the future, we will also increase our score – but for now we simply want to ensure the coin is
deleted.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Coin - Part 1

Making the Coin Rotate

To make the coin more visually appealing, we will add rotation and bobbing motion. Let’s start with
rotation.

1. Add an export variable for the rotation speed:

@export var rotate_speed : float = 180.0

2. Create the _process function to handle the rotation:

func _process(delta):
# Rotate the coin
rotation.y += deg_to_rad(rotate_speed) * delta

The deg_to_rad function converts the rotation speed from degrees to radians, ensuring the coin
rotates at the correct speed.

Thank you for following along! In the next lesson, we will continue building our coin by adding a
bobbing up and down motion to it. Stay tuned!

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Coin - Part 2

Welcome back! In this lesson, we will complete our coin implementation by adding an up-and-down
bobbing motion. This will make our coin more visually appealing and dynamic. Let’s dive into the
steps required to achieve this effect.

Setting Up Variables

First, we need to define a few variables in our coin script. These variables will control the height and
speed of the bobbing motion, as well as the starting Y position of the coin.

bob_height: This export variable defines how high the coin will bob up and down.
bob_speed: This export variable controls the speed of the bobbing motion.
start_y_pos: This onready variable stores the initial Y position of the coin.

Here is how you can define these variables in your script:

extends Area3D

@export var bob_height : float = 0.2


@export var bob_speed : float = 5.0
@onready var start_y_pos : float = global_position.y

Implementing the Bobbing Motion

To create the bobbing motion, we will use a sine wave. A sine wave oscillates between -1 and 1,
which we can use to move the coin up and down. We will sample the sine wave every frame to get
the current position of the coin.

Here are the steps to implement the bobbing motion:

1. Create a variable called time that increases every second. This will be used to sample the
sine wave.
2. Calculate the Y position offset using the sine function and the time variable.
3. Adjust the Y position of the coin based on the calculated offset.

Let’s implement this in the _process function:

func _process(delta):
# bob up and down
var time = Time.get_unix_time_from_system()
var y_pos = sin(time)
global_position.y = start_y_pos + y_pos

Adjusting the Bobbing Motion

After implementing the initial bobbing motion, you might notice that the coin goes below its starting
position. To fix this, we need to adjust the range of the sine wave from -1 to 1 to 0 to 1. This ensures
that the coin never goes below its starting position.

Update the y_pos calculation as follows:

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Coin - Part 2

var y_pos = (1 + sin(time)) / 2

Controlling the Bobbing Speed and Height

To control the speed and height of the bobbing motion, we will use the bob_speed and bob_height
variables. Multiply the time variable by bob_speed to control the speed, and multiply the resulting
Y position offset by bob_height to control the height.

Here is the final implementation:

func _process(delta):
# bob up and down
var time = Time.get_unix_time_from_system()
var y_pos = (1 + sin(time * bob_speed)) / 2 * bob_height
global_position.y = start_y_pos + y_pos

Saving and Placing the Coin

Once the bobbing motion is implemented, save the coin as a scene. You can then place multiple
coins around your level by copying and pasting the coin node.

To keep your scene organized, create a new node of type Node and rename it to Coins. Select all
your coin nodes and drag them into the Coins node. This will help you manage your coins more
easily.

Repeat the process for other nodes, such as enemies, to keep your scene hierarchy tidy.

Congratulations! You have now completed the implementation of the coin with a bobbing motion. In
the next lesson, we will continue building our game by adding more features and functionality.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Scoring

Welcome back! In this lesson, we will implement a scoring system for our game. Unlike traditional
scoring systems that reset when the player moves to a new level, our scoring system will persist
across levels. This means that the score the player achieves in one level will carry over to the next.
To accomplish this, we will use a feature in Godot called autoloads or singletons.

Understanding Autoloads/Singletons

Autoloads, also known as singletons, are scripts that run independently of the scene and node
structure. They can be accessed from anywhere in the project at any time, and their values and
functions remain constant as long as the game is running. This makes them perfect for storing
persistent data like a player’s score.

Creating an Autoload Script

To create an autoload script, follow these steps:

1. Go to Project -> Project Settings.


2. Navigate to the Globals tab.
3. In the Node Name field, enter PlayerStats.
4. Click Add.
5. Choose a location for your script (e.g., the Scripts folder) and name it [Link].
6. Click Create.

Now, open the [Link] script and add the following code:

extends Node

var score : int = 0

Accessing the Autoload Script

Next, we need to modify the [Link] script to access and update the score in the
PlayerStats singleton.

Open the [Link] script and add the following function:

func increase_score(amount: int):


[Link] += amount
print([Link])

Updating the Coin Script

Finally, we need to update the [Link] script to use the new increase_score function. Open the
[Link] script and modify the _on_body_entered function as follows:

func _on_body_entered(body):
if not body.is_in_group("Player"):
return

body.increase_score(1)
queue_free()

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Scoring

Testing the Scoring System

Now, when you play the game and collect coins, you should see the score printed in the output. The
score will persist even if the player restarts the level. This is because the score is stored in the
PlayerStats singleton, which runs independently of any scenes or nodes.

Resetting the Score on Game Over

To ensure the score resets when the game is over, we need to modify the _game_over function in
the [Link] script:

func _game_over():
[Link] = 0
get_tree().change_scene_to_file("res://Scenes/[Link]")

That’s it! You have now implemented a persistent scoring system using autoloads/singletons in
Godot. In the next lesson, we will explore how to display the score on the user interface. See you
then!

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
UI - Part 1

Welcome to this beginner-friendly tutorial at Zenva on creating a player User Interface (UI) in Godot.
In this lesson, we will focus on adding essential UI elements to help keep track of the player’s health
and score. By the end of this tutorial, you will have a clear understanding of how to create and
manage UI elements in Godot.

Setting Up the CanvasLayer

To begin, we need to create a CanvasLayer. This node is crucial for UI elements as it ensures that
they remain fixed on the screen, independent of the camera’s movement. Here’s how to do it:

1. Navigate to your PlayerScene.


2. Create a new node called CanvasLayer.

Adding Health Representations

Next, we will add hearts to represent the player’s health. These hearts will be displayed at the top
left corner of the screen.

1. Switch to 2D mode for easier UI management.


2. Right-click on the CanvasLayer and add a child node called TextureRect. Rename it to
Heart.
3. In the inspector, set the Texture property to your heart sprite (e.g., HUD_heart_full).

Using Horizontal Box Container

To manage multiple hearts efficiently, we will use a Horizontal Box Container. This node
automatically arranges its child nodes horizontally.

1. Delete all but one heart node.


2. Create a new node called HBoxContainer and rename it to HealthContainer.
3. Drag the remaining heart node into the HealthContainer.
4. Duplicate the heart node (Ctrl+D) to create multiple hearts. The HBoxContainer will
automatically arrange them horizontally.

Adding Score Text

Below the hearts, we will add a text label to display the player’s score.

1. Create a new Label node outside the HealthContainer to avoid visual bugs.
2. Rename the node to ScoreText.
3. In the inspector, set the text to something like “Score: 500”.
4. Adjust the font size and add a shadow for better visibility:
Create a new Label Settings resource.
Increase the font size (e.g., 38).
Add a shadow with a size of about 8 pixels and adjust the color for better contrast.

Preparing for Scripting

The final step is to prepare for scripting the UI to make it interactive. We will create a script that will
handle updating the hearts and score text based on the player’s actions.

1. Select the CanvasLayer.


2. Attach a new script and name it PlayerUI.
3. Save the script in your scripts folder.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
UI - Part 1

In the next lesson, we will dive into scripting the UI to make it dynamic and responsive to the
player’s actions. Stay tuned for more!

Thank you for following along. See you in the next lesson!

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
UI - Part 2

Welcome back! In this lesson, we will begin scripting our User Interface (UI) in Godot. We’ll explore
two methods to update our UI elements: checking and updating every frame versus updating only
when necessary. The latter approach is more efficient and aligns with best practices in programming.

Updating UI Elements

There are two primary ways to update UI elements based on player actions:

1. Frame-by-Frame Update: Check and update UI elements every frame. This method is
feasible for a small number of UI elements but can impact performance as more elements
are added.
2. Event-Driven Update: Update UI elements only when specific events occur, such as
changes in the player’s health or score. This method is more efficient and follows best
practices by reducing dependencies between scripts.

Using Signals for Event-Driven Updates

To implement event-driven updates, we will use signals in Godot. Signals are events that can be
emitted and listened to by other parts of the game. This approach minimizes dependencies and
improves performance.

Defining Custom Signals

We will define custom signals in our player controller script to notify the UI when the player’s health
or score changes. Here’s how to define these signals:

signal OnTakeDamage(hp: int)


signal OnUpdateScore(score: int)

Emitting Signals

Next, we need to emit these signals at the appropriate times. For example, when the player takes
damage or collects a coin, we will emit the respective signals.

func take_damage(amount: int):


health -= amount
[Link](health)

if health <= 0:
_game_over()

func increase_score(amount: int):


[Link] += amount
[Link]([Link])

Listening to Signals

In our player UI script, we will create functions that will be called when these signals are emitted.
These functions will update the UI elements accordingly (though for now we’ll leave them blank).

func _update_hearts(health: int):


pass

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
UI - Part 2

func _update_score_text(score: int):


pass

Connecting Signals to Functions

To connect the signals to the functions, we will use the connect method in the _ready function of our
player UI script.

func _ready():
var player = get_parent()

[Link](_update_hearts)
[Link](_update_score_text)

Now whenever these signals are emitted from the player, our UI update functions will trigger!

Initializing Variables

With our signals connected, we can now work on our update functions. We first need to initialize
some variables to reference our UI elements. These variables will be used to update the UI elements
when the signals are emitted. We need a reference to our health container, an array of all our hearts,
and a reference to our score_text label.

@onready var health_container = $HealthContainer


var hearts: Array = []

@onready var score_text: Label = $ScoreText

Updating the Score Text

Let’s start by updating the score text. This is a straightforward process where we update the text
property of the score label whenever the score changes.

func _update_score_text(score: int):


score_text.text = "Score: " + str(score)

To ensure we overwrite our default text, we also want to make sure to call this function in this
script’s Ready function:

func _ready ():


var player = get_parent()

[Link](_update_hearts)
[Link](_update_score_text)

_update_score_text([Link])

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
UI - Part 2

Conclusion

In this lesson, we covered how to use signals to update UI elements efficiently. We defined custom
signals, emitted them at the appropriate times, and connected them to functions that update the UI.
This approach ensures that our UI updates only when necessary, improving performance and
adhering to best practices in programming.

In the next lesson, we will continue working on our UI by updating the hearts to reflect the player’s
health.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
UI - Part 3

In this lesson, we will focus on setting up the user interface (UI) elements for displaying the player’s
health in our game. Specifically, we will be working with heart icons that represent the player’s
health points. By the end of this lesson, you will have a clear understanding of how to manage and
update these UI elements based on the player’s health status.

Accessing the Heart Nodes

To begin, we need to access the heart nodes that are children of the HealthContainer node. These
heart nodes will be stored in an array called hearts. This array will allow us to easily manage and
update the visibility of each heart icon based on the player’s current health.

In the _ready function, we will initialize the hearts array by retrieving all the child nodes of
HealthContainer. Here is the code snippet to achieve this:

hearts = health_container.get_children()

Updating the Heart Icons

Next, we need to create a function called _update_hearts that will loop through each heart icon and
set its visibility based on the player’s health. This function will be called whenever the player’s
health changes.

The _update_hearts function uses a for loop to iterate through the hearts array. For each iteration, it
checks if the current index is less than the player’s health. If it is, the heart icon will be visible;
otherwise, it will be hidden.

Here is the code snippet for the _update_hearts function:

func _update_hearts(health: int):


for i in len(hearts):
hearts[i].visible = i < health

Connecting the Signals

Like the score text, to ensure that the heart icons are updated at the start of the game, we need to
call the _update_hearts function in the _ready function.

func _ready():
...
_update_hearts([Link])

Testing the Implementation

Finally, we will test our implementation to ensure that the heart icons are correctly displayed based
on the player’s health. When the game starts, the player should have a certain number of hearts
visible. As the player takes damage, the number of visible hearts should decrease accordingly.

To test this, you can run the game and observe the heart icons in the UI. Take damage to see the
hearts disappear one by one until the player’s health reaches zero.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
UI - Part 3

Summary

In this lesson, we have learned how to set up and manage UI elements for displaying the player’s
health in our game. We accessed the heart nodes, created a function to update their visibility based
on the player’s health, and connected the necessary signals to ensure the UI is updated in real-time.
This knowledge will be valuable as you continue to develop and refine your game’s user interface.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
End Flag - Part 1

Welcome to this lesson! For the next step in our game, we will be creating an end flag for our game.
The end flag will be responsible for transitioning the player to the next level upon contact. This
process will be familiar to you, as we have previously created similar objects: the enemy and the
coin. Both of these objects share common characteristics with our end flag, which we will explore in
this article.

Similarities with Previous Objects

Before we dive into creating the end flag, let’s understand how it is similar to the enemy and coin
objects:

All three objects are of type Area2D.


Each has a model as a child and a collision shape as a child.
All three objects listen to the onBodyEntered signal, which is triggered when their Area2D
enters another body.

Given these similarities, it’s time you tackle a challenge! Try to set up the foundations of the End
Flag on your own. In the next lesson, we’ll go over the steps – but trying it yourself first will help
cement these skills for future projects!

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
End Flag - Part 2

In this lesson, we will create an EndFlag that the player can interact with to transition to a new
scene. This is a crucial element in games where the player needs to progress through different
levels. We will use Godot’s Area3D node and attach a script to handle the scene transition. Let’s
break down the steps:

Creating the EndFlag Node

First, we need to create a new node of type Area3D in our scene. This node will represent the
EndFlag that the player needs to reach.

1. Create a new Area3D node in your scene.


2. Rename the Area3D node to EndFlag.
3. Drag your 3D flag model into the scene and set it as a child of the EndFlag node.
4. Rename the model node to Model.
5. Set the position of the Model node to (0, 0, 0) to center it.

Adding a Collision Shape

Next, we need to add a collision shape to the EndFlag so that it can detect when the player enters its
area.

1. Attach a CollisionShape3D node to the EndFlag node.


2. Select a box shape for the collision shape. The shape does not need to be exact; an
approximation will suffice.

Attaching a Script to the EndFlag

We will now attach a script to the EndFlag to handle the scene transition when the player enters its
area.

1. Create a new script and attach it to the EndFlag node.


2. Name the script end_flag.gd and save it in the Scripts folder.

Connecting the Body Entered Signal

We need to connect the body_entered signal of the EndFlag node to the _on_body_entered function
in our script.

1. Select the EndFlag node.


2. Go to the Node panel and select the EndFlag node.
3. Go to the Signals tab and find the body_entered signal.
4. Double-click on the body_entered signal and connect it to the _on_body_entered function in
the script.

Writing the EndFlag Script

With all this done, we can now write the script – which will be quite simple. First, we set up a
PackedScene variable which will allow us to dynamically set the next level scene in the Inspector.

In our _on_body_entered function, we’ll check if the player entered the collision area. If so, we’ll call
our _load_new_scene function. Meanwhile, in the _load_new_scene function, we simply load the
scene set in our variable.

extends Area3D

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
End Flag - Part 2

@export var scene_to_load : PackedScene

func _on_body_entered(body):
if not body.is_in_group("Player"):
return

_load_new_scene()

func _load_new_scene ():


get_tree().change_scene_to_packed(scene_to_load)

Saving the EndFlag as a Scene

Finally, we will save the EndFlag as a scene so that it can be reused in different levels.

1. Save the EndFlag node as a scene named end_flag.tscn in the Scenes folder.

Testing the EndFlag

To test the EndFlag, we will temporarily position it next to the player and assign a scene to load
when the player reaches it.

1. Position the EndFlag next to the player for testing purposes.


2. Open the EndFlag scene and select the EndFlag node.
3. In the Inspector, you will see the scene_to_load property. Drag and drop a scene (e.g., the
player scene) into this property. Note that this has to be different from Level 1, as otherwise
Godot will prevent it to avoid errors.
4. Press play and test the EndFlag by running into it with the player.

By following these steps, you have created an EndFlag that the player can interact with to transition
to a new scene. This is a fundamental element in level-based games and will help you create a more
engaging and structured gameplay experience.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Creating a New Level

In this lesson, we will guide you through the process of setting up a second level in your game. By
the end of this tutorial, you will have a new level with a distinct visual style and functional scene
transitions. Let’s get started!

Creating a New Scene

To begin, we need to create a new scene for our second level:

1. Go to the Scene menu and select New Scene.


2. Create a new 3D scene.
3. Rename the root node to Main.
4. Save the scene in the Scenes folder as level_2.tscn.

Duplicating Assets from Level 1

To expedite the setup process, we will duplicate the assets from Level 1:

1. Open level_1.tscn.
2. Select all the child nodes of the Main node.
3. Copy the selected nodes.
4. Go back to level_2.tscn and paste the copied nodes.

Modifying the Visual Style

To give Level 2 a unique look, we will modify the environment settings:

1. Select the WorldEnvironment node.


2. Change the Fog/Light Color to a yellow-green-orange hue for a desert vibe.
3. Update the Ambient Color to match the new desert theme.

Customizing the Level Layout

Next, customize the layout of your level by:

Moving and adjusting platforms.


Adding or removing enemies and coins.
Changing the overall layout to create a new challenge.

Connecting Levels

To ensure smooth transitions between levels, we need to connect the end flag in Level 1 to Level 2:

1. Open level_1.tscn.
2. Select the EndFlag node.
3. In the Scene to Load property, drag in level_2.tscn.

Fixing Scene Transition Errors

You might encounter errors when transitioning between scenes. This is due to attempting to unload
and load scenes in the same frame. To fix this, we will use the call_deferred method.

Update the end_flag.gd script as follows:

extends Area3D

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Creating a New Level

@export var scene_to_load : PackedScene

func _on_body_entered(body):
if not body.is_in_group("Player"):
return

call_deferred("_load_new_scene")

func _load_new_scene():
get_tree().change_scene_to_packed(scene_to_load)

This modification ensures that the scene transition happens at the end of the frame, preventing
errors caused by the physics.

Testing the Level Transition

Finally, test the transition from Level 1 to Level 2:

1. Play the game and complete Level 1.


2. Ensure that upon reaching the end flag, the game transitions to Level 2 without errors.

Congratulations! You have successfully set up a second level in your game with a unique visual style
and functional scene transitions. In the next lessons, we will continue to build upon this foundation to
create an engaging and immersive gaming experience.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Menu

In this lesson, we will set up the menu scene for our game. The menu scene is the first scene that
players will see when they launch the game. It will include a background image, a title, and two
buttons: one for starting the game and another for quitting the game. Let’s go through the steps to
create this menu scene.

Creating the Menu Scene

To begin, we need to create a new scene. This scene will be of type User Interface, which allows us
to create UI elements using control nodes.

1. Create a new scene and select User Interface.


2. Rename the root node to Menu.
3. Save the scene to the scenes folder as [Link].

Adding a Background Image

The first element we need is a background image. We will use a TextureRect node for this purpose.

1. Add a TextureRect node as a child of the Menu node and rename it to Background.
2. In the FileSystem dock, navigate to the sprites folder and find the
Menu_Background.png file.
3. Drag the Menu_Background.png file onto the Texture property of the Background node.

To ensure the background image resizes with the screen, we need to set the anchor presets:

1. Select the Background node.


2. In the inspector, scroll down to the Layout section.
3. Change the Layout Mode to Anchors.
4. Set the Anchor Preset to Full Rect.

Adding the Title

Next, we will add a title to the menu. The title will be a Label node.

1. Add a Label node as a child of the Menu node and rename it to Title.
2. Set the Text property of the Title node to “3D Platformer Game”.
3. Adjust the size of the label and move it to the center of the screen.
4. Set the Anchor Preset to Center to ensure it stays centered when the screen resizes.
5. Change the Horizontal Alignment and Vertical Alignment to Center.
6. Increase the Font Size to 38 and adjust the color as desired.

Adding the Play and Quit Buttons

We will now add the play and quit buttons to the menu.

1. Add a Button node as a child of the Menu node and rename it to PlayButton.
2. Set the Text property of the PlayButton node to “Play”.
3. Adjust the size of the button and move it to the center of the screen.
4. Set the Anchor Preset to Center.
5. Duplicate the PlayButton node, rename the duplicate to QuitButton, and set its Text
property to “Quit”.
6. Move the QuitButton below the PlayButton.

Connecting the Buttons to Scripts

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Menu

To make the buttons functional, we need to connect them to a script. We will create a new script for
the Menu node.

1. Select the Menu node.


2. Create a new script and name it [Link]. Save it to the scripts folder.
3. Connect the pressed signal of the PlayButton to the [Link] script.
4. Connect the pressed signal of the QuitButton to the [Link] script.

In the [Link] script, we will add the following code to handle the button presses.

extends Control

func _on_play_button_pressed():
[Link] = 0
get_tree().change_scene_to_file("res://Scenes/level_1.tscn")

func _on_quit_button_pressed():
get_tree().quit()

As established, the play button will reset the score and load us into the first level. The quit button
will quit out of the game.

Handling Game Over and Level Completion

To ensure the game returns to the menu upon game over or level completion, we need to make a
few adjustments:

1. In the player_controller.gd script, modify the _game_over function to load the menu
scene:

func _game_over ():


[Link] = 0
get_tree().change_scene_to_file("res://Scenes/[Link]")

2. In Level 2 (or whatever your last level is), select the EndFlag node and set the menu scene
as the scene to load.

With these steps, we have created a functional menu scene with play and quit buttons. The game
will now loop from the menu to the levels and back to the menu, providing a complete game flow.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Audio

In this lesson, we will set up audio for our game using Godot. Audio is a crucial element in games as
it enhances the player’s experience by providing feedback and immersion. We will focus on playing
sound effects when the player collects a coin and when the player takes damage.

Setting Up the AudioStreamPlayer Node

To begin, we need to create a node that can play sound effects. Follow these steps:

1. Open your player scene.


2. Add a new node of type AudioStreamPlayer. This node will be responsible for playing our
sound effects.

Configuring the Player Controller Script

Next, we need to modify the player controller script to handle audio playback. Open the
player_controller.gd script and make the following changes:

Adding AudioStreamPlayer Reference

First, we need to create a reference to the AudioStreamPlayer node:

@onready var audio : AudioStreamPlayer = $AudioStreamPlayer

Preloading Audio Clips

We will preload the audio clips for the coin sound effect and the take damage sound effect. This
ensures that the sound effects are loaded into memory when the node is initialized, reducing any
delay when the sounds are played:

var coin_sfx : AudioStream = preload("res://Audio/[Link]")


var take_damage_sfx : AudioStream = preload("res://Audio/take_damage.wav")

Creating the PlaySound Function

We will create a function called _play_sound that takes an AudioStream as a parameter and plays it:

func _play_sound(sound : AudioStream):


[Link] = sound
[Link]()

Integrating Sound Effects

Finally, we will integrate the sound effects into the existing functions:

In the increase_score function, add the following line to play the coin sound effect:

_play_sound(coin_sfx)

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Audio

In the take_damage function, add the following line to play the take damage sound effect:

_play_sound(take_damage_sfx)

Testing the Audio

After making these changes, press play to test the game. You should hear the coin sound effect
when collecting a coin and the take damage sound effect when taking damage.

By following these steps, you have successfully integrated audio into your game, enhancing the
player’s experience with sound effects. In the next lessons, we will continue to build on this
foundation to create a more immersive and engaging game.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Camera Shake

In this lesson, we will implement a camera shake effect in Godot. This effect will trigger when the
player takes damage, enhancing the visual feedback of the game. We will achieve this by modifying
the camera’s offset properties to create a shaking effect. Let’s break down the steps to accomplish
this.

Understanding Camera Offset

First, let’s understand the camera offset properties:

H Offset: Moves the camera viewport horizontally.


V Offset: Moves the camera viewport vertically.

These offsets allow us to create a shaking effect by rapidly changing their values.

Setting Up the Camera Shake Script

To start, create a new script on the Camera3D node and save it as camera_shake.gd in the scripts
folder. This script will manage the intensity of the shake and apply the offsets to the camera.

Creating the Intensity Variable

Inside the script, define an intensity variable that will control the magnitude of the shake:

extends Camera3D

var intensity : float = 0

Connecting the Damage Signal

Next, we need to connect the camera shake to the player’s damage signal. In the _ready function,
connect the _damage_shake function to the player’s OnTakeDamage signal:

func _ready():
get_parent().[Link](_damage_shake)

Implementing the Damage Shake Function

The _damage_shake function will set the intensity of the shake when the player takes damage:

func _damage_shake(health: int):


intensity = 0.1

Reducing Intensity Over Time

In the _process function, we will gradually reduce the intensity of the shake over time using the lerp
function. We will also apply a random offset to the camera’s position:

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Camera Shake

func _process(delta):
if intensity > 0:
intensity = lerp(intensity, 0.0, delta * 10)
var offset : Vector2 = _get_random_offset()
h_offset = offset.x
v_offset = offset.y

Generating Random Offsets

The _get_random_offset function will generate random offsets for the camera based on the current
intensity:

func _get_random_offset() -> Vector2:


var x = randf_range(-intensity, intensity)
var y = randf_range(-intensity, intensity)
return Vector2(x, y)

Complete Camera Shake Script

Here is the complete camera_shake.gd script with all the functions implemented:

extends Camera3D

var intensity : float = 0

func _ready():
get_parent().[Link](_damage_shake)

func _damage_shake(health: int):


intensity = 0.1

func _process(delta):
if intensity > 0:
intensity = lerp(intensity, 0.0, delta * 10)
var offset : Vector2 = _get_random_offset()
h_offset = offset.x
v_offset = offset.y

func _get_random_offset() -> Vector2:


var x = randf_range(-intensity, intensity)
var y = randf_range(-intensity, intensity)
return Vector2(x, y)

Fixing the Game Over Error

Finally, we need to address an error that occurs when trying to change the scene during the game
over sequence. This error happens because the game is trying to unload an object while it is still in

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Camera Shake

its collision detection phase.

To fix this, we will use the call_deferred function to ensure that the game over function is called at
the end of the frame. In the player_controller.gd script, modify the take_damage function as follows:

func take_damage(amount: int):


health -= amount
[Link](health)
_play_sound(take_damage_sfx)

if health <= 0:
call_deferred("_game_over")

With these steps, you have successfully implemented a camera shake effect in Godot. This effect will
provide visual feedback to the player whenever they take damage, enhancing the overall gameplay
experience.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Level Design

Welcome to this lesson on level design techniques! Whether you’re new to game development or
looking to enhance your skills, understanding effective level design is crucial. This article will guide
you through various techniques to help you create engaging and intuitive levels for your games.
Let’s dive in!

Telegraphing the Objective

One of the fundamental aspects of level design is clearly communicating the objective to the player.
This can be achieved by ensuring that the end goal is visible from the start. By seeing the end goal,
players can plan their approach and understand what they need to do to complete the level.

Make the end goal visible from the beginning.


Allow players to plan their path to the objective.

Guiding Player Attention

In levels with multiple pathways, using collectibles like coins can guide the player’s attention. Coins
or other collectibles serve as breadcrumbs, leading players along a specific path. This technique is
commonly used in many games to direct player movement.

Use coins or collectibles to guide players along a path.


Players are naturally drawn to collecting items and achieving higher scores.

Visibility and Storytelling

Placing the end goal at a higher elevation improves visibility and can serve as a storytelling device.
This technique helps players see the objective from a distance and can enhance the narrative by
creating a sense of progression.

Place the end goal at the highest point for better visibility.
Use elevation to create a sense of progression in the story.

Providing Options and Risk vs. Reward

Giving players options adds depth to your levels. While it’s important to have a clear path to the
objective, providing multiple routes with varying difficulties and rewards enhances player
engagement.

Offer multiple paths to the end goal.


Introduce risk vs. reward scenarios to make levels more engaging.

1. Easier path with fewer rewards.


2. Harder path with more rewards or shorter completion time.

Theming and Level Identity

Theming plays a significant role in level design, contributing to the narrative and creating a unique
identity for each level. Even small changes in theming can make levels feel distinct and memorable.

Use theming to create unique level identities.


Align theming with the narrative and aesthetic of your game.

For example:

A sand-themed level could feature sandstone structures and pyramids.

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Level Design

A fantasy-themed level could have floating islands and magical elements.

Conclusion

Level design is a vast and complex field, but by applying these techniques, you can create engaging
and intuitive levels for your games. Remember, the best way to improve is to create, test, gather
feedback, and iterate on your designs.

Thank you for reading, and happy designing!

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Conclusion

Congratulations on completing your course on setting up a 3D platformer game using the Godot
engine! Throughout this project, we have created and integrated various elements to build a
functional and engaging game. Let’s recap the key components and concepts we’ve covered to
reinforce your learning.

Player Setup

We began by creating the player character, which is the core of our game. The player character can
move around and jump using various input methods such as:

Arrow keys
WASD keys
Spacebar
Customizable controller or mouse buttons

This flexibility was achieved using Godot’s input map system, which allowed us to assign different
keys or buttons for player movements.

Player Script and Mechanics

We then created a script utilizing the CharacterBody3D node to manage the player’s mechanics.
Here’s what we set up:

1. Gravity: Ensured the player is affected by gravity, allowing for realistic jumping and falling.
2. Movement: Implemented player movement based on input directions.
3. Jumping: Enabled the player to jump and control their character in the air.

Enemies and Damage System

Next, we introduced enemies to challenge the player. Our enemies featured:

Movement from one position to another over time.


A spinning saw enemy for varied gameplay.
Damage system that affects the player’s health.

When the player takes damage, we implemented:

Camera Shake: A visual effect to indicate impact.


Sound Effect: An auditory cue for damage taken.
UI Elements: Three hearts to represent the player’s remaining health.

Collectibles and UI

We also created collectible coins that provide rewards and update the UI score. Key features of the
coins include:

A sound effect (“ding”) when collected.


Disappearance upon collection.
Visual enhancements:
Bobbing up and down.
Rotating over time.

Level Transition

To create a full game loop, we set up an end flag that serves as a portal between levels. This allows

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Conclusion

us to connect:

1. Level 1
2. Level 2
3. The main menu

This structure enables players to progress through the game and restart it after completion.

About Zenva

Zenva is an online learning academy with over a million students. We offer a wide range of courses
suitable for both beginners and those looking to learn new skills. Our courses are versatile, allowing
you to learn in various ways:

Follow along with online video tutorials.


Read included lesson summaries.
Utilize included course files with the course instructor.

Thank you for following along with the course. We wish you the best of luck with your future Godot
games and hope to see you in more courses!

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])


Develop a Complete 3D Platformer in Godot
Full Source Code - Godot 3D Platformer

In this lesson, you can find the full source code for the project used within the course. Feel free to
use this lesson as needed – whether to help you debug your code, use it as a reference later, or
expand the project to practice your skills!

You can also download all project files from the Course Files tab via the project files or
downloadable PDF summary.

camera_shake.gd

Found in folder: /Scripts

This script extends the Camera3D class and adds a damage shake effect. When the parent node
takes damage, the `_damage_shake` function is called, setting the intensity of the shake effect. The
`_process` function then gradually reduces the intensity and applies a random offset to the camera’s
position, creating a shaking effect.

extends Camera3D

var intensity : float = 0

func _ready ():


get_parent().[Link](_damage_shake)

func _damage_shake (health : int):


intensity = 0.1

func _process (delta):


if intensity > 0:
intensity = lerp(intensity, 0.0, delta * 10)
var offset : Vector2 = _get_random_offset()
h_offset = offset.x
v_offset = offset.y

func _get_random_offset () -> Vector2:


var x = randf_range(-intensity, intensity)
var y = randf_range(-intensity, intensity)
return Vector2(x, y)

[Link]

Found in folder: /Scripts

This script rotates a coin object around its Y axis at a specified speed and makes it bob up and down
at a specified height and speed. The coin’s position is updated every frame to achieve this effect.
When another object in the “Player” group collides with this coin object, the player’s score is
increased by 1 and the coin is removed from the scene.

extends Area3D

@export var rotate_speed : float = 180.0

@export var bob_height : float = 0.2


@export var bob_speed : float = 5.0

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Full Source Code - Godot 3D Platformer

@onready var start_y_pos : float = global_position.y

func _process (delta):


# rotate
rotation.y += deg_to_rad(rotate_speed) * delta

# bob up and down


var time = Time.get_unix_time_from_system()
var y_pos = (1 + sin(time * bob_speed)) / 2 * bob_height

global_position.y = start_y_pos + y_pos

func _on_body_entered(body):
if not body.is_in_group("Player"):
return

body.increase_score(1)
queue_free()

end_flag.gd

Found in folder: /Scripts

This script for the End Flag extends the Area3D class and listens for a body to enter its area. When a
body enters and is part of the “Player” group, it triggers a scene change. The new scene is loaded
from a PackedScene resource assigned to the `scene_to_load` variable.

extends Area3D

@export var scene_to_load : PackedScene

func _on_body_entered(body):
if not body.is_in_group("Player"):
return

call_deferred("_load_new_scene")

func _load_new_scene ():


get_tree().change_scene_to_packed(scene_to_load)

[Link]

Found in folder: /Scripts

This script controls the movement and rotation of the enemy. It moves the enemy object back and
forth along a set direction at a specified speed, while also spinning it around its z-axis. When the
enemy collides with the player, it deals damage to the player.

extends Area3D

@export var move_speed : float = 2.0

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Full Source Code - Godot 3D Platformer

@export var move_direction : Vector3


@export var spin_speed : float = 900.0

@onready var start_pos : Vector3 = global_position


@onready var target_pos : Vector3 = start_pos + move_direction
@onready var model = $Model

func _process (delta):


[Link].z += deg_to_rad(spin_speed) * delta

global_position = global_position.move_toward(target_pos, move_speed * delta)

if global_position == start_pos:
target_pos = start_pos + move_direction
elif global_position == start_pos + move_direction:
target_pos = start_pos

func _on_body_entered (body):


if not body.is_in_group("Player"):
return

body.take_damage(1)

[Link]

Found in folder: /Scripts

This code handles the behavior of two buttons in the menu scene. When the play button is pressed,
it resets the player’s score to 0 and changes the scene to the first level. When the quit button is
pressed, it exits the game.

extends Control

func _on_play_button_pressed():
[Link] = 0
get_tree().change_scene_to_file("res://Scenes/level_1.tscn")

func _on_quit_button_pressed():
get_tree().quit()

player_controller.gd

Found in folder: /Scripts

This script controls the player character’s movement, health, and scoring. It applies gravity, allows
jumping and movement, and updates the player’s health and score based on external inputs. The
script also handles game over conditions and plays sound effects for taking damage and collecting
coins.

extends CharacterBody3D

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Full Source Code - Godot 3D Platformer

signal OnTakeDamage (hp : int)


signal OnUpdateScore (score : int)

@export var health : int = 3

@export var move_speed : float = 3.0


@export var jump_force : float = 8.0
@export var gravity : float = 20.0

@onready var camera : Camera3D = $Camera3D


@onready var audio : AudioStreamPlayer = $AudioStreamPlayer

var coin_sfx : AudioStream = preload("res://Audio/[Link]")


var take_damage_sfx : AudioStream = preload("res://Audio/take_damage.wav")

func _physics_process(delta):
# gravity
velocity.y -= gravity * delta

# jump
if Input.is_action_pressed("jump") and is_on_floor():
velocity.y = jump_force

# movement
var move_input : Vector2 = -Input.get_vector("move_right", "move_left", "move_back",
"move_forward")
var move_dir : Vector3 = Vector3(move_input.x, 0, move_input.y)

velocity.x = move_dir.x * move_speed


velocity.z = move_dir.z * move_speed

move_and_slide()

func _process (delta):


if global_position.y < -5:
_game_over()

func take_damage (amount : int):


health -= amount
[Link](health)
_play_sound(take_damage_sfx)

if health <= 0:
call_deferred("_game_over")

func _game_over ():


[Link] = 0
get_tree().change_scene_to_file("res://Scenes/[Link]")

func increase_score (amount : int):


[Link] += amount
[Link]([Link])
_play_sound(coin_sfx)

func _play_sound (sound : AudioStream):

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Full Source Code - Godot 3D Platformer

[Link] = sound
[Link]()

player_stats.gd

Found in folder: /Scripts

This singleton code declares a singleton variable named “score” with a data type of integer and
initializes it to 0. This variable can be used to store and manage a score value within the class and
maintain it across multiple scenes.

extends Node

var score : int = 0

player_ui.gd

Found in folder: /Scripts

This code manages the display of a player’s health and score. It initializes a container with hearts
representing the player’s health and a label for the score, and updates them when the player takes
damage or earns points. The hearts are shown or hidden based on the player’s current health, and
the score label is updated with the current score.

extends CanvasLayer

@onready var health_container = $HealthContainer


var hearts : Array = []

@onready var score_text : Label = $ScoreText

func _ready ():


hearts = health_container.get_children()

var player = get_parent()

[Link](_update_hearts)
[Link](_update_score_text)

_update_hearts([Link])
_update_score_text([Link])

func _update_hearts (health : int):


for i in len(hearts):
hearts[i].visible = i < health

func _update_score_text (score : int):


score_text.text = "Score: " + str(score)

© 2025 Zenva Pty Ltd. All rights reserved. [Link]


Develop a Complete 3D Platformer in Godot
Full Source Code - Godot 3D Platformer

player_visual.gd

Found in folder: /Scripts

This script rotates the player to face the direction of movement and smoothly transitions between
rotations. It also applies a subtle bobbing effect to the mesh when the player is moving on the floor,
creating a sense of movement. The rotation and bobbing effects are updated every frame based on
the player’s velocity and position.

extends MeshInstance3D

@export var rotate_rate : float = 20.0


var target_y_rot : float = 0

@onready var player : CharacterBody3D = get_parent()

func _process (delta):


_smooth_rotation(delta)
_move_bob(delta)

func _smooth_rotation (delta):


var vel = -[Link]

if vel.x != 0 or vel.z != 0:
target_y_rot = atan2(vel.x, vel.z)

rotation.y = lerp_angle(rotation.y, target_y_rot, rotate_rate * delta)

func _move_bob (delta):


var move_speed = [Link]()

if move_speed < 0.1 or not player.is_on_floor():


scale.y = 1
return

var time = Time.get_unix_time_from_system()


var y_scale = 1 + (sin(time * 30) * 0.08)
scale.y = y_scale

© 2025 Zenva Pty Ltd. All rights reserved. [Link]

Powered by TCPDF ([Link])

You might also like