Finite state machine
State machine
This was a deterministic finite state machine framework based on Chapter 3.1 of Game programming Gems 1 by Eric Dybsend. Therea is, classes and enums. Include them in your project and follow the explanations to get the FSM working properly. There ' s also a complete example script at the end of this page.
This is a deterministic finite state machine framework based on game programming Gems 1 of section 3.1. There are two classes and two enumerations. Put them in your project and follow the comment FSM to work. There is also a complete sample script later.
Transition enum: This enum contains the labels to the transitions so can be fired by the system. Don ' t change the first label, Nulltransition, as the Fsmsystem class uses it.
Conversion Enumeration: The enumeration contains the label conversions. Do not change the first label, Nulltransition, as the Fsmsystem class uses it.
Stateid enum: the The ID of the states the game May has. You could use references to the real states ' classes and using enums makes the system less susceptible to has code having Access to objects it isn't supposed to. All the states ' IDs should is placed here. Don ' t change the first label, Nullstateid, as the Fsmsystem class uses it.
Status ID Enumeration: this is the ID of the state that may be in the game. You can use the class to mark the true state, but using an enumeration should not cause the system to be affected too little to have code access to the object. All status IDs should be placed here. Do not change the first label, Nulltransition, as the Fsmsystem class uses it.
Fsmstate class: This class have a Dictionary with pairs (Transition-stateid) indicating which new state S2 the FSM should go to when a Tran Sition T is fired and the current state is S1. It has methods to add and delete pairs (Transition-stateid), a method to check which state to go to if a Transition is pas Sed to it. Methods is used in the example given to check which transition should be fired (Reason ()) and which action (s) (ACT ()) The gameobject that have the fsmstate attached should do. You don ' t has to use the this schema, but some kind of transition-action code must is used in your game.
state Machine State Class: This class has a dictionary (Dictionary) consisting of a pair (Transition-stateid) flag, when a transform t is not needed, the current state is the new state S2 that S1,FSM needs to reach, and. It has a pair of additions and deletions (Transition-stateid) methods to check if a transform is acting on an object and which state it is going to change to. The two methods used in the example are to check which changes should be eliminated (Reason ()) and What Action (Act ()) should be done with the Fsmstate object. You do not need to use this pattern, but you must use some type of conversion action (transition-action) code in your game.
Fsmsystem: The finite state machine class, each NPC, or gameobject in your game must has an in order To use the framework. It stores the NPC ' s states in a List, have methods to add and delete a state and a method to change the current state based On a transition passed to it (Performtransition ()). You can call the this method anywhere within your code, as in a collision test, or within Update () or fixedupdate ().
Fsmsystem: This is an alternate use frame for each game of NPC or object finite state machine class. Storing the state of an NPC in a list, there are methods for adding or deleting states, and methods for changing the current state based on a transform (Performtransition ()). You can call this method anywhere in the code, such as in a crash test (collision test), or in update () or Fixedupdate ().
C # templates
Using system;using system.collections;using system.collections.generic;using unityengine; /**a finite state machine System based on Chapter 3.1 of the Game programming Gems 1 by Eric Dybsand written by Roberto Cezar Bianchini, July how to Use:1. Place the labels for the transitions and the states of the finite state System in the corresponding enums. 2. Write new Class (es) inheriting from fsmstate and fill each one with pairs (transition-state). These pairs represent the state S2 the Fsmsystem should was if while being on state S1, a transition T is fired and stat e S1 have a transition from it to S2. Remember This is a deterministic FSM. You can ' t has one transition leading to the different states. Method Reason are used to determine which transition should are fired. Can write the code to fire transitions in another place, and leave this method empty if you feel it's more Appropria Te to your project. Method Act have the code to perform the actions the NPCs is Supposed do if it's on the This state. You can write the code for the Another place, and leave this method empty if you feel it's more appropriate t O your project. 3. Create a instance of Fsmsystem class and add the states to it. 4. Call Reason and ACT (or whichever methods-firing transitions and making the NPCs behave in your game) From your Update or Fixedupdate methods. Asynchronous transitions from Unity Engine, like Ontriggerenter, SendMessage, can also is used, just call the Method Perfo Rmtransition from your Fsmsystem instance and the correct Transition when the event occurs. The software is provided ' as is ', without WARRANTY of any KIND, EXPRESS OR implied, including and not LIMITED to the Warra Nties of merchantability, FITNESS for A particular PURPOSE and non-infringement. In NO EVENT shall the AUTHORS or COPYRIGHT holders is liable for any CLAIM, damages OR other liability, WHETHER in an ACTI On contract, TORT OR OTHERWISE, arising from, out OF OR in CONNECTION with the software or the if or other dealings in the software.*///<summary>///Place the lab Els for the transitions in this enum.///Don ' t change the first label, Nulltransition as Fsmsystem class uses it.///</ summary>public enum transition{nulltransition = 0,//Use this Transition to represent a non-existing Transition in Your system}///<summary>///Place the labels for the states in this enum.///Don ' t change the first label, NULLTR Ansition as Fsmsystem class uses it.///</summary>public enum stateid{nullstateid = 0,//Use this ID to Represe NT a non-existing state in your system}//<summary>///This class represents the states of the finite State system .//Each state have a Dictionary with pairs (transition-state) showing///which state the FSM should being if a transition is Fired while this state///are the current state.///Method Reason are used to determine which transition should be fired. Method Act has the CODe to perform the actions the NPCs are supposed do if it's on this state.///</summary>public abstract class fsmstate{ Protected Dictionary<transition, stateid> map = new dictionary<transition, stateid> (); protected Stateid Stateid; Public Stateid ID {get {return stateid;}} public void Addtransition (Transition trans, Stateid ID) {//Check if anyone of the. Args is invalid if (t Rans = = transition.nulltransition) {debug.logerror ("fsmstate error:nulltransition is not allowed for a Real transition "); Return } if (id = = Stateid.nullstateid) {debug.logerror ("fsmstate Error:nullstateid is not allowed fo R a real ID "); Return }//Since The deterministic FSM,//Check if the current transition was already inside the map if (map. ContainsKey (trans)) {Debug.logerror ("fsmstate error:state" + stateid.tostring () + "already has transition "+ trans. ToString () + "impossible to assign-another State"); Return } map. ADD (trans, id); }///<summary>//This method deletes a pair transition-state from this state ' s map. If the transition was isn't inside the state's map, an ERROR message is printed. </summary> public void Deletetransition (Transition trans) {//Check for Nulltransition if ( trans = = transition.nulltransition) {debug.logerror ("fsmstate error:nulltransition is not allowed"); Return }//Check If the pair is inside the map before deleting if (map. ContainsKey (trans)) {map. Remove (trans); Return } debug.logerror ("Fsmstate error:transition" + trans. ToString () + "passed to" + stateid.tostring () + "is not in the state ' s transition list"); }//<summary>//This method returns the new state the FSM should is if//this state receives a transition and/or </summary> public Stateid getoutputstate (Transition trans) {//Check if the map have this Transition if (map. ContainsKey (trans)) {return Map[trans]; } return Stateid.nullstateid; }///<summary>//This method was used to set up the state condition before entering it. It is called automatically by the Fsmsystem class before assigning it//to the current state. </summary> public virtual void dobeforeentering () {}///<summary>//This method was used to M Ake anything necessary, as reseting variables//Before the Fsmsystem changes to another one. It is called automatically///by the Fsmsystem before changing to a new state. </summary> public virtual void dobeforeleaving () {}///<summary>//This method decides If The State should transition to another in its list//NPC is a reference to the object that's controlled by this CL N/a </summary> public abstract void Reason (Gameobject player, Gameobject NPC); <summary>//This method controls the behavior of the NPCs in the game world. Every action, movement or communication the NPC does should be placed here//NPCs are a reference to the object tha T is controlled by this class///</summary> public abstract void Act (Gameobject player, Gameobject NPC); }//class Fsmstate//<summary>///Fsmsystem class represents the finite state machine class.///It have a List w ith the states the NPC have and methods to add,///delete a state, and to change the current state of the machine is on.///& Lt;/summary>public class fsmsystem{private list<fsmstate> states; The only-one can change the state of the FSM are by performing a transition//Don ' t change the CurrentStatedirectly private Stateid Currentstateid; Public Stateid Currentstateid {get {return currentstateid;}} Private Fsmstate CurrentState; Public Fsmstate CurrentState {get {return currentstate;}} Public Fsmsystem () {states = new list<fsmstate> (); }///<summary>//This method places new states inside the FSM,///prints an ERROR message if the St Ate was already inside the List. First State added are also the initial state. </summary> public void Addstate (Fsmstate s) {//Check for Null reference before deleting if (s = = null) {Debug.logerror ("FSM error:null reference is not allowed"); }//First state inserted are also the Initial state and//the state of the machine was in when the simulation B Egins if (states. Count = = 0) {states. ADD (s); CurrentState = s; Currentstateid = s.id; Return}//Add the state to the List if it's not a inside it foreach (Fsmstate State in states) { if (state.id = = s.id) {debug.logerror ("FSM error:impossible to add State" + s.id. ToString () + "because state has already been added"); Return }} states. ADD (s); }///<summary>//This method deletes a state from the FSM List if it exists,///prints an ERROR m Essage if the state is not on the List. </summary> public void deletestate (Stateid ID) {//Check for nullstate before deleting if ( id = = Stateid.nullstateid) {debug.logerror ("FSM Error:nullstateid is not allowed for a real state"); Return }//Search the List and delete the state if it's inside it foreach (Fsmstate State in states) { if (state.id = = ID) { States. Remove (state); Return }} debug.logerror ("FSM error:impossible to delete state" + ID.) ToString () + ". It wasn't on the list of States "); }///<summary>//This method tries to the state the FSM are in based on//the current state and The transition passed. If Current state////doesn ' t has a target state for the transition passed,///ERROR message is printed. </summary> public void Performtransition (Transition trans) {//Check for nulltransition before Cha Nging the current state if (trans = = Transition.nulltransition) {debug.logerror ("FSM error:null Transition isn't allowed for a real Transition "); Return }//Check If the CurrentState has the transition passed as argument Stateid id = Currentstate.getoutputsta Te (trans); if (id = = Stateid.nullstateid) {DEBUG.LOgerror ("FSM error:state" + currentstateid.tostring () + "does not has a target State" + " For transition "+ trans. ToString ()); Return }//Update the Currentstateid and currentstate Currentstateid = ID; foreach (Fsmstate state in states) {if (state.id = = Currentstateid) {//Do T He post processing of the state before setting the new one currentstate.dobeforeleaving (); CurrentState = State; Reset the state to its desired condition before it can reason or act currentstate.dobeforeentering (); Break }}}//Performtransition ()}//class Fsmsystem
C # Trial Example
Using system;using system.collections.generic;using system.text;using unityengine; [Requirecomponent (typeof (Rigidbody))]public class npccontrol:monobehaviour{public gameobject player; Public transform[] path; Private Fsmsystem FSM; public void Settransition (Transition t) {FSM. Performtransition (t); } public void Start () {MAKEFSM (); } public void Fixedupdate () {FSM. Currentstate.reason (player, gameobject); Fsm. Currentstate.act (player, gameobject); }//The NPC has both States:followpath and chaseplayer//If It's on the first state and Sawplayer transition is fired, it Changes to chaseplayer//If it's on chaseplayerstate and Lostplayer transition are fired, it returns to Followpath Priv ate void Makefsm () {followpathstate follow = new Followpathstate (path); Follow. Addtransition (Transition.sawplayer, Stateid.chasingplayer); Chaseplayerstate chase = new Chaseplayerstate (); Chase. Addtransition (Transition. Lostplayer, Stateid.followingpath); FSM = new Fsmsystem (); Fsm. Addstate (follow); Fsm. Addstate (Chase); }} public class followpathstate:fsmstate{private int currentwaypoint; Private transform[] waypoints; Public followpathstate (transform[] wp) {waypoints = WP; Currentwaypoint = 0; Stateid = Stateid.followingpath; } public override void Reason (Gameobject player, Gameobject NPCs) {//If the player passes less than mete Rs away in front of the NPC raycasthit hits; if (Physics.raycast (Npc.transform.position, Npc.transform.forward, out hit, 15F)) {if (Hit.transform.ga Meobject.tag = = "Player") NPC. Getcomponent<npccontrol> (). Settransition (Transition.sawplayer); }} public override void Act (Gameobject player, Gameobject NPC) {//Follow the path of waypoints//Find The direction of the current to point Vector3 vel = Npc.rigidbody.velocity; Vector3 movedir = waypoints[currentwaypoint].position-npc.transform.position; if (Movedir.magnitude < 1) {currentwaypoint++; if (Currentwaypoint >= waypoints. Length) {currentwaypoint = 0; }} else {vel = movedir.normalized * 10; Rotate towards the waypoint npc.transform.rotation = Quaternion.slerp (Npc.transform.rotation, Quaternion.lookrotation (Movedir), 5 * time.deltatime); Npc.transform.eulerAngles = new Vector3 (0, npc.transform.eulerangles.y, 0); }//Apply the Velocity npc.rigidbody.velocity = vel; }}//Followpathstate public class chaseplayerstate:fsmstate{public chaseplayerstate () {Stateid = Statei D.chasingplayer; } public override void Reason (gameobJect player, Gameobject NPC) {//If the player has gone-meters away from the NPC, Fire lostplayer Transition if (Vector3.distance (npc.transform.position, player.transform.position) >=) NPC. Getcomponent<npccontrol> (). Settransition (Transition.lostplayer); } public override void Act (Gameobject player, Gameobject NPC) {//Follow the path of waypoints//Find the D Irection of the player Vector3 vel = npc.rigidbody.velocity; Vector3 movedir = player.transform.position-npc.transform.position; Rotate towards the waypoint npc.transform.rotation = Quaternion.slerp (Npc.transform.rotation, Quaternion.lookrotation (Movedir), 5 * Time . deltatime); Npc.transform.eulerAngles = new Vector3 (0, npc.transform.eulerangles.y, 0); Vel = movedir.normalized * 10; Apply the new Velocity NPC. rigidbody.velocity = vel; }}//Chaseplayerstate
English Original address: Http://wiki.unity3d.com/index.php/Finite_State_Machine
-------translated from: wolf96
Unity3d Game AI Development state Machine (C # templates and examples)