FSM有限状态机

这次给大家分享一个简单的有限状态机,相信你看了我这篇博客会马上理解和使用,好了废话不多说了先上一张整体的架构图:

接下来就是代码的实现:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 角色有限状态机抽象基类.
/// </summary>
public abstract class RoleStateAbstract{

    /// <summary>
    /// 当前有限状态机管理器.
    /// </summary>
    public RoleFSMMgr CurrRoleFSMMgr { get; private set; }

    /// <summary>
    /// 当前动画状态片段信息.
    /// </summary>
    public AnimatorStateInfo currAnimatorStateInfo { get; set; }

    /// <summary>
    /// 构造函数.
    /// </summary>
    public RoleStateAbstract(RoleFSMMgr roleFSMMgr)
    {
        CurrRoleFSMMgr = roleFSMMgr;
    }

    /// <summary>
    /// 进入状态.
    /// </summary>
    public virtual void OnEnter() { }


    /// <summary>
    /// 执行状态.
    /// </summary>
    public virtual void OnUpdate() { }



    /// <summary>
    /// 离开状态.
    /// </summary>
    public virtual void OnExit() { }
	
}

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 角色待机状态.
/// </summary>
public class RoleStateIdle : RoleStateAbstract {

    public RoleStateIdle(RoleFSMMgr roleFSMMgr) : base(roleFSMMgr)
    {

    }

    /// <summary>
    /// 实现基类  进入状态方法.
    /// </summary>
    public override void OnEnter()
    {
        base.OnEnter();
        CurrRoleFSMMgr.CurrRoleCtrl._Animator.SetBool(ToAnimatorCondition.ToIdleNormal.ToString(),true);
        
    }

    /// <summary>
    /// 实现基类  执行状态方法.
    /// </summary>
    public override void OnUpdate()
    {
        base.OnUpdate();
        currAnimatorStateInfo = CurrRoleFSMMgr.CurrRoleCtrl._Animator.GetCurrentAnimatorStateInfo(0);
        if (currAnimatorStateInfo.IsName(RoleAnimatorName.Idle_Normal.ToString()))
        {
            CurrRoleFSMMgr.CurrRoleCtrl._Animator.SetInteger(ToAnimatorCondition.CurrState.ToString(), (int)RoleState.Idle);
        }
    }

    /// <summary>
    /// 实现基类  离开状态方法.
    /// </summary>
    public override void OnExit()
    {
        base.OnExit();
        CurrRoleFSMMgr.CurrRoleCtrl._Animator.SetBool(ToAnimatorCondition.ToIdleNormal.ToString(), false);
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 角色跑状态.
/// </summary>
public class RoleStateRun : RoleStateAbstract
{

    public RoleStateRun(RoleFSMMgr roleFSMMgr) : base(roleFSMMgr)
    {

    }

    /// <summary>
    /// 实现基类  进入状态方法.
    /// </summary>
    public override void OnEnter()
    {
        base.OnEnter();
        CurrRoleFSMMgr.CurrRoleCtrl._Animator.SetBool(ToAnimatorCondition.ToRun.ToString(), true);

    }

    /// <summary>
    /// 实现基类  执行状态方法.
    /// </summary>
    public override void OnUpdate()
    {
        base.OnUpdate();
        currAnimatorStateInfo = CurrRoleFSMMgr.CurrRoleCtrl._Animator.GetCurrentAnimatorStateInfo(0);
        if (currAnimatorStateInfo.IsName(RoleAnimatorName.Run.ToString()))
        {
            CurrRoleFSMMgr.CurrRoleCtrl._Animator.SetInteger(ToAnimatorCondition.CurrState.ToString(), (int)RoleState.Run);
        }
    }

    /// <summary>
    /// 实现基类  离开状态方法.
    /// </summary>
    public override void OnExit()
    {
        base.OnExit();
        CurrRoleFSMMgr.CurrRoleCtrl._Animator.SetBool(ToAnimatorCondition.ToRun.ToString(), false);
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 角色攻击状态.
/// </summary>
public class RoleStateAttack : RoleStateAbstract
{
    public RoleStateAttack(RoleFSMMgr roleFSMMgr) : base(roleFSMMgr)
    {

    }

    /// <summary>
    /// 实现基类  进入状态方法.
    /// </summary>
    public override void OnEnter()
    {
        base.OnEnter();
        CurrRoleFSMMgr.CurrRoleCtrl._Animator.SetInteger(ToAnimatorCondition.ToPhyAttack.ToString(), 1);

    }

    /// <summary>
    /// 实现基类  执行状态方法.
    /// </summary>
    public override void OnUpdate()
    {
        base.OnUpdate();
        currAnimatorStateInfo = CurrRoleFSMMgr.CurrRoleCtrl._Animator.GetCurrentAnimatorStateInfo(0);
        if (currAnimatorStateInfo.IsName(RoleAnimatorName.PhyAttack1.ToString()))
        {
            CurrRoleFSMMgr.CurrRoleCtrl._Animator.SetInteger(ToAnimatorCondition.CurrState.ToString(), (int)RoleState.Attack);

            //如果动画已经播放过一次  就切换到待机.
            if (currAnimatorStateInfo.normalizedTime > 1)
            {
                CurrRoleFSMMgr.CurrRoleCtrl.ToIdle();
            }
        }
    }

    /// <summary>
    /// 实现基类  离开状态方法.
    /// </summary>
    public override void OnExit()
    {
        base.OnExit();
        CurrRoleFSMMgr.CurrRoleCtrl._Animator.SetInteger(ToAnimatorCondition.ToPhyAttack.ToString(), 0);
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 角色死亡状态.
/// </summary>
public class RoleStateDie : RoleStateAbstract
{

    public RoleStateDie(RoleFSMMgr roleFSMMgr) : base(roleFSMMgr)
    {

    }

    /// <summary>
    /// 实现基类  进入状态方法.
    /// </summary>
    public override void OnEnter()
    {
        base.OnEnter();
        CurrRoleFSMMgr.CurrRoleCtrl._Animator.SetBool(ToAnimatorCondition.ToDie.ToString(), true);

    }

    /// <summary>
    /// 实现基类  执行状态方法.
    /// </summary>
    public override void OnUpdate()
    {
        base.OnUpdate();
        currAnimatorStateInfo = CurrRoleFSMMgr.CurrRoleCtrl._Animator.GetCurrentAnimatorStateInfo(0);
        if (currAnimatorStateInfo.IsName(RoleAnimatorName.Die.ToString()))
        {
            CurrRoleFSMMgr.CurrRoleCtrl._Animator.SetInteger(ToAnimatorCondition.CurrState.ToString(), (int)RoleState.Die);
        }
    }

    /// <summary>
    /// 实现基类  离开状态方法.
    /// </summary>
    public override void OnExit()
    {
        base.OnExit();
        CurrRoleFSMMgr.CurrRoleCtrl._Animator.SetBool(ToAnimatorCondition.ToDie.ToString(), false);
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 角色状态机管理器.
/// </summary>
public class RoleFSMMgr{

	
    /// <summary>
    /// 当前角色控制器.
    /// </summary>
    public RoleCtrl CurrRoleCtrl { get; private set; }


    /// <summary>
    /// 当前角色状态枚举.
    /// </summary>
    public RoleState currRoleStateEmun { get; private set; }

    /// <summary>
    /// 当前角色状态.
    /// </summary>
    private RoleStateAbstract currRoleState = null;


    private Dictionary<RoleState, RoleStateAbstract> roleStateDic;


    /// <summary>
    /// 构造函数.
    /// </summary>
    public RoleFSMMgr(RoleCtrl currRoleCtrl)
    {
        CurrRoleCtrl = currRoleCtrl;

        roleStateDic = new Dictionary<RoleState, RoleStateAbstract>();
        roleStateDic[RoleState.Idle] = new RoleStateIdle(this);
        roleStateDic[RoleState.Run] = new RoleStateRun(this);
        roleStateDic[RoleState.Hurt] = new RoleStateHurt(this);
        roleStateDic[RoleState.Attack] = new RoleStateAttack(this);
        roleStateDic[RoleState.Die] = new RoleStateDie(this);

        if (roleStateDic.ContainsKey(currRoleStateEmun))
        {
            currRoleState = roleStateDic[currRoleStateEmun];
        }
    }

    /// <summary>
    /// 每帧执行.
    /// </summary>
    public void OnUpdate()
    {
        if (currRoleState != null)
        {
            currRoleState.OnUpdate();
        }
        
    }
    /// <summary>
    /// 切换状态.
    /// </summary>
    /// <param name="newState"></param>
    public void ChangeState(RoleState newState)
    {
        if (currRoleStateEmun == newState) return;//如果相等直接返回  不需要重复执行同一个状态.

        //调用以前状态的离开方法.
        if (currRoleState != null)
        {
            currRoleState.OnExit();
        }
        //更改当前状态枚举.
        currRoleStateEmun = newState;

        //更改当前状态.
        currRoleState = roleStateDic[newState];

        //新状态执行进入方法.
        currRoleState.OnEnter();
    }
}

#region 角色状态
/// <summary>
/// 角色状态.
/// </summary>
public enum RoleState
{
    /// <summary>
    /// 未设置.
    /// </summary>
    None=0,
    /// <summary>
    /// 待机.
    /// </summary>
    Idle=1,

    /// <summary>
    /// 跑.
    /// </summary>
    Run=2,

    /// <summary>
    /// 攻击.
    /// </summary>
    Attack=3,

    /// <summary>
    /// 受伤.
    /// </summary>
    Hurt=4,

    /// <summary>
    /// 死亡.
    /// </summary>
    Die=5
}

#endregion


#region 角色动画名字.
/// <summary>
/// 角色动画名字.
/// </summary>
public enum RoleAnimatorName
{
    Idle_Normal,
    Idle_Fight,
    Run,
    Die,
    Hurt,
    PhyAttack1,
    PhyAttack2,
    PhyAttack3
}
#endregion


#region 角色动画条件.

/// <summary>
/// 角色动画条件.
/// </summary>
public enum ToAnimatorCondition
{
    ToIdleNormal,
    ToIdleFight,
    ToRun,
    ToDie,
    ToHurt,
    ToPhyAttack,
    CurrState
}
#endregion
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 角色控制器.
/// </summary>
public class RoleCtrl : MonoBehaviour {

    /// <summary>
    /// 角色动画组件.
    /// </summary>
    public Animator _Animator;

    /// <summary>
    /// 当前角色有限状态机管理器.
    /// </summary>
    public RoleFSMMgr currRoleFSMMgr = null;


    private void Start()
    {
        currRoleFSMMgr = new RoleFSMMgr(this);
    }


    private void Update()
    {
        
        if (currRoleFSMMgr != null)
        {
            currRoleFSMMgr.OnUpdate();//实时更新状态.
        }

        if (Input.GetKeyDown(KeyCode.Alpha0))
        {
            ToIdle();
        }else if (Input.GetKeyDown(KeyCode.Alpha1))
        {
            ToRun();
        }
        else if (Input.GetKeyDown(KeyCode.Alpha2))
        {
            ToAttack();
        }
        else if (Input.GetKeyDown(KeyCode.Alpha3))
        {
            ToHurt();
        }
        else if (Input.GetKeyDown(KeyCode.Alpha4))
        {
            ToDie();
        }
    }


    #region 角色操作方法.

    /// <summary>
    /// 切换到跑.
    /// </summary>
    public void ToRun()
    {
        currRoleFSMMgr.ChangeState(RoleState.Run);
    }
    /// <summary>
    /// 切换到攻击.
    /// </summary>
    public void ToAttack()
    {
        currRoleFSMMgr.ChangeState(RoleState.Attack);
    }
    /// <summary>
    /// 切换到受伤.
    /// </summary>
    public void ToHurt()
    {
        currRoleFSMMgr.ChangeState(RoleState.Hurt);
    }
    /// <summary>
    /// 切换到待机.
    /// </summary>
    public void ToIdle()
    {
        currRoleFSMMgr.ChangeState(RoleState.Idle);
    }
    /// <summary>
    /// 切换到死亡.
    /// </summary>
    public void ToDie()
    {
        currRoleFSMMgr.ChangeState(RoleState.Die);
    }

    #endregion
}

项目工程源码地址:链接: https://pan.baidu.com/s/1jWag6DFVpSfw36rBet1xSQ 提取码: cxvw 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值