State machines and enemy AI

Godot Version

4.4

Question

What is your method of implementing state machines and enemy AI?

I know people who make state machines modular, or all in one script. But I’m realizing idk how they run behavior from that, specifically for enemy AI

What are ways you have implemented behavior or ways I could?

In my game I know walking is always the same per character. As well as things like status effects like fear will mechanically be the same. While spells and skills will function differently

Do you just have it in the state?

I just use a pretty simple goal-based state machine, layered with a regular one for things like Idle, Patrol, Attack, etc.

Basically, if the enemy is near a tower, it knows to attack it by calling something like attack_tower(). But if it gets hit by the player while doing that, it’ll switch goals and call attack_player() instead.

If there’s nothing important nearby — no enemies, no objectives — it’ll just go back to patrolling or playing an idle animation.

It’s not super complex, but it works well for what I need. Hope that’s what you were asking!

1 Like

The statemachine itself does nothing except calling functions that transition something from one state to another, and making sure that the thing governed by the statemachine is only in one state at all times. You as the developer write the conditionals that call the transitions and the logic that gets executed when in a certain state.

In practice, that usually means that you write functions that handle a state, and call that function in physics process. Pseudocode e.g.

func _physics_process(delta) -> void: 
    match state:
        state.IDLE:
                handle_idle()
        state.CHASE: 
                handle_chase()

func handle_idle():
     # play idle animation 
     # listen for input to state transitions (like a Player body entering an area 2D)
     # set state to chase

func handle_chase(): 
     # get direction from player position 
     # move enemy to player position 
     # if player leaves area set state to idle 
2 Likes

I have found it useful for my enemy AI to create a behaviour machine to complement the state machine. The state machine is exactly as @Herb described above. I have children of the state machine that just handle what to do in a particular state. These states can then be re-used and they do not themselves switch between states. The behaviour machine deals with behaviour.

For example.
An area detects a player. It calls the behaviour machine function deal_with_player_detected. This function does all the necessary checks like do we have ammo, are we injured, what state are we in. So if we are injured and near death, we run away, which mean changing the state to ‘evade’. If we are not injured but have no ammo, we change the state to ‘return_to_base’. If we have ammo and are not injured, change the state to ‘move_to_attack’.

In this way, all the behaviour is contained in one place. So once all my states are working, I never have to touch them again. Also, to change an enemies behaviour I only have to alter the behaviour manager. (With this system, only the behaviour manager changes states, again making future debugging and maintenance so much easier).

So I would recommend using states to control the enemy, and using a behaviour manager to control the behaviour (the switching from one state to another). Obviously the player does not need it because the actual human is the behaviour manager for the players character.

2 Likes

@pauldrewett 's system is also useful for separating desire and action. I used something like that in a brawler years ago, where controls were split into “brain” and “body”, effectively. The “brain” made decisions like “I want to hit that guy”, while the body would say “love to, but I’m currently in a hit react animation…”.

Basically, separating what the AI wants to do from what it can currently do (or must do).

You can have multiple layers of this; for example, a high-level decision system (“chase that guy and get him!”), a mid-level task system (“he’s in range, throw a punch”) and a low-level body control system (“I’ve just jumped to get close enough, can’t punch yet…”).

1 Like

@hexgrid That is a really interesting point. For my next project (which I am just considering at the moment since I have not finished my current one) I was thinking of doing something much more organic. I had been wondering how I would deal with more complex behaviour trees but that idea of multiple levels of decision solves it. For instance I was not sure how to deal with say, a child currently looking for food but also evading a predator (simple example), without the behaviour manager getting overloaded with “if this and if that and if the other then this”. But your idea lets me make adults behave differently than children, say, as they gain experience.

So thank you, that was really helpful!

1 Like