Finite State Machines Finite State Machines Often AI as agents: - - PowerPoint PPT Presentation

finite state machines finite state machines
SMART_READER_LITE
LIVE PREVIEW

Finite State Machines Finite State Machines Often AI as agents: - - PowerPoint PPT Presentation

3/24/2016 Finite State Machines Finite State Machines Often AI as agents: sense , think , then act But many different rules for agents Ex: sensing, thinking and acting when fighting , running , exploring Can be difficult to


slide-1
SLIDE 1

3/24/2016 1

Finite State Machines

  • Often AI as agents: sense, think, then act
  • But many different rules for agents

– Ex: sensing, thinking and acting when fighting, running, exploring… – Can be difficult to keep rules consistent!

  • Try Finite State Machine

– Probably most common game AI software pattern – Natural correspondence between states and behaviors – Easy: to diagram, program, debug – General to any problem – See AI Depot – FSM: http://ai-depot.com/FiniteStateMachines/

  • For each situation, choose appropriate state

– Number of rules for each state is small

Finite State Machines

  • Abstract model of computation
  • Formally:

– Set of states – A starting state – An input vocabulary – A transition function that maps inputs and current state to next state

(Detailed game example next slide)

https://en.wikipedia.org/wiki/Finite-state_machine#/media/File:Turnstile_state_machine_colored.svg

Finite State Machines – Example (1 of 2)

  • Game where raid Egyptian Tomb
  • Mummies! Behavior

– Spend all of eternity wandering in tomb – When player is close, search – When see player, chase

  • Make separate states

– Define behavior in each state

  • Wander – move slowly, randomly
  • Search – move faster, in lines
  • Chasing – direct to player
  • Define transitions (suitable for code)

FSM?

Finite State Machines – Example (1 of 2)

  • Game where raid Egyptian Tomb
  • Mummies! Behavior

– Spend all of eternity wandering in tomb – When player is close, search – When see player, chase

  • Make separate states

– Define behavior in each state

  • Wander – move slowly, randomly
  • Search – move faster, in lines
  • Chasing – direct to player
  • Define transitions (suitable for code)

– Close is 100 meters (smell/sense) – Visible is line of sight

Wander Seek Attack

Sense See No sense Can’t see

slide-2
SLIDE 2

3/24/2016 2

Finite State Machines – Example (2 of 2)

  • Can be extended easily
  • Ex: Add magical scarab (amulet)
  • When player gets scarab,

Mummy is afraid. Cowers.

  • Behavior

– Stay still (tremble animation)

  • Transition

– When player gets scarab – When timer expires

  • Could also have sub-states

– Same transitions, but different actions

  • i.e., range attack versus melee

attack Wander Seek Attack

Sense See No Sense Can’t See

Cower

Ankh

No Ankh

Start

Outline

  • Introduction

(done)

  • Common AI Techniques

(done)

  • Promising AI Techniques

(done)

  • Pathfinding (A*)

(done)

  • Finite State Machines

– Game example (next)

  • Summary

Pyramid!

Solve the maze to escape the mummy guardians!

State.h

class State { private: string state_type; // Name of state. public: State(); // Set name of state. void setType(std::string new_type); // Get name of state. std::string getType() const; // Invoked when state first entered. virtual void Enter(Object *p_obj); // Invoked every game loop step. virtual void Execute(Object *p_obj)=0; // Invoked when state exited. virtual void Exit(Object *p_obj); };

Dragonfly

Must define

Derived class redefines

slide-3
SLIDE 3

3/24/2016 3

StateMachine.h

class StateMachine { private: Object *p_owner; // Owner of this state machine. State *p_state; // Current state. State *p_previous_state; // Previous state. State *p_global_state; // Global state (reachable from any state). public: StateMachine(); // Set owner of state machine. void setOwner(Object *p_new_owner); // Get owner of state machine. Object *getOwner() const; // Set current state. void setState(State *p_new_state); // Get current state. State *getState() const; // Set previous state. void setPreviousState(State *p_new_state); // Get previous state. State *getPreviousState() const; // Set global state. void setGlobalState(State *p_new_state); // Get global state. State *getGlobalState() const; // Update state machine (calling Execute() for current state). void Update(); // Change current state. void changeState(State *p_new_state); // Revert to previous state. void revertToPrevious(); };

Dragonfly

Called to update

  • FSM. Usually

every step Called when state changes

StateMachine Update(), ChangeState()

void StateMachine::Update() { // Execute global state. if (p_global_state) p_global_state -> Execute(p_owner); // Execute local state. if (p_state) p_state -> Execute(p_owner); } void StateMachine::changeState(State *p_new_state) { // Call exit on old state. if (p_state) p_state -> Exit(p_owner); // Keep track of previous state. p_previous_state = p_state; // Change to new state. p_state = p_new_state; // Call enter on new state. if (p_state) p_state -> Enter(p_owner); }

Dragonfly

StateWander.h

Pyramid class StateWander : public State { private: StateWander(); // Private since singleton. StateWander(StateWander const&); // Don't allow copy. void operator=(StateWander const&); // Don't allow assignment. public: // Get the singleton instance of the state. static StateWander *getInstance(); void Enter(Object *p_obj); void Execute(Object *p_obj); }; Also need: StateSearch, StateChase and StateCower

Note: has no Exit()

StateWander Enter()

// Change sprite to "wander" Mummy. void StateWander::Enter(Object *p_obj) { LogManager &log_manager = LogManager::getInstance(); // Set wander sprite (white mummy). ResourceManager &resource_manager = ResourceManager::getInstance(); Sprite *p_sprite = resource_manager.getSprite("mummy-white"); if (!p_sprite) { log_manager.writeLog("Warning! ‘mummy-white' not found"); return; } p_obj -> setSprite(p_sprite); log_manager.writeLog("StateWander::Enter(): Set mummy-white"); }

Pyramid

slide-4
SLIDE 4

3/24/2016 4

StateWander Execute()

// Wander around pyramid. void StateWander::Execute(Object *p_obj) { // This state deals with a Mummy, so cast Object *. Mummy *p_mummy = dynamic_cast <Mummy *> p_obj; // Move. if (!doMove(p_mummy, 1, false)) return; // If Hero has ankh, enter cower state. if (Hero::getInstance() -> hasAnkh()) { StateMachine *p_machine = p_mummy->getMachine(); p_machine -> changeState(StateCower::getInstance()); return; } // If can sense Hero, enter seek state. if (p_mummy -> senseHero()) { StateMachine *p_machine = p_mummy->getMachine(); p_machine -> changeState(StateSeek::getInstance()); return; } }

Pyramid

Defined in Mummy Defined in Hero

Mummy.h

class Mummy : public Object { private: int move_countdown; int think_countdown; enum direction_type direction; StateMachine machine; // Controls behavior. public: ~Mummy(); Mummy(); int eventHandler(Event *e); bool senseHero(); int seeHero(); void setMoveCountdown(int new_move_countdown); int getMoveCountdown(); void setThinkCountdown(int new_think_countdown); int getThinkCountdown(); void setDirection(enum direction_type new_direction); enum direction_type getDirection(); // Return pointer to Mummy's finite state machine. StateMachine *getMachine(); };

Pyramid

Used by states for transitions Used for slowing down movement, thinking

The Mummy State Transitions

// Constructor. Mummy::Mummy() { // Set up state machine. Starts in “wander” state. machine.setOwner(this); machine.setState(StateWander::getInstance()); machine.changeState(StateWander::getInstance()); … } // Handle event. // Return 0 if ignored, else 1 int Mummy::eventHandler(const Event *p_e) { if (p_e->getType() == df::STEP_EVENT) { machine.Update(); // Update state machine. return 1; } … // Return true if Hero is within sensing distance. bool Mummy::senseHero() { WorldManager &world_manager = WorldManager::getInstance(); // If Hero is within box, then can sense. // First, setup box. df::Box sense_box; df::Position p(getPosition().getX()-SENSE_XRANGE/2, getPosition().getY()-SENSE_YRANGE/2); sense_box.setCorner(p); sense_box.setHorizontal(SENSE_XRANGE); sense_box.setVertical(SENSE_YRANGE); // Then, see if Hero within box. df::ObjectList objs_in_box = world_manager.objectsInBox(sense_box); df::ObjectListIterator oi(&objs_in_box); for (oi.first(); !oi.isDone(); oi.next()) { df::Object *p_temp = i.currentObject(); if (p_temp -> getType() == "Hero") return true; // Senses Hero! } } return false; // Doesn’t sense Hero. }

Code Flow for State Machine

  • Initially:

– Define states as classes derived from State (e.g., StateWander) – Setup StateMachine (e.g., set starting state)

  • In Game Step event

– Get state from state machine – Call StateMachine Update() – StateMachine Update() calls State Execute() of derived class

  • e.g., StateWander calls Mummy senseHero()

– If so, tell state machine to change state – Otherwise, execute state action (e.g., Mummy wanders)

slide-5
SLIDE 5

3/24/2016 5

Finite State Machines Summary

Pros

  • Simplicity low entry level
  • Simplicity quick to design,

implement and execute

  • Predictability allows for easy

testing

  • Well-proven technique with lots of

examples

  • Flexibility many ways to

implement

  • Easy to transfer from abstract

representation to coded implementation

  • Low processor overhead only

the code for current state needs to run, well suited to games

  • Easy to tell reachability of state

Cons

  • Predictability can make for

easy-to-exploit opponent

  • Complexity Large FSMs

difficult to manage and maintain ("spaghetti-factor“)

  • Inflexibility All states,

transitions and conditions need to be known up front and be well defined

  • Inflexibility conditions for

transitions are rigid