如博文无法正常显示,请访问原文地址: https://blog.csdn.net/ChinarCSDN/article/details/82263126

有限状态机用法教程

 

文章目录

  • 有限状态机用法教程

  • @[toc]
  • 1
  • Finite-state machine —— 有限状态机
  • 2
  • Foreword —— 前言()
  • 3
  • Example —— 示例
  • 4
  • Moltimode —— 多状态
  • 5
  • GameManager ——游戏总控脚本
  • 6
  • View —— 视图脚本
  • 7
  • Final effect —— 最终效果
  • 8
  • Project —— 项目文件
  • 支持
  • May Be —— 搞开发,总有一天要做的事!

全文高清图片,点击即可放大观看 (很多人竟然不知道)


1

Finite-state machine —— 有限状态机

有限状态机简称: FSM —— 简称状态机

是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型

其他的不多说,对于我们开发者来说,状态机可以在全局视角下,管理我们的游戏状态/人物状态

使我们的工程逻辑清晰,将游戏/项目各个状态的转换,交由状态机统一管理

极大的避免了当状态过多 / 转换状态过多时,每次都需要调用相应函数来完成转换的麻烦

对于初学者来讲,套用状态机来对状态进行管理,可能认为过于麻烦

其实不用怕,那只是因为不熟悉用法和逻辑流程导致的

熟练的运用状态机来管理我们的项目状态,是很有必要的

那会使后期,我们的工程非常便于维护


2

Foreword —— 前言()

网上的大神们为了更全面的阐述状态机的具体工作方式,他们有些说的极为详细

但对于初学者来讲,直接看这样的图解,教程,多数都是一脸懵逼

例如:(图片引用自网络大神博客)

众所周知 Chinar 这些大神讲的略有不同

Chinar 会通过一些简单的例子,来带领初学者了解并学会如何使用状态机来管理我们的工程.

师傅领进门,修行靠个人 ,一切都需要先入门后,自己再慢慢扩展,不然一切都是扯淡


3

Example —— 示例

脚本引用自 Wiki.unity3d —— 源码链接

这里 Chinar 用一个简单的游戏状态切换逻辑来说明状态机用法

MVC 设计模式

FSM 一共2个类,不需要挂载到游戏对象上

FSMState 状态父类,所有子类状态都继承于这个类

例如以下工程:我们要需要2个状态: 菜单状态 与 游戏状态

那么这两个类MenuState 和 GameState都需要继承自 FSMState



状态机脚本

<span style="color:#000000"><code class="language-c">using UnityEngine<span style="color:#999999">;</span>
using System<span style="color:#999999">.</span>Collections<span style="color:#999999">.</span>Generic<span style="color:#999999">;</span>
using UnityEngine<span style="color:#999999">.</span>Experimental<span style="color:#999999">.</span>PlayerLoop<span style="color:#999999">;</span><span style="color:#6272a4">/// <summary></span>
<span style="color:#6272a4">/// Place the labels for the Transitions in this enum. —— 在此枚举中放置转换的标签。</span>
<span style="color:#6272a4">/// Don't change the first label, NullTransition as FSMSystem class uses it. —— 不要改变第一个标签:NullTransition,因为FSMSystem类使用它。</span>
<span style="color:#6272a4">/// </summary></span>
public <span style="color:#ff79c6">enum</span> Transition
<span style="color:#999999">{</span>NullTransition <span style="color:#6272a4">=</span> <span style="color:#f1fa8c">0</span><span style="color:#999999">,</span> <span style="color:#6272a4">// Use this transition to represent a non-existing transition in your system —— 使用此转换表示系统中不存在的转换</span>Game<span style="color:#999999">,</span>               <span style="color:#6272a4">//转到游戏</span>Menu                <span style="color:#6272a4">//转到菜单</span>
<span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span>
<span style="color:#6272a4">/// Place the labels for the States in this enum. ——  在此枚举中放置状态的标签。</span>
<span style="color:#6272a4">/// Don't change the first label, NullStateID as FSMSystem class uses it.不要改变第一个标签:NullStateID,因为FSMSystem类使用它。</span>
<span style="color:#6272a4">/// </summary></span>
public <span style="color:#ff79c6">enum</span> StateID
<span style="color:#999999">{</span>NullStateId <span style="color:#6272a4">=</span> <span style="color:#f1fa8c">0</span><span style="color:#999999">,</span> <span style="color:#6272a4">// Use this ID to represent a non-existing State in your system —— 使用此ID表示系统中不存在的状态</span>Menu<span style="color:#999999">,</span>            <span style="color:#6272a4">//菜单</span>Game             <span style="color:#6272a4">//游戏</span>
<span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span>
<span style="color:#6272a4">/// This class represents the States in the Finite State System.该类表示有限状态系统中的状态。</span>
<span style="color:#6272a4">/// Each state has a Dictionary with pairs (transition-state) showing 每个状态都有一个对显示(转换状态)的字典</span>
<span style="color:#6272a4">/// which state the FSM should be if a transition is fired while this state is the current state.如果在此状态为当前状态时触发转换,则FSM应处于那种状态。</span>
<span style="color:#6272a4">/// Method Reason is used to determine which transition should be fired .方法原因用于确定应触发哪个转换。</span>
<span style="color:#6272a4">/// Method Act has the code to perform the actions the NPC is supposed do if it's on this state.方法具有执行NPC动作的代码应该在这种状态下执行。</span>
<span style="color:#6272a4">/// </summary></span>
public abstract class FSMState <span style="color:#999999">:</span> MonoBehaviour
<span style="color:#999999">{</span>public    Dictionary<span style="color:#6272a4"><</span>Transition<span style="color:#999999">,</span> StateID<span style="color:#6272a4">></span> map <span style="color:#6272a4">=</span> new Dictionary<span style="color:#6272a4"><</span>Transition<span style="color:#999999">,</span> StateID<span style="color:#6272a4">></span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#6272a4">//字典 《转换,状态ID》</span>protected StateID                         stateID<span style="color:#999999">;</span>                                     <span style="color:#6272a4">//私有ID</span>public    StateID                         ID                                           <span style="color:#6272a4">//状态ID</span><span style="color:#999999">{</span>get <span style="color:#999999">{</span> <span style="color:#ff79c6">return</span> stateID<span style="color:#999999">;</span> <span style="color:#999999">}</span><span style="color:#999999">}</span>protected GameManager manager<span style="color:#999999">;</span> <span style="color:#6272a4">//保证子类状态可以访问到总控 GameManager</span>public    GameManager Manager<span style="color:#999999">{</span>set <span style="color:#999999">{</span> manager <span style="color:#6272a4">=</span> value<span style="color:#999999">;</span> <span style="color:#999999">}</span><span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// 添加转换</span><span style="color:#6272a4">/// </summary></span><span style="color:#6272a4">/// <param name="trans">转换状态</param></span><span style="color:#6272a4">/// <param name="id">转换ID</param></span>public <span style="color:#ff79c6">void</span> <span style="color:#8be9fd">AddTransition</span><span style="color:#999999">(</span>Transition trans<span style="color:#999999">,</span> StateID id<span style="color:#999999">)</span><span style="color:#999999">{</span><span style="color:#ff79c6">if</span> <span style="color:#999999">(</span>trans <span style="color:#6272a4">==</span> Transition<span style="color:#999999">.</span>NullTransition<span style="color:#999999">)</span> <span style="color:#6272a4">// Check if anyone of the args is invalid —— //检查是否有参数无效</span><span style="color:#999999">{</span>Debug<span style="color:#999999">.</span><span style="color:#8be9fd">LogError</span><span style="color:#999999">(</span><span style="color:#f1fa8c">"FSMState ERROR: NullTransition is not allowed for a real transition"</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#ff79c6">return</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#ff79c6">if</span> <span style="color:#999999">(</span>id <span style="color:#6272a4">==</span> StateID<span style="color:#999999">.</span>NullStateId<span style="color:#999999">)</span><span style="color:#999999">{</span>Debug<span style="color:#999999">.</span><span style="color:#8be9fd">LogError</span><span style="color:#999999">(</span><span style="color:#f1fa8c">"FSMState ERROR: NullStateID is not allowed for a real ID"</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#ff79c6">return</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#ff79c6">if</span> <span style="color:#999999">(</span>map<span style="color:#999999">.</span><span style="color:#8be9fd">ContainsKey</span><span style="color:#999999">(</span>trans<span style="color:#999999">)</span><span style="color:#999999">)</span> <span style="color:#6272a4">// Since this is a Deterministic FSM,check if the current transition was already inside the map —— 因为这是一个确定性FSM,检查当前的转换是否已经在字典中</span><span style="color:#999999">{</span>Debug<span style="color:#999999">.</span><span style="color:#8be9fd">LogError</span><span style="color:#999999">(</span><span style="color:#f1fa8c">"FSMState ERROR: State "</span> <span style="color:#6272a4">+</span> stateID<span style="color:#999999">.</span><span style="color:#8be9fd">ToString</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#6272a4">+</span> <span style="color:#f1fa8c">" already has transition "</span> <span style="color:#6272a4">+</span> trans<span style="color:#999999">.</span><span style="color:#8be9fd">ToString</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#6272a4">+</span><span style="color:#f1fa8c">"Impossible to assign to another state"</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#ff79c6">return</span><span style="color:#999999">;</span><span style="color:#999999">}</span>map<span style="color:#999999">.</span><span style="color:#8be9fd">Add</span><span style="color:#999999">(</span>trans<span style="color:#999999">,</span> id<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// This method deletes a pair transition-state from this state's map. —— 该方法从状态映射中删除一对转换状态。</span><span style="color:#6272a4">/// If the transition was not inside the state's map, an ERROR message is printed. —— 如果转换不在状态映射内,则会打印一条错误消息。</span><span style="color:#6272a4">/// </summary></span>public <span style="color:#ff79c6">void</span> <span style="color:#8be9fd">DeleteTransition</span><span style="color:#999999">(</span>Transition trans<span style="color:#999999">)</span><span style="color:#999999">{</span><span style="color:#ff79c6">if</span> <span style="color:#999999">(</span>trans <span style="color:#6272a4">==</span> Transition<span style="color:#999999">.</span>NullTransition<span style="color:#999999">)</span> <span style="color:#6272a4">// Check for NullTransition —— 检查状态是否为空</span><span style="color:#999999">{</span>Debug<span style="color:#999999">.</span><span style="color:#8be9fd">LogError</span><span style="color:#999999">(</span><span style="color:#f1fa8c">"FSMState ERROR: NullTransition is not allowed"</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#ff79c6">return</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#ff79c6">if</span> <span style="color:#999999">(</span>map<span style="color:#999999">.</span><span style="color:#8be9fd">ContainsKey</span><span style="color:#999999">(</span>trans<span style="color:#999999">)</span><span style="color:#999999">)</span> <span style="color:#6272a4">// Check if the pair is inside the map before deleting —— 在删除之前,检查这一对是否在字典中</span><span style="color:#999999">{</span>map<span style="color:#999999">.</span><span style="color:#8be9fd">Remove</span><span style="color:#999999">(</span>trans<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#ff79c6">return</span><span style="color:#999999">;</span><span style="color:#999999">}</span>Debug<span style="color:#999999">.</span><span style="color:#8be9fd">LogError</span><span style="color:#999999">(</span><span style="color:#f1fa8c">"FSMState ERROR: Transition "</span> <span style="color:#6272a4">+</span> trans<span style="color:#999999">.</span><span style="color:#8be9fd">ToString</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#6272a4">+</span> <span style="color:#f1fa8c">" passed to "</span> <span style="color:#6272a4">+</span> stateID<span style="color:#999999">.</span><span style="color:#8be9fd">ToString</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#6272a4">+</span><span style="color:#f1fa8c">" was not on the state's transition list"</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// This method returns the new state the FSM should be if this state receives a transition and—— 如果该状态接收到转换,该方法返回FSM应该为新状态</span><span style="color:#6272a4">/// 得到输出状态</span><span style="color:#6272a4">/// </summary></span>public StateID <span style="color:#8be9fd">GetOutputState</span><span style="color:#999999">(</span>Transition trans<span style="color:#999999">)</span><span style="color:#999999">{</span><span style="color:#ff79c6">if</span> <span style="color:#999999">(</span>map<span style="color:#999999">.</span><span style="color:#8be9fd">ContainsKey</span><span style="color:#999999">(</span>trans<span style="color:#999999">)</span><span style="color:#999999">)</span> <span style="color:#6272a4">// Check if the map has this transition —— 检查字典中是否有这个状态</span><span style="color:#999999">{</span><span style="color:#ff79c6">return</span> map<span style="color:#999999">[</span>trans<span style="color:#999999">]</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#ff79c6">return</span> StateID<span style="color:#999999">.</span>NullStateId<span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// This method is used to set up the State condition before entering it. —— 该方法用于在进入状态条件之前设置状态条件。</span><span style="color:#6272a4">/// It is called automatically by the FSMSystem class before assigning it to the current state.—— 在分配它之前,FSMSystem类会自动调用它到当前状态</span><span style="color:#6272a4">/// </summary></span>public virtual <span style="color:#ff79c6">void</span> <span style="color:#8be9fd">DoBeforeEntering</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span><span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// 此方法用于在FSMSystem更改为另一个变量之前进行任何必要的修改。在切换到新状态之前,FSMSystem会自动调用它。</span><span style="color:#6272a4">/// This method is used to make anything necessary, as reseting variables</span><span style="color:#6272a4">/// before the FSMSystem changes to another one. It is called automatically</span><span style="color:#6272a4">/// by the FSMSystem before changing to a new state.</span><span style="color:#6272a4">/// </summary></span>public virtual <span style="color:#ff79c6">void</span> <span style="color:#8be9fd">DoBeforeLeaving</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span><span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// 这个方法决定状态是否应该转换到它列表上的另一个NPC是对这个类控制的对象的引用</span><span style="color:#6272a4">/// This method decides if the state should transition to another on its list</span><span style="color:#6272a4">/// NPC is a reference to the object that is controlled by this class</span><span style="color:#6272a4">/// </summary></span>public virtual <span style="color:#ff79c6">void</span> <span style="color:#8be9fd">Reason</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span><span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// 这种方法控制了NPC在游戏世界中的行为。</span><span style="color:#6272a4">/// NPC做的每一个动作、动作或交流都应该放在这里</span><span style="color:#6272a4">/// NPC是这个类控制的对象的引用</span><span style="color:#6272a4">/// This method controls the behavior of the NPC in the game World.</span><span style="color:#6272a4">/// Every action, movement or communication the NPC does should be placed here</span><span style="color:#6272a4">/// NPC is a reference to the object that is controlled by this class</span><span style="color:#6272a4">/// </summary></span>public virtual <span style="color:#ff79c6">void</span> <span style="color:#8be9fd">Act</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span><span style="color:#999999">}</span>
<span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span>
<span style="color:#6272a4">///  FSMSystem class represents the Finite State Machine class.FSMSystem类表示有限状态机类。</span>
<span style="color:#6272a4">///  It has a List with the States the NPC has and methods to add, 它句有一个状态列表,NPC有添加、删除状态和更改机器当前状态的方法。</span>
<span style="color:#6272a4">///  delete a state, and to change the current state the Machine is on.</span>
<span style="color:#6272a4">/// </summary></span>
public class FSMSystem
<span style="color:#999999">{</span>private List<span style="color:#6272a4"><</span>FSMState<span style="color:#6272a4">></span> states<span style="color:#999999">;</span> <span style="color:#6272a4">//状态集</span><span style="color:#6272a4">// The only way one can change the state of the FSM is by performing a transition 改变FSM状态的唯一方法是进行转换</span><span style="color:#6272a4">// Don't change the CurrentState directly 不要直接改变当前状态</span>private StateID currentStateID<span style="color:#999999">;</span>public  StateID CurrentStateID<span style="color:#999999">{</span>get <span style="color:#999999">{</span> <span style="color:#ff79c6">return</span> currentStateID<span style="color:#999999">;</span> <span style="color:#999999">}</span><span style="color:#999999">}</span>private FSMState currentState<span style="color:#999999">;</span>public  FSMState CurrentState<span style="color:#999999">{</span>get <span style="color:#999999">{</span> <span style="color:#ff79c6">return</span> currentState<span style="color:#999999">;</span> <span style="color:#999999">}</span><span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// 默认构造函数</span><span style="color:#6272a4">/// </summary></span>public <span style="color:#8be9fd">FSMSystem</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span>states <span style="color:#6272a4">=</span> new List<span style="color:#6272a4"><</span>FSMState<span style="color:#6272a4">></span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// 设置当前状态</span><span style="color:#6272a4">/// </summary></span><span style="color:#6272a4">/// <param name="state">初始状态</param></span>public <span style="color:#ff79c6">void</span> <span style="color:#8be9fd">SetCurrentState</span><span style="color:#999999">(</span>FSMState state<span style="color:#999999">)</span><span style="color:#999999">{</span>currentState   <span style="color:#6272a4">=</span> state<span style="color:#999999">;</span>currentStateID <span style="color:#6272a4">=</span> state<span style="color:#999999">.</span>ID<span style="color:#999999">;</span>state<span style="color:#999999">.</span><span style="color:#8be9fd">DoBeforeEntering</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#6272a4">//开始前状态切换</span><span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// This method places new states inside the FSM, —— 这个方法在FSM内部放置一个放置一个新状态</span><span style="color:#6272a4">/// or prints an ERROR message if the state was already inside the List. —— 或者,如果状态已经在列表中,则打印错误消息。</span><span style="color:#6272a4">/// First state added is also the initial state. 第一个添加的状态也是初始状态。</span><span style="color:#6272a4">/// </summary></span>public <span style="color:#ff79c6">void</span> <span style="color:#8be9fd">AddState</span><span style="color:#999999">(</span>FSMState fsmState<span style="color:#999999">,</span> GameManager manager<span style="color:#999999">)</span><span style="color:#999999">{</span><span style="color:#6272a4">// Check for Null reference before deleting 删除前判空</span><span style="color:#ff79c6">if</span> <span style="color:#999999">(</span>fsmState <span style="color:#6272a4">==</span> null<span style="color:#999999">)</span><span style="color:#999999">{</span>Debug<span style="color:#999999">.</span><span style="color:#8be9fd">LogError</span><span style="color:#999999">(</span><span style="color:#f1fa8c">"FSM ERROR: Null reference is not allowed"</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#ff79c6">else</span> <span style="color:#6272a4">// First State inserted is also the Initial state, —— 插入的第一个状态也是初始状态,// the state the machine is in when the simulation begins —— 状态机是在模拟开始时</span><span style="color:#999999">{</span>fsmState<span style="color:#999999">.</span>Manager <span style="color:#6272a4">=</span> manager<span style="color:#999999">;</span> <span style="color:#6272a4">//给每个状态添加总控 GameManager</span><span style="color:#ff79c6">if</span> <span style="color:#999999">(</span>states<span style="color:#999999">.</span>Count <span style="color:#6272a4">==</span> <span style="color:#f1fa8c">0</span><span style="color:#999999">)</span><span style="color:#999999">{</span>states<span style="color:#999999">.</span><span style="color:#8be9fd">Add</span><span style="color:#999999">(</span>fsmState<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#ff79c6">return</span><span style="color:#999999">;</span><span style="color:#999999">}</span>foreach <span style="color:#999999">(</span>FSMState state in states<span style="color:#999999">)</span> <span style="color:#6272a4">// Add the state to the List if it's not inside it 如果状态不在列表中,则将其添加到列表中  (添加状态ID)</span><span style="color:#999999">{</span><span style="color:#ff79c6">if</span> <span style="color:#999999">(</span>state<span style="color:#999999">.</span>ID <span style="color:#6272a4">==</span> fsmState<span style="color:#999999">.</span>ID<span style="color:#999999">)</span><span style="color:#999999">{</span>Debug<span style="color:#999999">.</span><span style="color:#8be9fd">LogError</span><span style="color:#999999">(</span><span style="color:#f1fa8c">"FSM ERROR: Impossible to add state "</span> <span style="color:#6272a4">+</span> fsmState<span style="color:#999999">.</span>ID<span style="color:#999999">.</span><span style="color:#8be9fd">ToString</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#6272a4">+</span><span style="color:#f1fa8c">" because state has already been added"</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#ff79c6">return</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#999999">}</span>states<span style="color:#999999">.</span><span style="color:#8be9fd">Add</span><span style="color:#999999">(</span>fsmState<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// This method delete a state from the FSM List if it exists,  —— 这个方法从FSM列表中删除一个存在的状态,</span><span style="color:#6272a4">///   or prints an ERROR message if the state was not on the List. —— 或者,如果状态不存在,则打印错误信息</span><span style="color:#6272a4">/// </summary></span>public <span style="color:#ff79c6">void</span> <span style="color:#8be9fd">DeleteState</span><span style="color:#999999">(</span>StateID id<span style="color:#999999">)</span><span style="color:#999999">{</span><span style="color:#ff79c6">if</span> <span style="color:#999999">(</span>id <span style="color:#6272a4">==</span> StateID<span style="color:#999999">.</span>NullStateId<span style="color:#999999">)</span> <span style="color:#6272a4">// Check for NullState before deleting —— 判空</span><span style="color:#999999">{</span>Debug<span style="color:#999999">.</span><span style="color:#8be9fd">LogError</span><span style="color:#999999">(</span><span style="color:#f1fa8c">"FSM ERROR: NullStateID is not allowed for a real state"</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#ff79c6">return</span><span style="color:#999999">;</span><span style="color:#999999">}</span>foreach <span style="color:#999999">(</span>FSMState state in states<span style="color:#999999">)</span> <span style="color:#6272a4">// Search the List and delete the state if it's inside it  搜索列表并删除其中的状态</span><span style="color:#999999">{</span><span style="color:#ff79c6">if</span> <span style="color:#999999">(</span>state<span style="color:#999999">.</span>ID <span style="color:#6272a4">==</span> id<span style="color:#999999">)</span><span style="color:#999999">{</span>states<span style="color:#999999">.</span><span style="color:#8be9fd">Remove</span><span style="color:#999999">(</span>state<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#ff79c6">return</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#999999">}</span>Debug<span style="color:#999999">.</span><span style="color:#8be9fd">LogError</span><span style="color:#999999">(</span><span style="color:#f1fa8c">"FSM ERROR: Impossible to delete state "</span> <span style="color:#6272a4">+</span> id<span style="color:#999999">.</span><span style="color:#8be9fd">ToString</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#6272a4">+</span><span style="color:#f1fa8c">". It was not on the list of states"</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// This method tries to change the state the FSM is in based on</span><span style="color:#6272a4">/// the current state and the transition passed. If current state</span><span style="color:#6272a4">///  doesn't have a target state for the transition passed, </span><span style="color:#6272a4">/// an ERROR message is printed.</span><span style="color:#6272a4">/// 该方法尝试根据当前状态和已通过的转换改变FSM所处的状态。如果当前状态没有传递的转换的目标状态,则输出错误消息。</span><span style="color:#6272a4">/// </summary></span>public <span style="color:#ff79c6">void</span> <span style="color:#8be9fd">PerformTransition</span><span style="color:#999999">(</span>Transition trans<span style="color:#999999">)</span><span style="color:#999999">{</span><span style="color:#ff79c6">if</span> <span style="color:#999999">(</span>trans <span style="color:#6272a4">==</span> Transition<span style="color:#999999">.</span>NullTransition<span style="color:#999999">)</span> <span style="color:#6272a4">// Check for NullTransition before changing the current state 在更改当前状态之前检查是否有NullTransition</span><span style="color:#999999">{</span>Debug<span style="color:#999999">.</span><span style="color:#8be9fd">LogError</span><span style="color:#999999">(</span><span style="color:#f1fa8c">"FSM ERROR: NullTransition is not allowed for a real transition"</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#ff79c6">return</span><span style="color:#999999">;</span><span style="color:#999999">}</span>StateID id <span style="color:#6272a4">=</span> currentState<span style="color:#999999">.</span><span style="color:#8be9fd">GetOutputState</span><span style="color:#999999">(</span>trans<span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#6272a4">// Check if the currentState has the transition passed as argument 检查currentState是否将转换作为参数传递</span><span style="color:#ff79c6">if</span> <span style="color:#999999">(</span>id <span style="color:#6272a4">==</span> StateID<span style="color:#999999">.</span>NullStateId<span style="color:#999999">)</span><span style="color:#999999">{</span>Debug<span style="color:#999999">.</span><span style="color:#8be9fd">LogError</span><span style="color:#999999">(</span><span style="color:#f1fa8c">"FSM ERROR: State "</span> <span style="color:#6272a4">+</span> currentStateID<span style="color:#999999">.</span><span style="color:#8be9fd">ToString</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#6272a4">+</span> <span style="color:#f1fa8c">" does not have a target state "</span> <span style="color:#6272a4">+</span><span style="color:#f1fa8c">" for transition "</span> <span style="color:#6272a4">+</span> trans<span style="color:#999999">.</span><span style="color:#8be9fd">ToString</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#ff79c6">return</span><span style="color:#999999">;</span><span style="color:#999999">}</span>currentStateID <span style="color:#6272a4">=</span> id<span style="color:#999999">;</span> <span style="color:#6272a4">// Update the currentStateID and currentState     更新当前状态和ID</span>foreach <span style="color:#999999">(</span>FSMState state in states<span style="color:#999999">)</span><span style="color:#999999">{</span><span style="color:#ff79c6">if</span> <span style="color:#999999">(</span>state<span style="color:#999999">.</span>ID <span style="color:#6272a4">==</span> currentStateID<span style="color:#999999">)</span><span style="color:#999999">{</span>currentState<span style="color:#999999">.</span><span style="color:#8be9fd">DoBeforeLeaving</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#6272a4">// Do the post processing of the state before setting the new one 在设置新状态之前是否对状态进行后处理</span>currentState <span style="color:#6272a4">=</span> state<span style="color:#999999">;</span>currentState<span style="color:#999999">.</span><span style="color:#8be9fd">DoBeforeEntering</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#6272a4">// Reset the state to its desired condition before it can reason or act 在它推动和动作之前,重置状态到它所需的条件</span><span style="color:#ff79c6">break</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#999999">}</span><span style="color:#999999">}</span>
<span style="color:#999999">}</span>
</code></span>

4

Multimode —— 多状态

菜单状态脚本:MenuState

游戏状态脚本:GameState

我们来控制这两个状态,交由状态机进行切换

菜单脚本

<span style="color:#000000"><code class="language-c"><span style="color:#6272a4">/// <summary></span>
<span style="color:#6272a4">/// 菜单状态</span>
<span style="color:#6272a4">/// </summary></span>
public class MenuState <span style="color:#999999">:</span> FSMState
<span style="color:#999999">{</span><span style="color:#ff79c6">void</span> <span style="color:#8be9fd">Awake</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span>stateID <span style="color:#6272a4">=</span> StateID<span style="color:#999999">.</span>Menu<span style="color:#999999">;</span><span style="color:#8be9fd">AddTransition</span><span style="color:#999999">(</span>Transition<span style="color:#999999">.</span>Game<span style="color:#999999">,</span> StateID<span style="color:#999999">.</span>Game<span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#6272a4">//(菜单状态下:需要转游戏)→→添加转换,转换游戏 —— 对应游戏状态</span><span style="color:#6272a4">//map.Add(Transition.Game, StateID.Game);//上边也可这么写</span><span style="color:#999999">}</span><span style="color:#ff79c6">void</span> <span style="color:#8be9fd">Start</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span>manager<span style="color:#999999">.</span>View<span style="color:#999999">.</span>StartButton<span style="color:#999999">.</span>onClick<span style="color:#999999">.</span><span style="color:#8be9fd">AddListener</span><span style="color:#999999">(</span>OnStarGameClick<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// 开始游戏</span><span style="color:#6272a4">/// </summary></span>public <span style="color:#ff79c6">void</span> <span style="color:#8be9fd">OnStarGameClick</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span>manager<span style="color:#999999">.</span>Fsm<span style="color:#999999">.</span><span style="color:#8be9fd">PerformTransition</span><span style="color:#999999">(</span>Transition<span style="color:#999999">.</span>Game<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// 进入该状态时</span><span style="color:#6272a4">/// </summary></span>public override <span style="color:#ff79c6">void</span> <span style="color:#8be9fd">DoBeforeEntering</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span>manager<span style="color:#999999">.</span>View<span style="color:#999999">.</span><span style="color:#8be9fd">ShowMenuUi</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// 离开该状态时</span><span style="color:#6272a4">/// </summary></span>public override <span style="color:#ff79c6">void</span> <span style="color:#8be9fd">DoBeforeLeaving</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span>manager<span style="color:#999999">.</span>View<span style="color:#999999">.</span><span style="color:#8be9fd">HideMenuUi</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span>
<span style="color:#999999">}</span>
</code></span>

游戏脚本

<span style="color:#000000"><code class="language-c"><span style="color:#6272a4">/// <summary></span>
<span style="color:#6272a4">/// 游戏状态</span>
<span style="color:#6272a4">/// </summary></span>
public class GameState <span style="color:#999999">:</span> FSMState
<span style="color:#999999">{</span><span style="color:#ff79c6">void</span> <span style="color:#8be9fd">Awake</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span>stateID <span style="color:#6272a4">=</span> StateID<span style="color:#999999">.</span>Game<span style="color:#999999">;</span><span style="color:#8be9fd">AddTransition</span><span style="color:#999999">(</span>Transition<span style="color:#999999">.</span>Menu<span style="color:#999999">,</span> StateID<span style="color:#999999">.</span>Menu<span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#6272a4">//(游戏状态下:点击暂停需要转菜单)→→添加转换,转换菜单—— 对应菜单状态</span><span style="color:#6272a4">//map.Add(Transition.Menu, StateID.Menu);//上边也可这么写</span><span style="color:#999999">}</span><span style="color:#ff79c6">void</span> <span style="color:#8be9fd">Start</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span>manager<span style="color:#999999">.</span>View<span style="color:#999999">.</span>PauseButton<span style="color:#999999">.</span>onClick<span style="color:#999999">.</span><span style="color:#8be9fd">AddListener</span><span style="color:#999999">(</span>OnPauseButton<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// 暂停</span><span style="color:#6272a4">/// </summary></span>public <span style="color:#ff79c6">void</span> <span style="color:#8be9fd">OnPauseButton</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span>manager<span style="color:#999999">.</span>Fsm<span style="color:#999999">.</span><span style="color:#8be9fd">PerformTransition</span><span style="color:#999999">(</span>Transition<span style="color:#999999">.</span>Menu<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// 进入该状态时</span><span style="color:#6272a4">/// </summary></span>public override <span style="color:#ff79c6">void</span> <span style="color:#8be9fd">DoBeforeEntering</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span>manager<span style="color:#999999">.</span>View<span style="color:#999999">.</span><span style="color:#8be9fd">ShowGameUi</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// 离开该状态时</span><span style="color:#6272a4">/// </summary></span>public override <span style="color:#ff79c6">void</span> <span style="color:#8be9fd">DoBeforeLeaving</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span>manager<span style="color:#999999">.</span>View<span style="color:#999999">.</span><span style="color:#8be9fd">HideGameUi</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span>
<span style="color:#999999">}</span>
</code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

5

GameManager ——游戏总控脚本

游戏总控脚本:GameManager —— 用来控制全局游戏逻辑 ©

我们在这个脚本中,将所有状态批量添加到状态机中

这里我通过修改,传入了 GameManager 到所有状态中

这样我们后期可以在各个状态中完成对 GameManager中函数的调用,同时节省了代码,逻辑也非常清晰


游戏总控脚本

<span style="color:#000000"><code class="language-c">using UnityEngine<span style="color:#999999">;</span><span style="color:#6272a4">/// <summary></span>
<span style="color:#6272a4">/// 游戏总控脚本</span>
<span style="color:#6272a4">/// </summary></span>
public class GameManager <span style="color:#999999">:</span> MonoBehaviour
<span style="color:#999999">{</span>public FSMSystem Fsm<span style="color:#999999">;</span>  <span style="color:#6272a4">//有限状态机系统对象</span>public View      View<span style="color:#999999">;</span> <span style="color:#6272a4">// 显示层</span>private <span style="color:#ff79c6">void</span> <span style="color:#8be9fd">Awake</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span>View <span style="color:#6272a4">=</span> GameObject<span style="color:#999999">.</span><span style="color:#8be9fd">FindGameObjectWithTag</span><span style="color:#999999">(</span><span style="color:#f1fa8c">"View"</span><span style="color:#999999">)</span><span style="color:#999999">.</span>GetComponent<span style="color:#6272a4"><</span>View<span style="color:#6272a4">></span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#6272a4">//这里要给 View 游戏对象设置标签 "View"</span><span style="color:#6272a4">//添加所有状态到状态集(这里,我也通过修改,将 GameManager传到所有状态中,简化代码,便于调用)</span>Fsm               <span style="color:#6272a4">=</span> new <span style="color:#8be9fd">FSMSystem</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span>                     <span style="color:#6272a4">//调用构造函数,内部会自动初始化 状态集</span>FSMState<span style="color:#999999">[</span><span style="color:#999999">]</span> states <span style="color:#6272a4">=</span> GetComponentsInChildren<span style="color:#6272a4"><</span>FSMState<span style="color:#6272a4">></span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#6272a4">//找到所有 状态</span>foreach <span style="color:#999999">(</span>FSMState state in states<span style="color:#999999">)</span><span style="color:#999999">{</span>Fsm<span style="color:#999999">.</span><span style="color:#8be9fd">AddState</span><span style="color:#999999">(</span>state<span style="color:#999999">,</span> this<span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#6272a4">//将状态,逐个添加到 状态机中</span><span style="color:#999999">}</span>MenuState menuState <span style="color:#6272a4">=</span> GetComponentInChildren<span style="color:#6272a4"><</span>MenuState<span style="color:#6272a4">></span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span>Fsm<span style="color:#999999">.</span><span style="color:#8be9fd">SetCurrentState</span><span style="color:#999999">(</span>menuState<span style="color:#999999">)</span><span style="color:#999999">;</span> <span style="color:#6272a4">//默认状态是 菜单状态</span><span style="color:#999999">}</span>
<span style="color:#999999">}</span>
</code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

6

View —— 视图脚本

用 View 脚本来对我们所有 UI 元素进行赋值与管理

项目中引用了 DoTween 插件,来完成对UI简单动画的控制

视图脚本

<span style="color:#000000"><code class="language-c">using DG<span style="color:#999999">.</span>Tweening<span style="color:#999999">;</span>
using UnityEngine<span style="color:#999999">;</span>
using UnityEngine<span style="color:#999999">.</span>UI<span style="color:#999999">;</span><span style="color:#6272a4">/// <summary></span>
<span style="color:#6272a4">/// 视图脚本 —— 管理UI元素</span>
<span style="color:#6272a4">/// </summary></span>
public class View <span style="color:#999999">:</span> MonoBehaviour
<span style="color:#999999">{</span>private RectTransform menuUi<span style="color:#999999">;</span>      <span style="color:#6272a4">//菜单页</span>private RectTransform gameUi<span style="color:#999999">;</span>      <span style="color:#6272a4">//游戏页</span>public  Button        StartButton<span style="color:#999999">;</span> <span style="color:#6272a4">//开始按钮</span>public  Button        PauseButton<span style="color:#999999">;</span> <span style="color:#6272a4">//暂停按钮</span>public  Ease          PubEase<span style="color:#999999">;</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// 初始化函数</span><span style="color:#6272a4">/// </summary></span><span style="color:#ff79c6">void</span> <span style="color:#8be9fd">Awake</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span>menuUi      <span style="color:#6272a4">=</span> <span style="color:#999999">(</span>RectTransform<span style="color:#999999">)</span> <span style="color:#8be9fd">Find</span><span style="color:#999999">(</span><span style="color:#f1fa8c">"Menu Ui"</span><span style="color:#999999">)</span><span style="color:#999999">;</span>gameUi      <span style="color:#6272a4">=</span> <span style="color:#999999">(</span>RectTransform<span style="color:#999999">)</span> <span style="color:#8be9fd">Find</span><span style="color:#999999">(</span><span style="color:#f1fa8c">"Game Ui"</span><span style="color:#999999">)</span><span style="color:#999999">;</span>StartButton <span style="color:#6272a4">=</span> <span style="color:#8be9fd">Find</span><span style="color:#999999">(</span><span style="color:#f1fa8c">"Menu Ui/Menu Button"</span><span style="color:#999999">)</span><span style="color:#999999">.</span>GetComponent<span style="color:#6272a4"><</span>Button<span style="color:#6272a4">></span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span>PauseButton <span style="color:#6272a4">=</span> <span style="color:#8be9fd">Find</span><span style="color:#999999">(</span><span style="color:#f1fa8c">"Game Ui/Pause Button"</span><span style="color:#999999">)</span><span style="color:#999999">.</span>GetComponent<span style="color:#6272a4"><</span>Button<span style="color:#6272a4">></span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// 显示菜单页</span><span style="color:#6272a4">/// </summary></span>public <span style="color:#ff79c6">void</span> <span style="color:#8be9fd">ShowMenuUi</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span>menuUi<span style="color:#999999">.</span><span style="color:#8be9fd">DOScale</span><span style="color:#999999">(</span>new <span style="color:#8be9fd">Vector3</span><span style="color:#999999">(</span><span style="color:#f1fa8c">0.3f</span><span style="color:#999999">,</span> <span style="color:#f1fa8c">0.3f</span><span style="color:#999999">,</span> <span style="color:#f1fa8c">0.3f</span><span style="color:#999999">)</span><span style="color:#999999">,</span> <span style="color:#f1fa8c">0.1f</span><span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#8be9fd">OnComplete</span><span style="color:#999999">(</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#6272a4">=</span><span style="color:#6272a4">></span><span style="color:#999999">{</span>menuUi<span style="color:#999999">.</span><span style="color:#8be9fd">DOScale</span><span style="color:#999999">(</span>Vector3<span style="color:#999999">.</span>one<span style="color:#999999">,</span> <span style="color:#f1fa8c">0.3f</span><span style="color:#999999">)</span><span style="color:#999999">;</span>StartButton<span style="color:#999999">.</span>enabled <span style="color:#6272a4">=</span> true<span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#8be9fd">SetEase</span><span style="color:#999999">(</span>PubEase<span style="color:#999999">)</span><span style="color:#999999">;</span>menuUi<span style="color:#999999">.</span><span style="color:#8be9fd">DOAnchorPos</span><span style="color:#999999">(</span>Vector2<span style="color:#999999">.</span>zero<span style="color:#999999">,</span> <span style="color:#f1fa8c">0.3f</span><span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#8be9fd">SetEase</span><span style="color:#999999">(</span>PubEase<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// 隐藏菜单页</span><span style="color:#6272a4">/// </summary></span>public <span style="color:#ff79c6">void</span> <span style="color:#8be9fd">HideMenuUi</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span>menuUi<span style="color:#999999">.</span><span style="color:#8be9fd">DOScale</span><span style="color:#999999">(</span>new <span style="color:#8be9fd">Vector3</span><span style="color:#999999">(</span><span style="color:#f1fa8c">0.3f</span><span style="color:#999999">,</span> <span style="color:#f1fa8c">0.3f</span><span style="color:#999999">,</span> <span style="color:#f1fa8c">0.3f</span><span style="color:#999999">)</span><span style="color:#999999">,</span> <span style="color:#f1fa8c">0.1f</span><span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#8be9fd">OnComplete</span><span style="color:#999999">(</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#6272a4">=</span><span style="color:#6272a4">></span><span style="color:#999999">{</span>menuUi<span style="color:#999999">.</span><span style="color:#8be9fd">DOAnchorPos</span><span style="color:#999999">(</span>new <span style="color:#8be9fd">Vector2</span><span style="color:#999999">(</span><span style="color:#6272a4">-</span><span style="color:#f1fa8c">600</span><span style="color:#999999">,</span> <span style="color:#6272a4">-</span><span style="color:#f1fa8c">450</span><span style="color:#999999">)</span><span style="color:#999999">,</span> <span style="color:#f1fa8c">0.3f</span><span style="color:#999999">)</span><span style="color:#999999">;</span>menuUi<span style="color:#999999">.</span><span style="color:#8be9fd">DOScale</span><span style="color:#999999">(</span>Vector3<span style="color:#999999">.</span>zero<span style="color:#999999">,</span> <span style="color:#f1fa8c">0.3f</span><span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#8be9fd">OnComplete</span><span style="color:#999999">(</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#6272a4">=</span><span style="color:#6272a4">></span> <span style="color:#999999">{</span> StartButton<span style="color:#999999">.</span>enabled <span style="color:#6272a4">=</span> false<span style="color:#999999">;</span> <span style="color:#999999">}</span><span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#8be9fd">SetEase</span><span style="color:#999999">(</span>PubEase<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#8be9fd">SetEase</span><span style="color:#999999">(</span>PubEase<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// 显示游戏页</span><span style="color:#6272a4">/// </summary></span>public <span style="color:#ff79c6">void</span> <span style="color:#8be9fd">ShowGameUi</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span>gameUi<span style="color:#999999">.</span><span style="color:#8be9fd">DOScale</span><span style="color:#999999">(</span>new <span style="color:#8be9fd">Vector3</span><span style="color:#999999">(</span><span style="color:#f1fa8c">0.3f</span><span style="color:#999999">,</span> <span style="color:#f1fa8c">0.3f</span><span style="color:#999999">,</span> <span style="color:#f1fa8c">0.3f</span><span style="color:#999999">)</span><span style="color:#999999">,</span> <span style="color:#f1fa8c">0.1f</span><span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#8be9fd">OnComplete</span><span style="color:#999999">(</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#6272a4">=</span><span style="color:#6272a4">></span><span style="color:#999999">{</span>gameUi<span style="color:#999999">.</span><span style="color:#8be9fd">DOScale</span><span style="color:#999999">(</span>Vector3<span style="color:#999999">.</span>one<span style="color:#999999">,</span> <span style="color:#f1fa8c">0.3f</span><span style="color:#999999">)</span><span style="color:#999999">;</span>PauseButton<span style="color:#999999">.</span>enabled <span style="color:#6272a4">=</span> true<span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#8be9fd">SetEase</span><span style="color:#999999">(</span>PubEase<span style="color:#999999">)</span><span style="color:#999999">;</span>gameUi<span style="color:#999999">.</span><span style="color:#8be9fd">DOAnchorPos</span><span style="color:#999999">(</span>Vector2<span style="color:#999999">.</span>zero<span style="color:#999999">,</span> <span style="color:#f1fa8c">0.3f</span><span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#8be9fd">SetEase</span><span style="color:#999999">(</span>PubEase<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// 隐藏游戏页</span><span style="color:#6272a4">/// </summary></span>public <span style="color:#ff79c6">void</span> <span style="color:#8be9fd">HideGameUi</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">{</span>gameUi<span style="color:#999999">.</span><span style="color:#8be9fd">DOScale</span><span style="color:#999999">(</span>new <span style="color:#8be9fd">Vector3</span><span style="color:#999999">(</span><span style="color:#f1fa8c">0.3f</span><span style="color:#999999">,</span> <span style="color:#f1fa8c">0.3f</span><span style="color:#999999">,</span> <span style="color:#f1fa8c">0.3f</span><span style="color:#999999">)</span><span style="color:#999999">,</span> <span style="color:#f1fa8c">0.1f</span><span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#8be9fd">OnComplete</span><span style="color:#999999">(</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#6272a4">=</span><span style="color:#6272a4">></span><span style="color:#999999">{</span>gameUi<span style="color:#999999">.</span><span style="color:#8be9fd">DOAnchorPos</span><span style="color:#999999">(</span>new <span style="color:#8be9fd">Vector2</span><span style="color:#999999">(</span><span style="color:#6272a4">-</span><span style="color:#f1fa8c">600</span><span style="color:#999999">,</span> <span style="color:#6272a4">-</span><span style="color:#f1fa8c">450</span><span style="color:#999999">)</span><span style="color:#999999">,</span> <span style="color:#f1fa8c">0.3f</span><span style="color:#999999">)</span><span style="color:#999999">;</span>gameUi<span style="color:#999999">.</span><span style="color:#8be9fd">DOScale</span><span style="color:#999999">(</span>Vector3<span style="color:#999999">.</span>zero<span style="color:#999999">,</span> <span style="color:#f1fa8c">0.3f</span><span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#8be9fd">OnComplete</span><span style="color:#999999">(</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#6272a4">=</span><span style="color:#6272a4">></span> <span style="color:#999999">{</span> PauseButton<span style="color:#999999">.</span>enabled <span style="color:#6272a4">=</span> false<span style="color:#999999">;</span> <span style="color:#999999">}</span><span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#8be9fd">SetEase</span><span style="color:#999999">(</span>PubEase<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#8be9fd">SetEase</span><span style="color:#999999">(</span>PubEase<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span><span style="color:#6272a4">/// <summary></span><span style="color:#6272a4">/// 查找对Ui元素完成赋值</span><span style="color:#6272a4">/// </summary></span><span style="color:#6272a4">/// <param name="uiElement">Ui名查找路径</param></span>Transform <span style="color:#8be9fd">Find</span><span style="color:#999999">(</span>string uiElement<span style="color:#999999">)</span><span style="color:#999999">{</span><span style="color:#ff79c6">return</span> transform<span style="color:#999999">.</span><span style="color:#8be9fd">Find</span><span style="color:#999999">(</span><span style="color:#f1fa8c">"Canvas/"</span> <span style="color:#6272a4">+</span> uiElement<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#999999">}</span>
<span style="color:#999999">}</span>
</code></span>

7

Final effect —— 最终效果

我们通过状态机简单的完成了 开始游戏 和暂停的状态切换

代码中注释写的非常详细了,请初学者认真看下

具体流程就是:

1. GameManager 完成将所有子类状态添加到状态集中

2. View 获取到我们所需要的所有 UI 元素对象,并提供公有方法可供各个状态访问

3. 确认好各个状态的进入 与离开时机发生时,需要执行的事件,并交由状态机去管理!

状态进入:DoBeforeEntering()
状态离开:DoBeforeLeaving()

4. 例子较为简单,为了方便初学者理解学习只写了2个状态

根据需求,大家可以举一反三,多写几个状态练习一下,其实流程很简单!


8

Project —— 项目文件

项目文件为 unitypackage 文件包:

下载导入 Unity 即可使用

点击下载 —— 项目资源 (积分支持)

点击下载 —— 项目资源 (Chinar免费)

最终效果: (由于GIF录制 60帧数的限制,所以我点击太快了,看着有些卡似得)

至此:状态机教程结束


支持

May Be —— 搞开发,总有一天要做的事!

 

拥有自己的服务器,无需再找攻略!

Chinar 提供一站式教程,闭眼式创建!

为新手节省宝贵时间,避免采坑!

 

先点击领取 —— 阿里全产品优惠券 (享受最低优惠)

1 —— 云服务器超全购买流程 (新手必备!)

2 —— 阿里ECS云服务器自定义配置 - 购买教程(新手必备!)

3—— Windows 服务器配置、运行、建站一条龙 !

4 —— Linux 服务器配置、运行、建站一条龙 !


技术交流群:806091680 ! Chinar 欢迎你的加入


END

本博客为非营利性个人原创,除部分有明确署名的作品外,所刊登的所有作品的著作权均为本人所拥有,本人保留所有法定权利。违者必究

对于需要复制、转载、链接和传播博客文章或内容的,请及时和本博主进行联系,留言,Email: ichinar@icloud.com

对于经本博主明确授权和许可使用文章及内容的,使用时请注明文章或内容出处并注明网址

【转】有限状态机用法教程相关推荐

  1. Python编程语言学习:判断变量是否为NONE或False的几种常见写法(if not用法教程)

    Python编程语言学习:判断变量是否为NONE或False的几种常见写法(if not用法教程) 目录 判断变量是否为NONE或False的几种常见写法(if not用法教程) 1.not用法 2. ...

  2. C语言入门之指针用法教程

    C语言入门之指针用法教程 这篇文章主要介绍了C语言入门之指针用法教程,主要对C语言中指针的本质及常见用法做了较为通俗易懂的分析,是后续深入学习C语言的基础,需要的朋友可以参考下 undefined u ...

  3. Python爬虫4.2 — ajax(动态网页数据抓取)用法教程

    Python爬虫4.2 - ajax[动态网页数据]用法教程 综述 AJAX 介绍 什么是AJAX 实例说明 请求分析 获取方式 实例说明 其他博文链接 综述 本系列文档用于对Python爬虫技术的学 ...

  4. android miui悬浮按钮,如何开启MIUI 8悬浮球 MIUI8悬浮球用法教程

    MIUI 8悬浮球怎么开启呢?我们知道全新的MIUI 8加入了"悬浮球"功能,可以带来更好的大屏单手操作体验.其实关于这个功能类似于IOS系统的AssistiveTouch小白点功 ...

  5. Python爬虫1.4 — requests高级用法教程

    Python爬虫1.4 - requests高级用法教程 综述 设置请求头(headers) 设置代理服务器IP(proxy) Cookies(Session) requests.Session() ...

  6. Python爬虫4.4 — selenium高级用法教程

    Python爬虫4.4 - selenium高级用法教程 综述 Headless Chrome 设置请求头 设置代理IP 常用启动项参数options设置 Cookie操作 selenium设置coo ...

  7. css margin属性,css margin属性怎么用?css margin属性用法教程

    在css中,有一个重要的属性margin,很多人都不知道css margin属性是什么?怎么用,下面为您总结一下css margin属性用法教程. margin是css用于在一个声明中,对所有css ...

  8. python补充urllib教程,Python爬虫之urllib基础用法教程

    综述 本系列文档用于对Python爬虫技术进行简单的教程讲解,巩固自己技术知识的同时,万一一不小心又正好对你有用那就更好了. Python 版本是3.7.4 urllib库介绍 它是 Python 内 ...

  9. dotween上下摆动_DoTween用法教程

    DoTween用法攻略 本文提供全流程,中文翻译. Chinar坚持将简单的生活方式,带给世人! (拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar-- 心分享.心创新 ...

最新文章

  1. 8月第3周回顾:四巨头发三大新闻 一报告引多家争议
  2. Linux-CAN Bus
  3. windows 2003 下oracle从10.2.0.1升级到10.2.0.4
  4. 淘宝和QQ空间顶部工具栏三角形箭头的实现方式
  5. r语言x%3c-读取文件,R语言读写最灵活的文件——txt文件
  6. MessagePack Java Jackson Dataformat 在 Map 中不使用 String 为 Key 的序列化
  7. ci phpexcel mysql_PHPExcel导入数据到mysql数据库
  8. kruskal算法_大厂面试为什么总是考算法?
  9. oracle内存参数越大越好吗,什么是Oracle内存参数调优技术?
  10. 二叉搜索树的学习笔记(有解释)
  11. 无线网络安全技术基础
  12. win10启动修复_在win10桌面建立高级启动选项快捷方式,修复电脑故障不用愁
  13. “封号斗罗” 程序员修炼之道:通向务实的最高境界
  14. vue + web 前端访问后端,跨域问题解决方案
  15. 【转贴】忽悠:如何让武器战士买屠龙
  16. Java工程师的职业规划(最全版本)
  17. 华为al00的计算机在哪,(详细)华为畅享8 LDN-AL00的USB调试模式在哪里开启的流程...
  18. Spring boot的定时任务调度
  19. [归并排序]leetcode327:区间和的个数(hard)
  20. Plantuml类图用法

热门文章

  1. 037-PHP如何返回闭包函数实例
  2. sql exist 优化查询时间
  3. Javascript引擎单线程机制及setTimeout执行原理说明
  4. 通过JavaScript操作HTML中select标签
  5. [Silverlight]16进制颜色转ARGB及Color转Int32
  6. C#提供的类库能够轻松实现对文件的操作
  7. [攻防世界][CTF][2020][MISC] 攻防世界 MISC writeup
  8. [Leetcode][第491题][JAVA][递增子序列][回溯][RK算法]
  9. [密码学基础][每个信息安全博士生应该知道的52件事][Bristol Cryptography][第14篇]什么是基于线性对的密码学
  10. mysql 查询两张表结构相同的数据库_利用反射处理多个表结构相同的数据的查询和数据库表的关联...