finite state machines finite state machines
play

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


  1. 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 keep rules consistent! • Try Finite State Machine https://en.wikipedia.org/wiki/Finite-state_machine#/media/File:Turnstile_state_machine_colored.svg – Probably most common game AI software pattern – Natural correspondence between states and behaviors • Abstract model of computation – Easy: to diagram, program, debug • Formally: (Detailed game example – General to any problem – Set of states next slide) – See AI Depot – FSM: http://ai-depot.com/FiniteStateMachines/ – A starting state • For each situation, choose appropriate state – An input vocabulary – Number of rules for each state is small – A transition function that maps inputs and current state to next state Finite State Machines – Example (1 of 2) Finite State Machines – Example (1 of 2) Game where raid Egyptian Tomb Game where raid Egyptian Tomb • • Mummies! Behavior Mummies! Behavior Wander • • – Spend all of eternity w andering in – Spend all of eternity w andering in tomb tomb No sense Sense – When player is close, s earch – When player is close, s earch – When see player, c hase – When see player, c hase FSM? Make separate states Make separate states • • Seek – Define behavior in each state – Define behavior in each state • Wander – move slowly, randomly • Wander – move slowly, randomly Can’t see • Search – move faster, in lines • Search – move faster, in lines See • Chasing – direct to player • Chasing – direct to player Define transitions (suitable for code) Define transitions (suitable for code) • • Attack – Close is 100 meters (smell/sense) – Visible is line of sight 1

  2. 3/24/2016 Finite State Machines – Example (2 of 2) Outline Start • Can be extended easily • Introduction (done) • Ex: Add magical scarab (amulet) Wander • When player gets scarab, • Common AI Techniques (done) Mummy is afraid. Cowers. No Sense Sense • Behavior • Promising AI Techniques (done) No – Stay still (tremble animation) Ankh • Pathfinding (A*) (done) • Transition Seek Cower – When player gets scarab Ankh • Finite State Machines Can’t See – When timer expires See • Could also have sub-states – Game example (next) – Same transitions, but different Attack • Summary actions • i.e., range attack versus melee attack class State { Pyramid! private: string state_type; // Name of state. public: State(); // Set name of state. void setType(std::string new_type); State.h // Get name of state. std::string getType() const; // Invoked when state first entered. virtual void Enter(Object *p_obj); Must define Derived class // Invoked every game loop step. redefines virtual void Execute(Object *p_obj)=0; // Invoked when state exited. virtual void Exit(Object *p_obj); Dragonfly }; Solve the maze to escape the mummy guardians! 2

  3. 3/24/2016 class StateMachine { StateMachine Update(), ChangeState() private: Object *p_owner; // Owner of this state machine. State *p_state; // Current state. State *p_previous_state; // Previous state. void StateMachine::Update() { State *p_global_state; // Global state (reachable from any state). StateMachine.h // Execute global state. public: StateMachine(); if (p_global_state) p_global_state -> Execute(p_owner); // Set owner of state machine. void setOwner(Object *p_new_owner); // Execute local state. // Get owner of state machine. if (p_state) Object *getOwner() const; p_state -> Execute(p_owner); // Set current state. void setState(State *p_new_state); } // Get current state. State *getState() const; void StateMachine::changeState(State *p_new_state) { // Set previous state. Called to update void setPreviousState(State *p_new_state); FSM. Usually // Call exit on old state. // Get previous state. if (p_state) p_state -> Exit(p_owner); State *getPreviousState() const; every step // Set global state. void setGlobalState(State *p_new_state); // Keep track of previous state. // Get global state. p_previous_state = p_state; State *getGlobalState() const; // Update state machine (calling Execute() for current state). // Change to new state. void Update(); Called when p_state = p_new_state; // Change current state. void changeState(State *p_new_state); state changes // Revert to previous state. // Call enter on new state. void revertToPrevious(); if (p_state) p_state -> Enter(p_owner); Dragonfly }; } Dragonfly StateWander.h Pyramid StateWander Enter() Pyramid class StateWander : public State { // Change sprite to "wander" Mummy. void StateWander::Enter(Object *p_obj) { private: LogManager &log_manager = LogManager::getInstance(); StateWander(); // Private since singleton. StateWander(StateWander const&); // Don't allow copy. // Set wander sprite (white mummy). void operator=(StateWander const&); // Don't allow assignment. ResourceManager &resource_manager = ResourceManager::getInstance(); public: Sprite *p_sprite = resource_manager.getSprite("mummy-white"); // Get the singleton instance of the state. if (!p_sprite) { static StateWander *getInstance(); log_manager.writeLog("Warning! ‘mummy-white' not found"); return; } void Enter(Object *p_obj); Note: has no Exit() p_obj -> setSprite(p_sprite); void Execute(Object *p_obj); log_manager.writeLog("StateWander::Enter(): Set mummy-white"); }; } Also need: StateSearch , StateChase and StateCower 3

  4. 3/24/2016 Pyramid Pyramid class Mummy : public Object { // Wander around pyramid. void StateWander::Execute(Object *p_obj) { Used for slowing down StateWander Execute() private: movement, thinking int move_countdown; // This state deals with a Mummy, so cast Object *. int think_countdown; Mummy *p_mummy = dynamic_cast <Mummy *> p_obj; enum direction_type direction; StateMachine machine; // Controls behavior. // Move. Mummy.h if (!doMove(p_mummy, 1, false)) public: return; Defined in Hero ~Mummy(); Mummy(); Used by states for // If Hero has ankh, enter cower state. int eventHandler(Event *e); if (Hero::getInstance() -> hasAnkh()) { transitions bool senseHero(); StateMachine *p_machine = p_mummy->getMachine(); int seeHero(); p_machine -> changeState(StateCower::getInstance()); void setMoveCountdown(int new_move_countdown); return; int getMoveCountdown(); } void setThinkCountdown(int new_think_countdown); Defined in Mummy int getThinkCountdown(); // If can sense Hero, enter seek state. void setDirection(enum direction_type new_direction); if (p_mummy -> senseHero()) { enum direction_type getDirection(); StateMachine *p_machine = p_mummy->getMachine(); p_machine -> changeState(StateSeek::getInstance()); // Return pointer to Mummy's finite state machine. return; StateMachine *getMachine(); } }; } The Mummy State Transitions Code Flow for State Machine • Initially: // Return true if Hero is within sensing distance. // Constructor. bool Mummy::senseHero() { – Define states as classes derived from State (e.g., Mummy::Mummy() { WorldManager &world_manager = WorldManager::getInstance(); // Set up state machine. Starts in “wander” state. StateWander) machine.setOwner(this); // If Hero is within box, then can sense. machine.setState(StateWander::getInstance()); // First, setup box. – Setup StateMachine (e.g., set starting state) machine.changeState(StateWander::getInstance()); df::Box sense_box; … df::Position p(getPosition().getX()-SENSE_XRANGE/2, • In Game � Step event } getPosition().getY()-SENSE_YRANGE/2); sense_box.setCorner(p); sense_box.setHorizontal(SENSE_XRANGE); – Get state from state machine sense_box.setVertical(SENSE_YRANGE); // Handle event. // Return 0 if ignored, else 1 – Call StateMachine Update() // Then, see if Hero within box. int Mummy::eventHandler(const Event *p_e) { df::ObjectList objs_in_box = if (p_e->getType() == df::STEP_EVENT) { world_manager.objectsInBox(sense_box); – StateMachine Update() calls State Execute() of derived machine.Update(); // Update state machine. df::ObjectListIterator oi(&objs_in_box); return 1; class for (oi.first(); !oi.isDone(); oi.next()) { } df::Object *p_temp = i.currentObject(); … if (p_temp -> getType() == "Hero") • e.g., StateWander calls Mummy senseHero() return true; // Senses Hero! } – If so, tell state machine to change state } return false; // Doesn’t sense Hero. – Otherwise, execute state action (e.g., Mummy wanders) } 4

  5. 3/24/2016 Finite State Machines Summary Pros Cons Simplicity � low entry level Predictability � can make for • • Simplicity � quick to design, easy-to-exploit opponent • implement and execute Complexity � Large FSMs Predictability � allows for easy • • difficult to manage and testing maintain ("spaghetti-factor“) Well-proven technique with lots of • examples Inflexibility � All states, • Flexibility � many ways to • transitions and conditions implement need to be known up front Easy to transfer from abstract • representation to coded and be well defined implementation Inflexibility � conditions for • Low processor overhead � only • transitions are rigid the code for current state needs to run, well suited to games Easy to tell reachability of state • 5

Recommend


More recommend