Unity动作游戏动作控制之状态机编写

我们先看下我们状态机的流程图:

状态机机构图

如我们所知。动作游戏都有很多角色。而每个角色动作也有多少。也不可能用一个脚本控制所有的角色。所以肯定会有很多脚本。这样我们写状态机将我们的工作变简单并且更加科学就很有必要了。

今天我们就来看下状态机怎么写。

状态机一般分为两部分 1.状态总管理 2.状态机接口

再给大家画个状态机的流程图

状态机流程图

 

好吧。我们上代码:

状态机接口类 IState.cs

 

/// <summary>
/// 转台接口
/// </summary>
public interface IState
{
    /// <summary>
    /// 获取状态ID
    /// </summary>
    /// <returns></returns>
    int GetStateID();

    /// <summary>
    /// 进入状态回调此方法
    /// </summary>
    /// <param name="stateMachine">控制此状态的状态机</param>
    /// <param name="prevState">进入此状态的前状态</param>
    void OnEnter(GameStateMachine stateMachine, IState prevState, object param1, object param2);

    /// <summary>
    /// 离开状态时回调此方法
    /// </summary>
    /// <param name="nextState">离开此状态后的下一状态</param>
    void OnLeave(IState nextState, object param1, object param2);

    /// <summary>
    /// 每帧的OnUpdate方法回调
    /// </summary>
    void OnUpdate();

    /// <summary>
    /// 每帧的FixedUpdate回调
    /// </summary>
    void OnFixedUpdate();

    /// <summary>
    /// 每帧的LateUpdate回调
    /// </summary>
    void OnLateUpdate();
}

 状态机管理脚本 GameStateMachine.cs

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

/// <summary>
/// 状态机管理脚本
/// </summary>
public class GameStateMachine 
{
    /// <summary>
    /// 存储所有注册进来的状态。key是状态ID,value是状态对象
    /// </summary>
    private Dictionary<int, IState> m_dictState;
    /// <summary>
    /// 当前运行的状态
    /// </summary>
    private IState m_curState;

    public GameStateMachine()
    {
        m_curState = null;
        m_dictState = new Dictionary<int, IState>();
    }

    /// <summary>
    /// 注册一个状态
    /// </summary>
    /// <param name="state">要注册的状态</param>
    /// <returns>成功返回true,如果此状态ID已存在或状态为NULL,则返回false</returns>
    public bool RegistState(IState state)
    {
        if (null == state)
        {
            Debug.LogWarning("StateMachine::RegistState->state is null");
            return false;
        }

        if (m_dictState.ContainsKey(state.GetStateID()))
        {
            Debug.LogWarning("StateMachine::RegistState->state had exist! state id=" + state.GetStateID());
            return false;
        }

        m_dictState[state.GetStateID()] = state;

        return true;
    }

    /// <summary>
    /// 尝试获取一个状态
    /// </summary>
    /// <param name="iStateId"></param>
    /// <returns></returns>
    public IState GetState(int iStateId)
    {
        IState ret = null;
        m_dictState.TryGetValue(iStateId, out ret);
        return ret;
    }

    /// <summary>
    /// 停止当前正在运行的状态, 切换到空状态
    /// </summary>
    public void StopState(object param1, object param2)
    {
        if (null == m_curState)
        {
            return;
        }

        m_curState.OnLeave(null, param1, param2);

        m_curState = null;
    }

    /// <summary>
    /// 取消状态的注册
    /// </summary>
    /// <param name="iStateID">要取消的状态ID</param>
    /// <returns>如果找不到状态或状态正在运行,则会返回false</returns>
    public bool CancelState(int iStateID)
    {
        if (!m_dictState.ContainsKey(iStateID))
        {
            return false;
        }

        if (null != m_curState && m_curState.GetStateID() == iStateID)
        {
            return false;
        }

        return m_dictState.Remove(iStateID);
    }

    public delegate void BetweenSwitchState(IState from, IState to, object param1, object param2);

    /// <summary>
    /// 在切换状态之间回调
    /// </summary>
    public BetweenSwitchState BetweenSwitchStateCallBack { get; set; }

    /// <summary>
    /// 切换状态
    /// </summary>
    /// <param name="iNewStateID">要切换的新状态</param>
    /// <returns>如果找不到新的状态,或者新旧状态一样,返回false</returns>
    public bool SwitchState(int iNewStateID, object param1, object param2)
    {
        //状态一样,不做转换//
        if (null != m_curState && m_curState.GetStateID() == iNewStateID)
        {
            return false;
        }

        IState newState = null;
        m_dictState.TryGetValue(iNewStateID, out newState);
        if (null == newState)
        {
            return false;
        }

        IState oldState = m_curState;

        if (null != oldState)
        {
            oldState.OnLeave(newState, param1, param2);
        }

        if (BetweenSwitchStateCallBack != null) BetweenSwitchStateCallBack(oldState, newState, param1, param2);

        m_curState = newState;

        if (null != newState)
        {
            newState.OnEnter(this, oldState, param1, param2);
        }

        return true;
    }

    /// <summary>
    /// 获取当前状态
    /// </summary>
    /// <returns></returns>
    public IState GetCurState()
    {
        return m_curState;
    }

    /// <summary>
    /// 获取当前状态ID
    /// </summary>
    /// <returns></returns>
    public int GetCurStateID()
    {
        IState state = GetCurState();
        return (null == state) ? 0 : state.GetStateID();
    }

    /// <summary>
    /// 判断当前是否在某个状态下
    /// </summary>
    /// <param name="iStateID"></param>
    /// <returns></returns>
    public bool IsInState(int iStateID)
    {
        if (null == m_curState)
        {
            return false;
        }

        return m_curState.GetStateID() == iStateID;
    }

    /// <summary>
    /// 每帧的更新回调
    /// </summary>
    public void OnUpdate()
    {
        if (null != m_curState)
        {
            m_curState.OnUpdate();
        }
    }

    /// <summary>
    /// 每帧的更新回调
    /// </summary>
    public void OnFixedUpdate()
    {
        if (null != m_curState)
        {
            m_curState.OnFixedUpdate();
        }
    }

    /// <summary>
    /// 每帧的更新回调
    /// </summary>
    public void OnLateUpdate()
    {
        if (null != m_curState)
        {
            m_curState.OnLateUpdate();
        }
    }
}

然后我们来写角色控制脚本。如下

Player.cs

 

using UnityEngine;
using System.Collections;

public class Player : MonoBehaviour {

    GameStateMachine playerGameStateMachine = new GameStateMachine();
    public enum PlayerState
    {
        /// <summary>
        /// 待机
        /// </summary>
        Walk = 0,

        /// <summary>
        /// 攻击
        /// </summary>
        Attack = 1,
        /// <summary>
        /// 暴涨
        /// </summary>
        Jump = 2,
    }

    void Awake() 
    {
        //注册所有状态//
        playerGameStateMachine.RegistState(new PlayerWalkState(this));
        playerGameStateMachine.RegistState(new PlayerAttackState(this));
        playerGameStateMachine.RegistState(new PlayerJumpState(this)); 

        playerGameStateMachine.SwitchState((int)PlayerState.Walk, null, null);
    }
	
    void Update() 
    {
        if (playerGameStateMachine.GetCurState() != null)
        {
            currentstate = (PlayerState)playerGameStateMachine.GetCurStateID();
        }
        playerGameStateMachine.OnUpdate();
    }

    void FixedUpdate()
    {
        playerGameStateMachine.OnFixedUpdate();
    }

    void LateUpdate()
    {
        playerGameStateMachine.OnLateUpdate();
    }

    private PlayerState currentstate = PlayerState.Walk;

    void OnGUI()
    {
        if(GUI.Button(new Rect(0,0,150,50),"切换成等待状态"))
        {
            playerGameStateMachine.SwitchState((int)PlayerState.Walk, null, null);
        }
        if (GUI.Button(new Rect(200,0, 150, 50), "切换成攻击状态"))
        {
            playerGameStateMachine.SwitchState((int)PlayerState.Attack, null, null);
        }
        if (GUI.Button(new Rect(400, 0, 150, 50), "切换成暴涨状态"))
        {
            playerGameStateMachine.SwitchState((int)PlayerState.Jump, null, null);
        }
        GUI.Label(new Rect(60, 60, 300, 200), "State:"+currentstate.ToString());
    }
}

 PlayerWalkState.cs

11

using UnityEngine;
using System.Collections;

public class PlayerWalkState : IState
{
    Player m_Player = null;
    public PlayerWalkState(Player player)
    {
        m_Player = player;
    }
    #region IState 成员

    public int GetStateID()
    {
        return (int)Player.PlayerState.Walk;
    }

    public void OnEnter(GameStateMachine stateMachine, IState prevState, object param1, object param2)
    {
        m_Player.gameObject.GetComponent<Animation>().Play("zombie_walk");
        Debug.Log("进入待机状态 上次的状态为 :" + prevState);
    }

    public void OnLeave(IState nextState, object param1, object param2)
    {
        Debug.Log("退出待机状态 下次的状态为 :" + nextState);
    }

    public void OnUpdate()
    {
       

    }

    public void OnFixedUpdate()
    {
    }

    public void OnLateUpdate()
    {
    }

    #endregion
}

PlayerAttackState.cs

using UnityEngine;
using System.Collections;

public class PlayerAttackState : IState
{
    Player m_Player = null;
    public PlayerAttackState(Player player)
    {
        m_Player = player;
    }
    #region IState 成员

    public int GetStateID()
    {
        return (int)Player.PlayerState.Attack;
    }

    public void OnEnter(GameStateMachine stateMachine, IState prevState, object param1, object param2)
    {
        m_Player.gameObject.GetComponent<Animation>().Play("zombie_attack");
        Debug.Log("攻击状态 上次的状态为 :" + prevState);
    }

    public void OnLeave(IState nextState, object param1, object param2)
    {
        Debug.Log("退出行走状态 下次的状态为 :" + nextState);
    }

    public void OnUpdate()
    {
        
    }

    public void OnFixedUpdate()
    {
    }

    public void OnLateUpdate()
    {
    }

    #endregion
}

 PlayerJumpState.cs

using UnityEngine;
using System.Collections;

public class PlayerJumpState : IState 
{

	Player m_Player = null;
    public PlayerJumpState(Player player)
    {
        m_Player = player;
    }
    #region IState 成员

    public int GetStateID()
    {
        return (int)Player.PlayerState.Jump;
    }

    public void OnEnter(GameStateMachine stateMachine, IState prevState, object param1, object param2)
    {
        m_Player.gameObject.GetComponent<Animation>().Play("zombie_jump");
        Debug.Log("暴涨状态 上次的状态为 :" + prevState);
    }

    public void OnLeave(IState nextState, object param1, object param2)
    {
        Debug.Log("退出暴涨状态 下次的状态为 :" + nextState);
    }

    public void OnUpdate()
    {
        
    }

    public void OnFixedUpdate()
    {
    }

    public void OnLateUpdate()
    {
    }

    #endregion
}

 效果图

1

下载地址

链接:http://pan.baidu.com/s/1kT3lV3D 密码:gyij

本文链接:

https://www.bobsong.net/839.html
1 + 2 =
快来做第一个评论的人吧~