How software developer tried game development
Posted 2 days ago
A bit of theory

A week into development, I finally tackled AI logic. The big question was: how should I implement it? A quick search led me to three possible approaches:
  1. Finite-State Machine (FSM) – The bot switches between different states, each defining a unique behavior.
  2. Behavior Tree.
  3. Decision Tree.
I didn't even describe the last two—because I didn’t understand them :). While FSM resembled a familiar state pattern, the tree-based approaches seemed way more complex. I couldn’t grasp their benefits for my specific use case in the short timeframe. So maybe next time.

FSM, however, had their own challenges. For example, let’s say a bot has the state "moving from point A to B" and another state "attacking the target." What if I wanted the bot to both move and attack at the same time?
That’s where Hierarchical Finite-State Machines (HFSMs) come in. However, I misunderstood them and accidentally invented my own version instead. I suspected this for a while, but I only confirmed it now.

Anyway, here’s what my NPC’s state system looked like:
  • Movement States: idle, chasing, combat maneuvering (strategic movements, like taking cover).
  • Combat States: Idle, shooting, reloading.

Clearly, there were two parallel layers of states (movement and combat), so I split them into separate subtypes:
Additionally, I introduced conditions (an `ICondition` interface). This prevented redundant checks across multiple states. For instance, if the bot lost its weapon, it shouldn’t try to shoot or reload. Here’s a class structure of condtions:
Their usage was as follows:
  1. The FSM runs every set period of time:
  2. Check conditions – If needed, change states.
  3. Execute logic – Run the behavior of the current state (handled by `Think`).

How I did it
Each state had a straightforward implementation:
  • Idle – both combat and action states wait for the right conditions to change the state.
  • Attacking and reloading – If the bot has ammo and a clear shot, it fires (`IsShooting = true`). Otherwise, it reloads.
  • Chasing – Updates target coordinates and requests a path from NavMesh. The bot continues chasing until it's close enough to enter combat maneuvering.
  • Combat Maneuvering – Is more interesting. AI finds a nearby cover and moves behind it. If no cover is available, the bot picks a random movement pattern. Below is a flowchart of the algorithm (where "tick" refers to a `Think` call):
Once this work was done, I had an AI bot that resembled a basic Half-Life 2 NPC. Before refining it further, I wanted to showcase its existing features.