How are people doing enemy AI?

I wanted to ask the community how they have implemented enemy AI in their projects.

I like this discussion here, of having a finite state machine for the various agents in the game:

(I’d also, in all my years of playing pacman, never once noticed that two of the ghosts always turn the same direction)

I also like this tutorial on decision trees, and started to build an implementation of the selector/ sequencer nodes he discusses by using closures:

I’m a little stumped though in terms of working out whether these two approaches can be combined. The finite state machine idea seems better suited to more dynamically changing environments where the agent has to react appropriately, whereas the decision trees seem better-suited for more proactive agents.

Does anyone have any tips they can share?

Thank you for the links

I’m not sure that many of us have written games complicated enough for decision trees - generally, a small series of if tests will be sufficient - but finite state machines seem simple enough.

It’s the sort of thing where you really need an “agile” approach with lots of testing to make sure that logic errors aren’t creeping in.

Not got to the point in any game of having any AI. Most of mine ends up as random spawning of enemies

Yes, I tend to keep an extra tab on the right called “Test”, where I run small programs (overriding the main program) to test functions like this, then I comment the Test tab out to run the main program

Hi @yojimbo2000, for our game we wrote the AI system in C as a series of state machines and compiled it in…

@ignatz @brookesi This is all so interesting, how do I implement state machines and decision trees? Are there existing projects with just the base functions I can peer at?

No, I don’t think you’ll find any templates, but if you google the forum, I’m sure you’ll find some example projects

@archistudent You can implement a simple state machine by having a table with each key representing a single state, you can then “move” between states by simply setting the a state variable. eg

Enemy = Class()

function Enemy:init(stateMachine)
   self.state = "init"
   self.stateMachine = stateMachine

function Enemy:update()
   print("State = "..self.state)

local bobsStates = {
   init = function(self) self.state = "waiting" end,
   waiting = function(self) self.state = "moving" end,
   moving = function(self) self.state= "attacking" end,
   attacking = function(self) self.state = "waiting" end
   -- etc

local bob = Enemy(bobsStates)

Hope this gives you some ideas.

@techdojo ahh I see, I think I may have implemented something similar to this before but just never knew its name hah!