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);
}
}