Many gamers and budding developers might be surprised to learn that Godot, usually celebrated for its 2D capabilities, has been on the scene since 2007. Though it became public domain in 2014, Godot has quietly boasted 3D support from the get-go. Recently, it’s 3D support has become a game-changer, quite literally, as we’re witnessing an increasing number of 3D games made in Godot. And it’s not hard to see why — Godot offers indie developers such as me and you a user-friendly platform that’s not just easy on system resources, but also packs enough punch to bring our creative visions to life in three dimensions!
When I set out to create a 3D game tutorial series targeted at beginners, I initially wanted to make a 3D fishing game, where players complete QTEs to capture a certain number of fish per level before the timer runs out. Initially, when I started creating this game in Godot 4, I encountered many obstacles because Godot requires a lot of manual work for 3D creation. The camera, environment, player character — everything — has to be built from scratch, so it made things a lot more interesting when I encountered the many bugs that came from trial-and-error coding!
Figure 4: Help, I’ve fallen and I can’t get up!
It wasn’t until I finished making this fishing game — which turned out pretty cool — that I realized something important. This game was way too complex for beginners. The fishing mechanics and all the logic behind it were pretty advanced, and the world-building section was kind of overwhelming.
It just wouldn’t cut it for someone just starting with 3D development in Godot 4. So, I had this lightbulb moment and thought, “Why not make something new?” I decided to cook up a game that’s more about the basics — like animations, handling the camera, procedural world creation, and all that jazz. The key was to keep it simple and not too long. I wanted something that anyone could jump into without feeling lost, something fun and straight to the point. The answer was an Endless Runner game.
Figure 5: Preview of Dock & Roll, our 3D Endless Runner
The world of endless runners has captivated players for years, with popular games like Subway Surfers and Temple Run being household names. For novice players, Endless Runner games provide an excellent learning experience. They offer a gradual increase in difficulty, allowing players to familiarize themselves with the mechanics and controls at their own pace. As players progress, they can unlock new obstacles, levels, and even customize their gaming experience.
You can test our Endless Runner game end-result here if you’d like. You can also find out more information, including seeing the demo video of this project here.
In our Endless Runner game, called Dock & Roll, our players will spawn in a procedurally generated level. When they press start, they will start running forward against a timer, and as they move forward the level will procedurally generate around them. Players must jump over obstacles and collect power-ups consisting of coins (score boosts), flags (which decrease game time), and gems (for jump boosts). If they survive until the timer runs out, they will complete the level, after which the game ups the ante with faster speeds and more complex obstacles. Players have three lives and losing them all or crashing into an obstacle requires restarting the level. We’ll also integrate the ability to save and load levels, allowing for breaks without losing progress.
Figure 6: Overview of our game and game loop. You can view all the Excalidraw boards for this booklet here.
We’ll create our game in sections, particularly focusing on the seven entities that make up our game. These entities form a complex system that works in unison to deliver a seamless and engaging Endless Runner game. These entities are:
1. Player: This is the game’s protagonist, controlled by the user. They are responsible for navigating through the game world, which involves running on platforms, dodging various obstacles, collecting power-ups, and ultimately facing the win or lose screen depending on their outcome.
2. World: This entity is the backbone of the game environment. It dynamically generates the game space by spawning platforms, obstacles, collectibles, and the environment itself, which the player collides with.
3. Obstacles: These are the challenges placed within the world to test the player. Each obstacle type has specific behavior, and this entity manages their spawning logic and movement, making the game engaging and challenging.
4. Collectibles: Serving as rewards and aids, collectibles are of various types, each with unique spawning logic and movement. Players aim to gather these to improve scores, gain jump boosts, or affect game time.
5. HUD (Heads-Up Display): This element of the game provides the player with real-time information such as the number of lives left, the remaining time, the current score, and any active power-ups or boosts. It’s essential for keeping the player informed about their status within the game.
6. Global: This entity acts like the game’s overseer and is an Autoload Singleton. It manages scenes that can be spawned multiple times, keeps track of level variables, and handles signals across the game. It’s also in charge of the save/load system, ensuring players can resume their progress.
7. Main: It contains the player and world spawner, handles the environmental aspects of the game, and is responsible for the main menu, allowing players to start or exit the game, or load saved games.
Figure 7: Overview of our game’s entities.
*Please note that this booklet is meant for beginner to intermediate developers, but I do assume that you know the fundamentals of GDScript. If you know nothing about GDScript or coding in general, please go and do this free workshop first.
Without any further dilly-dallying, let’s get started with our project setup. Open up your Godot 4 editor, and let’s create a new project. We’ll call it Dock&Roll, and we will run it in forward+ mode since this is a 3D game that requires a bit more processing power and graphics rendering.
We’ll have to import all of the assets that we will use for our project. You can find the accreditations to all of the CC licensed assets that I’ve compiled for this project all over the internet on my GitHub repository, which also contains the sectional source code for this project. You can use the sectional source code to compare your code to the code at the end of each part. Let’s download our assets. You can download it directly from my Google Drive, here.
Once that’s done downloading, unzip the Assets folder, and drag the Assets folder within it into your newly created project.
You’ll see that we have a bunch of folders within this newly imported Assets directory. Each of these folders contains the assets for each entity of our project. Most of these assets are in .fbx format. The .fbx file format, which stands for Filmbox, is a popular type of file format used for 3D models, animations, and scenes. We import our files as. fbx because it can store our assets mesh, skeleton, collision, and animations. Godot also supports .glb/.gltf assets, which store our assets’ geometry, materials, and animations (if any), rather than game-specific features like collisions.
We’ll need to create two new folders in our FileSystem panel: one to hold our scenes, and another one to hold our scripts. To create a folder, simply right-click in your FileSystem panel and select “New Folder”. Let’s create these folders, called “Scripts” and “Scenes”.
In the Scenes folder, let’s create our first scene, which will be our Main Scene. The Main Scene is the scene that will serve as the core container for our game elements. It is here where we will add our environment, player, and spawnable world so that we can play the game. The Main Scene is also the one that runs automatically when the game launches.
To add a scene, you can right-click on the FileSystem panel and add it like we added our folders, or you can click on the plus icon or select the “3D Scene” option in our Scene Dock.
Let’s create a new 3D scene.
You will now see that a Node3D node has been added as our root, but our Scene hasn’t been saved yet. Save it in the Scenes menu above or use the shortcut CTRL + S. Save the Scene as “Main” in your Scenes folder.
Let’s rename this root node to “Main”. Since the root node is the main node, or top node, in our scene hierarchy, it is better to give our node the same name as the scene. We do this so that when we instance this scene in other scenes, we will know that this node belongs to the “Main” scene.
To rename this node, simply double click on it.
To see your 3D scene, open your 3D workspace.
We’ll set this scene to be our first scene to show on the screen when we run the game. So, if we press F5, this scene should open. To do this, we will set it as the main scene in our project settings. Open up your project settings, and underneath Application > Run, change the main scene to your Main resource.
Whilst we’re in our settings, we’ll have to change our Anti-Aliasing settings for our project as well. When we later spawn our platforms, you might notice some jittering or flickering in your meshes, and this is because by default anti-aliasing is disabled.
Anti-aliasing is a technique used in computer graphics to reduce the visual defects that occur when high-resolution images are displayed in lower resolutions. These defects, often seen as jagged edges on diagonal lines and curves, are known as “aliasing.” Anti-aliasing smooths out these edges, making the lines appear straighter and the overall image more polished.
Figure 8: Our water with and without anti-aliasing enabled.
In your project settings, head over to Rendering > Anti-Aliasing, and let’s change our settings as follows:
MSAA 3D — MSAA is a type of spatial anti-aliasing that smooths out the edges by sampling a pixel multiple times at different sample points and then averaging the results to get a smoother transition. The “8x” setting means the engine will take 8 samples per pixel, which provides a high-quality anti-aliasing effect but is also the most performance intensive.
Screen Space AA — FXAA is a screen-space anti-aliasing algorithm that is faster than MSAA but can sometimes result in a slight blurring of the image. We set it to fast because this generally gets applied to the image after it has been rendered.
TAA — Combines information from past frames (temporal data) to produce smoother edges and reduce flickering in motion. However, it can also introduce some motion blur and might be more performance intensive.
Finally, we will add all of our Input Actions for our game. This is the physical controls, such as our keyboard keys, joysticks, buttons, etc. that we will map to our functions to move our character around the game. We’ll only have to create the input action for our player’s jumping, since the movement inputs for left, right, up, and down have already been added. To add input actions, we go to Project Settings > Input Map.
Godot 4 comes with pre-existing input actions. To see them, enable the “Show Built-in Actions” toggle. The **ui_ **stands for “user input”, and you don’t have to stick to this naming convention for your future input actions, but for this project we will just keep our code consistent.
You’ll see Godot has already pre-configured the inputs to move a character left, right, up, and down. They assigned the keyboard keys UP, DOWN, LEFT, and DOWN to these actions. You can edit them by pressing on the pencil icon next to them, or even delete them. You can also assign other keys to this input by clicking on the plus icon next to it.
Let’s add a new input called “ui_jump”, and we’ll assign the SPACE key on our keyboard to this input action.
Congratulations, you’ve learnt how to navigate through the Godot Editor, as well as work with nodes and scenes — which are the core fundamentals you’ll use throughout your game. It would be good practice for you to create your own GitHub repository for your project so that you can make regular backups of your project. When you’re ready, let’s move on to the next part, where we will set up our environment — meaning the lighting, fog, and sky sphere.
Unlock the Series!
This series will be turned into a video series on my YouTube channel, but if you like this series and would like to support me, you could donate any amount to my KoFi shop or you could purchase the offline PDF for $4 that has the entire series in one on-the-go booklet!
This PDF gives lifelong access to the full, offline version of the “Learn Godot” PDF booklet. This is a 291-page document that contains all the tutorials of this series in a sequenced format, plus you get dedicated help from me if you ever get stuck or need advice. This means you don’t have to wait for me to release the next part of the tutorial series on YouTube, Dev.to or Medium. You can just move on and continue the tutorial at your own pace — anytime and anywhere!
This book will be updated continuously to fix newly discovered bugs, or to fix compatibility issues with newer versions of Godot 4.