State Driven Agents CIS 479/579 Bruce R. Maxim UM-Dearborn 3/24/2016 1 Buckland Software • The executables and source code available http://www.wordware.com/files/ai The Boost library is available from http://www.boost.org/ • The Visual C++ environment need to be configured to compile the source code by setting the appropriate paths 3/24/2016 2 Paths • Include file paths C:\boost C:\AI_Source\Common C:\AI_Source\Common\lua-5.0\include C:\AI_Source\Common\laubind • Source file paths C:\AI_Source\Common C:\AI_Source\Common\lua-5.0 C:\AI_Source\Common\laubind • Library file paths C:\AI_Source\Common\lua-5.0\lib 3/24/2016 3 FSM Agent Advantages • • • • Quick design and simple to code Easy to debug Low computational overhead Intuitive so they make sense to domain experts • Flexible, easy for programmers to tweak to modify behaviors 3/24/2016 4 FSM State Examples • Pacman ghosts – evade, chase • Quake bots – find armor, find health, seek cover, run away • FIFA soccer players – strike, dribble, chase ball, mark player • NPC’s in real time strategy games – move to position, patrol, follow path 3/24/2016 5 Switch Implementation - 1 • Define an enumerated type with the state names enum StateType(RunAway, Patrol, Attack); • Then define method that manages the transitions void Agent::Update(StateType CurrentState) { switch (CurrentState) { case Runaway: EvadeEnemy( ); if (Safe( )) ChangeState(Patrol); break; … 3/24/2016 6 Switch Implementation - 2 • This works OK for simple FSM’s • Becomes overly complicated for FSM’s with lots of states and transitions • Requires recompilation if states are changed • Not easy to have simultaneous behaviors implemented (run and shoot) without defining lots of states 3/24/2016 7 State Transition Table -1 Current State Condition State Transition Runaway Safe Patrol Attack Weaker than enemy Runaway Patrol Threatened and stronger than enemy Attack Patrol Threatened and weaker than enemy Runaway 3/24/2016 8 State Transition Table - 2 • Agent queries table as needed • Table can stored in file and edited without recompiling the program • Each state can be modeled as a separate objects or functions called by the agent • Fairly easy to extend and modify 3/24/2016 9 State Design Pattern - 1 • The state transition rules can be embedded in the states themselves • All states share a common interface using a pure virtual class class State { public: virtual void Execute(Troll* troll) = 0; } 3/24/2016 10 State Design Pattern - 2 class Troll { State* m_pCurrentState; public: void Update() { m_pCurrentState->Execute(this); } void ChangeState(const State* pNewState) { delete m_pCurrentState; m_pCurrentState = pNewState; } } 3/24/2016 11 State Design Pattern - 3 class State_Runaway : public State { public: void Execute(Troll* troll) { if (troll->isSafe()) troll->ChangeState(new State_Sleep()); else troll->MoveAwayFromEnemy(); } } 3/24/2016 12 State Design Pattern - 4 class State_Sleep : public State { public: void Execute(Troll* troll) { if (troll->isThreatned()) troll->ChangeState(new State_RunAway()); else troll->Snore(); } } 3/24/2016 13 West World Miner States pockets full EnterMineDigForGold thirsty not thirsty not wealthy VisitBankDepositGold QuenchThirstSaloon rested wealthy enough GoHomeSleep 3/24/2016 14 Classes • All West World inhabitants are derived from the base class BaseGameEntity • Each entity will be assigned a unique identifier • The Miner class is an example of one such class • The State class is the base abstract class and each of the four Miner states needs its own class definition 3/24/2016 15 Reusable Classes • The State base class and the Miner owned classes would be more easily reused if were templates • Creating a StateMachine class with ways of tracking the Miner’s current, previous, and global states gives the FSM a crude memory to allow more complex (context sensitive) behaviors 3/24/2016 16 Adding New NPC • Elsa only visits two states VisitBathroom (1 chance in 10) or DoHouseWork • This makes use of the template version of the State class and required the definition of a new global state WifeGlobalState to deal with the bathroom visits • This requires adding classes MinersWife and MinersWifeOwnedStates 3/24/2016 17 Adding NPC Communication • Good games make use of event driven architectures • When events occur they are broadcast to other game objects who are programmed to react to the event or ignore it • Intelligent game agents can send messages to each other to allow cooperative behaviors 3/24/2016 18 Telegram Structure struct Telegram { //the entity that sent this telegram int Sender; //the entity that is to receive this telegram int Receiver; //the message itself. These are all enumerated in the file //"MessageTypes.h" int Msg; //If a delay is necessary this field is stamped with the time //the message should be dispatched. double DispatchTime; //any additional information that may accompany the message void* ExtraInfo; // constructors not shown here } 3/24/2016 19 Message Types #include <string> enum message_type { Msg_HiHoneyImHome, Msg_StewReady, }; inline std::string MsgToStr(int msg) { switch (msg) { case 1: return "HiHoneyImHome"; case 2: return "StewReady"; default: return "Not recognized!"; } } 3/24/2016 20 Elsa’s New States CookStew 1 chance in 10 Previous state Delayed message to self “Stew Ready” VisitBathroom 1 chance in 10 Receive “honey I’m home” previous state DoHouseWork 3/24/2016 21 Message Management • Creation, dispatch, and management of telegrams is handled by the class MessageDispatcher • The method DispatchMessage is used by every agent to send a message to entity with a known ID • The database of ID’s are managed by the class EntityManager 3/24/2016 22 Use Priority Queue • Telegrams with delays are store in a priority queue ordered by their Time Stamp data • Telegrams without delays (e.g. “I just shot you with my crossbow”) are sent right away • The front queue message is removed long with any unprocessed expired telegrams 3/24/2016 23 FSM Changes • The BaseEntity class needs to be modified (add HandleMessage) so that any derived class can receive messages • The State class needs to be modified so that BaseEntity states can choose to accept and handle messages (add OnMessage method) • The StateMachine class needs its own version of HandleMessage 3/24/2016 24 Elsa Cooks Dinner • Miner enters shack and sends “honey I’m home” message • Elsa receives “honey I’m home” and changes state to CookStew • Elsa puts Stew in oven and sends delayed message “Stew ready” • Elsa receives “Stew ready”, takes out stew, and sends Miner “Dinner ready” message • Miner receives “Dinner ready” and changes state to EatStew 3/24/2016 25 What happens? • In between messages the NPC’s are free to respond to all state appropriate inputs • This may means that the Miner has left the building before receiving the “Dinner ready” message • Sometimes you need two FSM’s working in parallel (one for character movement and one for character’s weapon) • Sometimes you need nested state machines (aka hierarchical FSM’s) 3/24/2016 26