一个实用的有限状态机FSM

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






猜你喜欢

转载自blog.csdn.net/Kelly59/article/details/80780313