Patrol, alert, attack! Overview

Heads up!
Module 4 is expected to have 9 lessons. So it's not over yet!
Starting this module we will be releasing lessons gradually, one at a time. This allows us to push lessons out to you more frequently and iterate faster on your feedback.
As always throughout Early Access, things are not set in stone, we may still go back and make changes to improve the learning experience.
If you prefer to wait until the complete module is released with all the lessons, keep an eye/ear out for the usual announcement. You can subscribe to course updates by clicking the button in the Stay Tuned section, or join our discord server.
Nathan
Founder and teacher at GDQuest
In the previous module, we created a player controller that can shoot fireballs and take and deal damage. We also made a dummy mob, but it could only stand there and act as a damage sponge.
In action games, you generally challenge the player with mobs that have various attack patterns. That's what we'll focus on in this module. You'll code three mobs that can:
  • Look at the player.
  • Shoot projectiles.
  • Have a cone of vision.
  • Chase the player.
  • Attack using different patterns.
Not only will you code the individual mechanics, but you'll also learn how to structure the code to make them reusable across different mobs. This is important for a game with many mobs, as it allows you and your team to create new enemies quickly by mixing and matching behaviors.
That's what you'll create in this module. And in the next module, we'll turn this into a complete little level with arenas and focus on improving the game feel.
Game AI is not strictly 3D knowledge, but it's an integral part of many 2D and 3D games' core gameplay loops, so I want to give you some tools to help tackle it.
Like Learn 2D Gamedev From Zero before it, this course is not only about 3D; it's also about thinking like a programmer and learning to manage complexity.
Nathan
Founder and teacher at GDQuest

The challenge of coding multiple mobs

In the kind of game we're making, you'll likely want many mobs that reuse the same behaviors with some variations. For example, in action games, bosses typically use the same attack patterns as mobs you previously faced, only with more intensity and complexity.
In general, mobs have many little behaviors in common, like a line of sight, a way to chase the player, etc. In a sizeable project, you need a way to code these behaviors once and reuse them across different mobs.
But how do you go about that exactly? You could code each and every mob independently. We did that with the towers in the tower defense module in Learn 2D Gamedev From Zero. We used inheritance so they could share some properties, but we still had to code each mob individually.
Towards the end of the course, we also learned to make multiple AIs faster to code by creating a library of reusable functions. This approach works great in a simple game with few mobs or for simple AIs, but it has limitations.
There are two main issues you may face:
  1. As you make mobs with increasingly complex behaviors, it can become challenging to coordinate many different functions that each have their own constraints. It's too easy to inadvertently tangle functions together.
  2. With only functions, you will always need a programmer to implement and modify every mob in the game. It's not very accessible to a designer teammate.
This module will teach you one of the most common tools professionals use. You will learn how to create a robust foundation for AIs in your game using finite state machines

Finite State Machine

Finite state machines are a way to design code by splitting individual behaviors into separate exclusive states. You execute the code of only one state at a time and control the transitions between states.
A good example is a character that can run, jump, and attack. You can create a state for each of these actions: the run, jump, and attack states.
When the player presses the jump button on the ground, the character transitions from run to jump. When the character lands, it transitions back to the run state. When the player presses the attack button, the character transitions to the attack state. When the attack is done, the character transitions back to the run state.
It's a simple idea that can be implemented in many ways, ranging from a few lines of code to a complex system that supports games like Hollow Knight, which uses state machines for its enemies and bosses.
More on Finite State Machine
. We will start with the simplest possible implementation and scale up to creating a small AI library that allows you to code reusable behaviors and reuse them across different mobs.

What you will learn

We will create two mobs together. The first is the training dummy from M3. We'll make it turn toward the player and shoot fireballs.
The second mob is a bee that can charge at the player and attack them in a straight line.
You will then use what you learned to code a beetle that slowly walks toward the player, stomps the ground, and deals damage in an area around it.
You will also reuse the hitbox, hurtbox, and projectile we created in the previous module to take and deal damage.
All three mobs, and probably all mobs in a top-down shooter game like this, will share similar behaviors: they can see the player or sense them when close enough, get interrupted when they take damage, move toward the player, and attack when in range.
Some mobs may even have variants of the same attack patterns. Here, we only have three, but we're going to think as if the project was meant to scale past our little demo. We will think about how to make the code work for a roguelike shooter or a Metroidvania game that might take months to years of development.
You will learn how to:
  • Implement a simple finite state machine with a variable and an enum in a script.
  • Implement a more complex state machine designed to scale and support games that take months to years of development.
  • Code states

    State (Finite State Machine)

    In state machines, a state is a specific behavior or set of behaviors that an entity can be in. For example, a mob can be in the "patrol" state, where it moves between waypoints, or in the "chase" state, where it runs towards the player.
    It's a bit different from when we talk about the state of a program, which is a snapshot of the current data the program put in the computer's memory at a given point in time.
    More on State (Finite State Machine)
    that can be reused across different mobs, so you only have to code shared behaviors once.
  • Create a mob that turns to look at the player, pauses, and shoots a bullet at them.
  • Create a mob that can charge at the player and sting them.
  • Create a mob that walks towards the player, stomps the ground, and deals damage in an area around it.
  • Implement mobs that take damage and die using hit and hurt boxes.
A key takeaway from this module is that a state machine is a model for structuring your code. You can implement it in different ways, making trade-offs between flexibility, scalability, and development time.
Like most programming patterns, state machines are not a specific way to code but a general idea that you can adapt to your needs.
You can start with as little as two lines of code, just a variable and an enum, and evolve it into a more complex form to scale up to large commercial games with dozens of enemies and bosses. From indie platformer hit Celeste to ID Software's Doom 2016, numerous games use finite state machines for playable characters and enemies.
Nathan
Founder and teacher at GDQuest
We will also follow the process we recommend as professional game developers: starting with the simplest code for prototyping or during game jams, where you are still figuring out the gameplay. Simpler code is faster to change

More is less

The more elaborate and scalable you make the code early on, the more constraints you impose on your project. You need more code to build the system, which means more potential bugs and all the code that uses the system is constrained by it and tied to it.
More abstraction also makes code harder to change. The more abstract your code is, the more systematic it becomes. In games, we often need special cases, so keeping the code as lose and simple as possible until the end is a good idea.
One thing I learned while watching really experienced and productive game developers is that they throw away and rewrite code quite a lot. I think of it as concept art or blocking out a sculpt. You figure out the game's design or the code requirements through one-time experiments. Once you have a clearer idea of where you're headed, you can work towards a more final version.
and ideal early on.
That's why we'll implement a simple state machine in the next lesson: it works great for prototypes and helps separate concerns. Then, we will rewrite it into a more powerful system.

Download the project files

To follow along with this module, ensure you have downloaded the latest version of the Godot project files. Click the button corresponding to your system to do so:
This download includes all the assets to follow along with the module. I'll see you in the next lesson to start coding the dummy mob!

Lesson Q&A

Use this space for questions related to what you're learning. For any other type of support (website, learning platform, payments, etc...) please get in touch using the contact form.

No questions yet! It's really ok to ask the first question.
Site is in BETA!found a bug?