[Unity] (小新)角色控制之U3D状态机的编写

查看:4727 |回复:101 | 2015-7-5 01:05:47

您需要 登录 才可以下载或查看,没有账号?注册

x
本帖最后由 醉酒風 于 2019-5-13 22:17 编辑

转自小新的干货。很不错的~!
55.jpg
先简单介绍下状态机机的大概工作流程
1.png




一般格斗游戏都是有许多的角色,
肯定不可能一个脚本控制所有的角色。
所以每个角色肯定会有相应的角色控制脚本,
每个角色都会有很多个状态,那么自己编写个状态机肯定是很有必要的。
那么今天我就给大家分享个状态机玩玩,希望大家相互学习状态机
一般分为两部分 1.状态总管理 2.状态机接口
再给大家画个状态机的流程图




每个状态之间是互不影响的 都是靠状态机的管理所有的状态  
进入下一个状态 退出当前状态
好吧上代码
状态机接口类

IState.cs

  1. //////////////////////////////////////////////////////////////////////////
  2. /// Author: sheen
  3. /// Date: 2015-5-20 13:47:19
  4. /// Description: 状态接口
  5. //////////////////////////////////////////////////////////////////////////

  6. public interface IState
  7. {
  8.     /// <summary>
  9.     /// 获取状态ID
  10.     /// </summary>
  11.     /// <returns></returns>
  12.     int GetStateID();

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

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

  24.     /// <summary>
  25.     /// 每帧的OnUpdate方法回调
  26.     /// </summary>
  27.     void OnUpdate();

  28.     /// <summary>
  29.     /// 每帧的FixedUpdate回调
  30.     /// </summary>
  31.     void OnFixedUpdate();

  32.     /// <summary>
  33.     /// 每帧的LateUpdate回调
  34.     /// </summary>
  35.     void OnLateUpdate();
  36. }
点击此处复制文本


状态管理脚本
GameStateMachine.cs

  1. using UnityEngine;
  2. using System.Collections;

  3. //////////////////////////////////////////////////////////////////////////
  4. /// Author: sheen
  5. /// Date: 2015-5-20 13:46:51
  6. /// Description: 状态机
  7. //////////////////////////////////////////////////////////////////////////
  8. using System.Collections.Generic;
  9. using UnityEngine;

  10. public class GameStateMachine
  11. {
  12.     /// <summary>
  13.     /// 存储所有注册进来的状态。key是状态ID,value是状态对象
  14.     /// </summary>
  15.     private Dictionary<int, IState> m_dictState;
  16.     /// <summary>
  17.     /// 当前运行的状态
  18.     /// </summary>
  19.     private IState m_curState;

  20.     public GameStateMachine()
  21.     {
  22.         m_curState = null;
  23.         m_dictState = new Dictionary<int, IState>();
  24.     }

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

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

  42.         m_dictState[state.GetStateID()] = state;

  43.         return true;
  44.     }

  45.     /// <summary>
  46.     /// 尝试获取一个状态
  47.     /// </summary>
  48.     /// <param name="iStateId"></param>
  49.     /// <returns></returns>
  50.     public IState GetState(int iStateId)
  51.     {
  52.         IState ret = null;
  53.         m_dictState.TryGetValue(iStateId, out ret);
  54.         return ret;
  55.     }

  56.     /// <summary>
  57.     /// 停止当前正在运行的状态, 切换到空状态
  58.     /// </summary>
  59.     public void StopState(object param1, object param2)
  60.     {
  61.         if (null == m_curState)
  62.         {
  63.             return;
  64.         }

  65.         m_curState.OnLeave(null, param1, param2);

  66.         m_curState = null;
  67.     }

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

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

  83.         return m_dictState.Remove(iStateID);
  84.     }

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

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

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

  102.         IState newState = null;
  103.         m_dictState.TryGetValue(iNewStateID, out newState);
  104.         if (null == newState)
  105.         {
  106.             return false;
  107.         }

  108.         IState oldState = m_curState;

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

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

  114.         m_curState = newState;

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

  119.         return true;
  120.     }

  121.     /// <summary>
  122.     /// 获取当前状态
  123.     /// </summary>
  124.     /// <returns></returns>
  125.     public IState GetCurState()
  126.     {
  127.         return m_curState;
  128.     }

  129.     /// <summary>
  130.     /// 获取当前状态ID
  131.     /// </summary>
  132.     /// <returns></returns>
  133.     public int GetCurStateID()
  134.     {
  135.         IState state = GetCurState();
  136.         return (null == state) ? 0 : state.GetStateID();
  137.     }

  138.     /// <summary>
  139.     /// 判断当前是否在某个状态下
  140.     /// </summary>
  141.     /// <param name="iStateID"></param>
  142.     /// <returns></returns>
  143.     public bool IsInState(int iStateID)
  144.     {
  145.         if (null == m_curState)
  146.         {
  147.             return false;
  148.         }

  149.         return m_curState.GetStateID() == iStateID;
  150.     }

  151.     /// <summary>
  152.     /// 每帧的更新回调
  153.     /// </summary>
  154.     public void OnUpdate()
  155.     {
  156.         if (null != m_curState)
  157.         {
  158.             m_curState.OnUpdate();
  159.         }
  160.     }

  161.     /// <summary>
  162.     /// 每帧的更新回调
  163.     /// </summary>
  164.     public void OnFixedUpdate()
  165.     {
  166.         if (null != m_curState)
  167.         {
  168.             m_curState.OnFixedUpdate();
  169.         }
  170.     }

  171.     /// <summary>
  172.     /// 每帧的更新回调
  173.     /// </summary>
  174.     public void OnLateUpdate()
  175.     {
  176.         if (null != m_curState)
  177.         {
  178.             m_curState.OnLateUpdate();
  179.         }
  180.     }
  181. }
点击此处复制文本


接下来写个写个使用示例
先写角色控制脚本
player.cs

  1. using UnityEngine;
  2. using System.Collections;

  3. public class Player : MonoBehaviour {

  4.     GameStateMachine playerGameStateMachine = new GameStateMachine();
  5.     public enum PlayerState
  6.     {
  7.         /// <summary>
  8.         /// 待机
  9.         /// </summary>
  10.         Ide = 0,

  11.         /// <summary>
  12.         /// 行走
  13.         /// </summary>
  14.         Runing = 1,
  15.     }

  16.     void Awake()
  17.     {
  18.         //注册所有状态//
  19.         playerGameStateMachine.RegistState(new PlayerIdeState(this)); //注册待机状态//
  20.         playerGameStateMachine.RegistState(new PlayerRuningState(this)); //注册行走状态//


  21.         playerGameStateMachine.SwitchState((int)PlayerState.Ide, null, null);
  22.     }
  23.         
  24.     void Update()
  25.     {
  26.         if (playerGameStateMachine.GetCurState() != null)
  27.         {
  28.             currentstate = (PlayerState)playerGameStateMachine.GetCurStateID();
  29.         }
  30.         playerGameStateMachine.OnUpdate();
  31.     }

  32.     void FixedUpdate()
  33.     {
  34.         playerGameStateMachine.OnFixedUpdate();
  35.     }

  36.     void LateUpdate()
  37.     {
  38.         playerGameStateMachine.OnLateUpdate();
  39.     }

  40.     private PlayerState currentstate = PlayerState.Ide;

  41.     void OnGUI()
  42.     {
  43.         if(GUI.Button(new Rect(0,0,300,50),"切换成待机状态"))
  44.         {
  45.             playerGameStateMachine.SwitchState((int)PlayerState.Ide,null,null);
  46.         }
  47.         if (GUI.Button(new Rect(360,0, 300, 50), "切换成行走状态"))
  48.         {
  49.             playerGameStateMachine.SwitchState((int)PlayerState.Runing, null, null);
  50.         }
  51.         GUI.Label(new Rect(60, 60, 300, 200), "currntState:"+currentstate.ToString());
  52.     }
  53. }
点击此处复制文本


两个状态  待机  和 行走
待机PlayerIdeState.cs

  1. using UnityEngine;
  2. using System.Collections;

  3. public class PlayerIdeState : IState
  4. {
  5.     Player m_Player = null;
  6.     public PlayerIdeState (Player player)
  7.     {
  8.         m_Player = player;
  9.     }
  10.     #region IState 成员

  11.     public int GetStateID()
  12.     {
  13.         return (int)Player.PlayerState.Ide;
  14.     }

  15.     public void OnEnter(GameStateMachine stateMachine, IState prevState, object param1, object param2)
  16.     {
  17.         isUp = false;
  18.         m_Player.transform.position = UnityEngine.Vector3.zero;
  19.         Debug.Log("进入待机状态 上次的状态为 :" + prevState);
  20.     }

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

  25.     bool isUp = true;
  26.     public void OnUpdate()
  27.     {
  28.       
  29.         if (m_Player.transform.position.y >= 0.5)
  30.         {
  31.             isUp = false;
  32.         }
  33.         if (m_Player.transform.position.y <= 0)
  34.         {
  35.             isUp = true;
  36.         }
  37.         if (isUp)
  38.         {
  39.             m_Player.transform.position += new UnityEngine.Vector3(0.0f, 0.5f, 0.0f) * Time.deltaTime;
  40.         }
  41.         else
  42.         {
  43.             m_Player.transform.position -= new UnityEngine.Vector3(0.0f, 0.5f, 0.0f) * Time.deltaTime;
  44.         }

  45.     }

  46.     public void OnFixedUpdate()
  47.     {
  48.     }

  49.     public void OnLateUpdate()
  50.     {
  51.     }

  52.     #endregion
  53. }
点击此处复制文本


行走 PlayerRuningState.cs


  1. using UnityEngine;
  2. using System.Collections;

  3. public class PlayerRuningState : IState
  4. {
  5.     Player m_Player = null;
  6.     private bool isRight;
  7.     public PlayerRuningState(Player player)
  8.     {
  9.         m_Player = player;
  10.     }
  11.     #region IState 成员

  12.     public int GetStateID()
  13.     {
  14.         return (int)Player.PlayerState.Runing;
  15.     }

  16.     public void OnEnter(GameStateMachine stateMachine, IState prevState, object param1, object param2)
  17.     {
  18.         isRight = true;
  19.         m_Player.transform.position = UnityEngine.Vector3.zero;
  20.         Debug.Log("进入行走状态 上次的状态为 :" + prevState);
  21.     }

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

  26.     public void OnUpdate()
  27.     {
  28.         if (m_Player.transform.position.x >= 0.5)
  29.         {
  30.             isRight = false;
  31.         }
  32.         if (m_Player.transform.position.x <= 0)
  33.         {
  34.             isRight = true;
  35.         }
  36.         if (isRight)
  37.         {
  38.             m_Player.transform.position += new UnityEngine.Vector3(0.5f, 0.0f, 0.0f) * Time.deltaTime;
  39.         }
  40.         else
  41.         {
  42.             m_Player.transform.position -= new UnityEngine.Vector3(0.5f, 0, 0.0f) * Time.deltaTime;
  43.         }
  44.     }

  45.     public void OnFixedUpdate()
  46.     {
  47.     }

  48.     public void OnLateUpdate()
  49.     {
  50.     }

  51.     #endregion
  52. }
点击此处复制文本

最后看看效果

小新的个人博客 http://www.liyingxin.com

工程下载地址:回复可见~
尊敬的游客,如果您要查看本帖关注 或 回复可见内容请关注回复后刷新页面查看!

评分

参与人数 1元素币 +40 活跃度 +10 展开 理由
adminsss + 40 + 10 有范例!非常不错!

查看全部评分

2015-7-5 01:05:47  
 赞 赞 1

使用道具 登录

101个回答,把该问题分享到群,邀请大神一起回答。
2#
给力!元素有你更精彩
回复 收起回复
2015-7-5 01:20:54   回复
 赞 赞 1

使用道具 登录

3#
缘画 发表于 2015-7-5 01:20
给力!元素有你更精彩

深夜爪机党?还不睡觉?
回复 收起回复
2015-7-5 01:26:55   回复
 赞 赞 1

使用道具 登录

4#
带你赚币带你飞,元素里面有正妹!
回复 收起回复
2015-7-5 07:18:13   回复
 赞 赞 1

使用道具 登录

5#
元素帖子强,满满正能量!
回复 收起回复
2015-7-5 07:20:03   回复
 赞 赞 1

使用道具 登录

6#
资源发布哪家强?元素首发称大王!
回复 收起回复
2015-7-5 07:20:08   回复
 赞 赞 1

使用道具 登录

7#
资源甚好,发帖艰辛,且阅且珍惜!
回复 收起回复
2015-7-5 07:20:13   回复
 赞 赞 1

使用道具 登录

8#
资源发布哪家强?元素首发称大王!
回复 收起回复
2015-7-5 07:20:18   回复
 赞 赞 1

使用道具 登录

9#
带你赚币带你飞,元素里面有正妹!
回复 收起回复
2015-7-5 09:37:25   回复
 赞 赞 1

使用道具 登录

10#
给力!元素有你更精彩
回复 收起回复
2015-7-5 09:41:39   回复
 赞 赞 1

使用道具 登录

11#
好人啊
回复 收起回复
2015-7-5 10:12:02   回复
 赞 赞 1

使用道具 登录

12#
非常感谢
回复 收起回复
2015-7-5 17:28:10   回复
 赞 赞 1

使用道具 登录

13#
看完楼主的帖子,感觉自己萌萌哒~!
回复 收起回复
2015-7-5 20:50:04   回复
 赞 赞 1

使用道具 登录

14#
看完楼主的帖子,感觉自己萌萌哒~!
回复 收起回复
2015-7-5 20:51:02   回复
 赞 赞 1

使用道具 登录

15#
好资源~!支持
回复 收起回复
2015-7-5 23:13:28   回复
 赞 赞 1

使用道具 登录

16#
{:1_144:}
回复 收起回复
2015-7-6 16:36:03   回复
 赞 赞 1

使用道具 登录

17#
立刻提起了精神。
回复 收起回复
2015-7-9 10:03:37   回复
 赞 赞 1

使用道具 登录

18#
资源甚好,发帖艰辛,且阅且珍惜!
回复 收起回复
2015-7-9 19:04:40   回复
 赞 赞 1

使用道具 登录

19#
想要成大触,天天上元素!
回复 收起回复
2015-7-11 09:24:41   回复
 赞 赞 1

使用道具 登录

20#
谢谢分享
回复 收起回复
2015-7-12 14:45:08   回复
 赞 赞 1

使用道具 登录

CG 游戏行业专业问题

Unity3D技术手机游戏引擎手游引擎
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表