FSM定义:
一个有限状态机是一个设备,或者是一个设备模型,具有有限数量的状态,它可以在任何给定的时间根据输入进行操作,使得一个状态变换到另一个状态,或者是使一个输入或者一种行为的发生。一个有限状态机在任何瞬间只能处在一种状态。
它的优点:
1.编程快速简单,2.易于调试,3.很少的计算开销,4.直觉性,5.灵活性。
框架:
主要的两个类,RoleStateAbstract表示状态基类,RoleCtrl里面负责切换状态,最后需要一个RoleFSMMgr作为状态的控制器。
代码如下:
public class RoleStateAttack : RoleStateAbstract { //当前有限状态机 public RoleFSMMgr CurrentRoleCtrl{get;set;} public RoleStateAttack(RoleFSMMgr mgr):base(mgr) { CurrentRoleCtrl = mgr; } //进入状态 public override void OnEnter() { base.OnEnter(); CurrentRoleCtrl.CurrRoleCtrl.m_Animator.SetInteger (ToAnimatorCondition.ToPhyAttack.ToString(),1); } //执行状态 public override void OnUpdate() { base.OnUpdate(); CurrStateInfo = CurrentRoleCtrl.CurrRoleCtrl.m_Animator.GetCurrentAnimatorStateInfo (0); if (CurrStateInfo.IsName("PhyAttack1")) { CurrentRoleCtrl.CurrRoleCtrl.m_Animator.SetInteger (ToAnimatorCondition.CurrState.ToString(),(int)RoleState.Atack); if (CurrStateInfo.normalizedTime>1) { CurrentRoleCtrl.CurrRoleCtrl.ToIdle (); } } } //离开状态 public override void OnLeave() { base.OnLeave(); CurrentRoleCtrl.CurrRoleCtrl.m_Animator.SetInteger (ToAnimatorCondition.ToPhyAttack.ToString(), 0); } }
public abstract class RoleStateAbstract { //当前有限状态机 public RoleFSMMgr CurrentRoleCtrl{get;private set;} public AnimatorStateInfo CurrStateInfo; public RoleStateAbstract(RoleFSMMgr mgr) { CurrentRoleCtrl = mgr; } //进入状态 public virtual void OnEnter() { } //执行状态 public virtual void OnUpdate() { } //离开状态 public virtual void OnLeave() { } }
//攻击状态 public class RoleStateAttack : RoleStateAbstract { //当前有限状态机 public RoleFSMMgr CurrentRoleCtrl{get;set;} public RoleStateAttack(RoleFSMMgr mgr):base(mgr) { CurrentRoleCtrl = mgr; } //进入状态 public override void OnEnter() { CurrentRoleCtrl.CurrRoleCtrl.m_Animator.SetInteger ("ToPhyAttack",1); } //执行状态 public override void OnUpdate() { CurrStateInfo = CurrentRoleCtrl.CurrRoleCtrl.m_Animator.GetCurrentAnimatorStateInfo (0); if (CurrStateInfo.IsName("PhyAttack1")) { CurrentRoleCtrl.CurrRoleCtrl.m_Animator.SetInteger ("CurrState",4); if (CurrStateInfo.normalizedTime>1) { CurrentRoleCtrl.CurrRoleCtrl.ToIdle (); } } } //离开状态 public override void OnLeave() { CurrentRoleCtrl.CurrRoleCtrl.m_Animator.SetInteger ("ToPhyAttack",0); } }
//死亡状态 public class RoleStateDie : RoleStateAbstract { //当前有限状态机 public RoleFSMMgr CurrentRoleCtrl{get;private set;} public RoleStateDie(RoleFSMMgr mgr):base(mgr) { CurrentRoleCtrl = mgr; } //进入状态 public override void OnEnter() { CurrentRoleCtrl.CurrRoleCtrl.m_Animator.SetBool ("ToDie",true); } //执行状态 public override void OnUpdate() { CurrStateInfo = CurrentRoleCtrl.CurrRoleCtrl.m_Animator.GetCurrentAnimatorStateInfo (0); if (CurrStateInfo.IsName("Die")) { CurrentRoleCtrl.CurrRoleCtrl.m_Animator.SetInteger ("CurrState",6); } } //离开状态 public override void OnLeave() { CurrentRoleCtrl.CurrRoleCtrl.m_Animator.SetBool ("ToDie",false); } }
//受伤状态 public class RoleStateHurt : RoleStateAbstract { //当前有限状态机 public RoleFSMMgr CurrentRoleCtrl{get;private set;} public RoleStateHurt(RoleFSMMgr mgr):base(mgr) { CurrentRoleCtrl = mgr; } //进入状态 public override void OnEnter() { CurrentRoleCtrl.CurrRoleCtrl.m_Animator.SetBool ("ToHurt",true); } //执行状态 public override void OnUpdate() { CurrStateInfo = CurrentRoleCtrl.CurrRoleCtrl.m_Animator.GetCurrentAnimatorStateInfo (0); if (CurrStateInfo.IsName("Hurt")) { CurrentRoleCtrl.CurrRoleCtrl.m_Animator.SetInteger ("CurrState",5); if (CurrStateInfo.normalizedTime>1) { CurrentRoleCtrl.Change (RoleState.Idle); } } } //离开状态 public override void OnLeave() { CurrentRoleCtrl.CurrRoleCtrl.m_Animator.SetBool ("ToHurt",false); } }
//待机状态 public class RoleStateIdle : RoleStateAbstract { //当前有限状态机 public RoleFSMMgr CurrentRoleCtrl{get;private set;} public RoleStateIdle(RoleFSMMgr mgr):base(mgr) { CurrentRoleCtrl = mgr; } //进入状态 public override void OnEnter() { CurrentRoleCtrl.CurrRoleCtrl.m_Animator.SetBool ("ToIdleNormal",true); } //执行状态 public override void OnUpdate() { CurrStateInfo = CurrentRoleCtrl.CurrRoleCtrl.m_Animator.GetCurrentAnimatorStateInfo (0); if (CurrStateInfo.IsName("Idle_Normal")) { CurrentRoleCtrl.CurrRoleCtrl.m_Animator.SetInteger ("CurrState",1); } } //离开状态 public override void OnLeave() { CurrentRoleCtrl.CurrRoleCtrl.m_Animator.SetBool ("ToIdleNormal",false); } }
//跑步状态 public class RoleStateRun : RoleStateAbstract { //当前角色有限状态机 public RoleFSMMgr CurrentRoleCtrl{get;private set;} public RoleStateRun(RoleFSMMgr mgr):base(mgr) { CurrentRoleCtrl = mgr; } //进入状态 public override void OnEnter() { CurrentRoleCtrl.CurrRoleCtrl.m_Animator.SetBool ("ToRun",true); } //执行状态 public override void OnUpdate() { CurrStateInfo = CurrentRoleCtrl.CurrRoleCtrl.m_Animator.GetCurrentAnimatorStateInfo (0); if (CurrStateInfo.IsName ("Run")) { CurrentRoleCtrl.CurrRoleCtrl.m_Animator.SetInteger ("CurrState", 3); } else { CurrentRoleCtrl.CurrRoleCtrl.m_Animator.SetInteger ("CurrState", 0); } } //离开状态 public override void OnLeave() { CurrentRoleCtrl.CurrRoleCtrl.m_Animator.SetBool ("ToRun",false); } }
游戏中AnimatorController截图:
RoleCtrl代码是测试玩家移动脚本,如下:
public class RoleCtrl : MonoBehaviour { public static RoleCtrl Instance; //移动速度 [SerializeField] private float m_Speed = 10f; //目标点 public Vector3 TargetPos = Vector3.zero; //刚体 private CharacterController m_Chara; //动画 public Animator m_Animator; //当前有限状态机 private RoleFSMMgr m_FSM; void Awake() { Instance = this; } void Start() { m_Chara = GetComponent<CharacterController>(); m_FSM = new RoleFSMMgr (this); } void Update() { //执行状态 m_FSM.OnUpdate(); //鼠标点击玩家移动 if (Input.GetMouseButtonDown(0)) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (Physics.Raycast(ray,out hit)) { if (hit.collider.gameObject.name.Equals("Ground",System.StringComparison.CurrentCultureIgnoreCase)) { // m_TargetPos = hit.point; ToRun(hit.point); } } } //如果目标点不是原点 进行移动 if (TargetPos != Vector3.zero) { if (Vector3.Distance(TargetPos, transform.position) > 0.2f) { Vector3 direction = TargetPos - transform.position; direction = direction.normalized;//归一化 direction = direction * Time.deltaTime * m_Speed; transform.LookAt(new Vector3(TargetPos.x, transform.position.y, TargetPos.z)); m_Chara.Move(direction); } else { ToIdle(); } } } public void ToIdle() { m_FSM.Change (RoleState.Idle); } public void ToAttack() { m_FSM.Change (RoleState.Atack); } public void ToDie() { m_FSM.Change (RoleState.Die); } public void ToHurt() { m_FSM.Change (RoleState.Hurt); } public void ToRun(Vector3 targetPos) { TargetPos = targetPos; m_FSM.Change (RoleState.Run); } }