【转】有限状态机用法教程

如博文无法正常显示,请访问原文地址: 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 —— 简称状态机

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


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

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

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


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

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

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

那会使后期,我们的工程非常便于维护
New举例子黑白88


2

Foreword —— 前言()



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

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

例如:(图片引用自网络大神博客)
在这里插入图片描述在这里插入图片描述

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

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

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


3

Example —— 示例



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

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

MVC 设计模式


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

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

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

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

New举例子黑白88
在这里插入图片描述
状态机脚本

<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

我们来控制这两个状态,交由状态机进行切换
New举例子黑白88

菜单脚本

<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中函数的调用,同时节省了代码,逻辑也非常清晰


New举例子黑白88

游戏总控脚本

<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简单动画的控制
New举例子黑白88

视图脚本

<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 即可使用

New举例子黑白88

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

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

最终效果: (由于GIF录制 60帧数的限制,所以我点击太快了,看着有些卡似得)
在这里插入图片描述

 

至此:状态机教程结束

 


支持

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

 

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

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

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

 

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


 

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


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


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


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


 

 

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

 


END

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/437112.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

通用usb集线器驱动_多口充电、高速传输——ORICO晶锐系列7口集线器测评

随着笔电越来越薄&#xff0c;机身接口数量越来越少&#xff0c;U盘、存储卡、移动硬盘、鼠标、蓝牙适配器等明显感觉无处可插&#xff0c;因此USB集线器就成为笔电的最佳拍档。近期&#xff0c;ORICO(奥睿科)推出了一款晶锐系列7口集线器产品&#xff0c;它集成了7个USB3.0接口…

【转】状态机思路在程序设计中的应用

状态机思路在单片机程序设计中的应用 状态机的概念 状态机是软件编程中的一个重要概念。比这个概念更重要的是对它的灵活应用。在一个思路清晰而且高效的程序中&#xff0c;必然有状态机的身影浮现。 比如说一个按键命令解析程序&#xff0c;就可以被看做状态机&#xff1a;本…

【转】超详细的UML状态图符号,初学者也能轻松看懂状态图

UML状态图&#xff0c;用于显示状态机&#xff0c;即描述一个对象所处的可能状态以及状态之间的转移。用状态图建模可以帮助开发人员分析复杂对象的各种状态的转换&#xff0c;以及对象何时执行怎样的动作。那状态图又是怎样表示这些信息的呢&#xff1f;要想看明白其中的奥妙&…

舒尔特注意力训练表格_舒尔特注意力训练,舒尔特方格练习入口

孩子的注意力是否集中&#xff0c;直接影响孩子的上课效率和作业正确率&#xff0c;最终影响学习成绩。道理大家都懂&#xff0c;关键是如何保证注意力的集中。接下来&#xff0c;我给大家推荐一个简单方便在家就能完成的训练方法&#xff0c;把它比作小游戏也不为过。那就是舒…

nginx文件系统大小_Nginx 了解一下?

这篇文章主要简单的介绍下 Nginx 的相关知识&#xff0c;主要包括以下几部分内容&#xff1a;Nginx 适用于哪些场景&#xff1f;为什么会出现 Nginx&#xff1f;Nginx 优点Nginx 的编译与配置Nginx 适用于哪些场景&#xff1f;如图所示&#xff0c;一个请求会先经过 Nginx 到达…

存储过程排版工具_安利一款比Evernote更为实用的云笔记工具,不容错过

作为一个爱分享的自媒体人&#xff0c;出于工作和兴趣前前后后接触到的云笔记工具很多&#xff0c;例如&#xff1a;有道云笔记、为知笔记、语雀、印象笔记、oneNote...在笔记工具的使用上还是略有点点心得&#xff0c;今天给大家分享一款实用的云笔记工具——Baklib&#xff0…

【转】有限状态机(FSM)学习总结C#

FSM&#xff08;Finite State Machine有限状态机&#xff09;可以理解成是对行为逻辑的抽象&#xff0c;就好象人在生活中会做出各种行为&#xff0c;例如吃饭、睡觉等&#xff0c;这些所有我们都看作是“行为”的分支&#xff0c;由大脑决定每种行为具体是什么实施。在整个FSM…

【转】[完全免费] 在线UML Sequence Diagram 时序图工具 - 教程第3部分

时序图教程 甲序列图描述了一组对象之间的相互作用参与协作&#xff08;或情况&#xff09;&#xff0c;布置成按时间顺序; 它通过它们的“生命线”和它们发送给对方的消息来显示参与交互的对象。 什么是UML中的序列图&#xff1f; UML序列图是详细说明如何执行操作的交互图。…

【转】[完全免费] 在线UML Class Diagram 类图工具 - 教程第1部分

在线Visual Paradigm - UML编辑器 使用在线UML编辑器轻松绘制UML图&#xff0c;其中包含功能强大的UML编辑工具&#xff0c;即时UML语法检查和整洁的用户界面。Visual Paradigm在线UML 图&#xff0c;如类&#xff0c;用例&#xff0c;序列&#xff0c;活动&#xff0c;部署&a…

python 定时器_python 线程之四:定时器(Timer),非阻塞

线程之一讲了线程&#xff0c;如果不熟悉&#xff0c;可以点击【线程之一&#xff1a;线程的创建、启动及运行方式】1、定时器实质&#xff1a;Timer 定时器源码实现&#xff0c;和我们自定义一个线程方式一样&#xff0c;都是继承了 Thread 类&#xff0c;重写了 run() 方法&a…

人如何认知事物?

自然界是连续的&#xff0c;人类将自然界离散化成一个个独立的概念&#xff0c;独立的概念相互关联&#xff0c;形成模型&#xff0c;随着模型的完善&#xff0c;模型会不断逼近真实事物。 比如人类创造了各种学科&#xff0c;就是从不同的方面深入研究世界的结果。 所以&…

域内定位个人PC的三种方式(1)

会话搜集 在cmd下调用query session命令可以获得当前环境下的windows会话 NetSessionEnum 这个函数不允许直接查询是谁登陆&#xff0c;但是它允许查询是谁在访问此工作站的网络资源时所创建的网络会话&#xff0c;从而知道来自何处&#xff0c;此函数不需要高权限即可查询 第…

02.Teams组成概述及使用分享

在上一篇博客中介绍了Teams的前世今生&#xff0c;大家对Teams已经有了一个初步的认识&#xff0c;但是如上一篇文章中所说Teams是一个集成度很高的云协作平台&#xff0c;具体应该怎么去有效的利用起来呢&#xff1f;接下来这篇博客给大家全方位的分享一下Teams的组成部分以及…

【Qt】解决GDAL直接读取数据到QImage导致图像歪斜的问题

QRect intersect_rect; .... QImage img(intersect_rect.size(), QImage::Format_RGB888); uchar *pImageData (unsigned char *)img.constBits(); int img_width intersect_rect.width(); int img_height intersect_rect.height();// QImage每行是按照sizeof(int)对齐的&am…

高斯课堂数电讲义笔记_【法考经验贴】40岁三战主观题127分!他的笔记学习法助他逆袭!...

这位学员在考证界算是“高龄学员”&#xff0c;高分过关依赖于他的努力和正确的学习方法&#xff1b;本文中他有重点介绍自己是如何做笔记的&#xff0c;非常值得大家学习借鉴&#xff01;一、个人概况&#xff1a;三战法考我正值不惑之年&#xff0c;是一名在职基层人民警察&a…

【转】持续交付和DevOps的前世今生

作者/分享人&#xff1a;乔梁&#xff0c;20年IT老兵&#xff0c;腾讯公司高级管理顾问&#xff0c;敏捷和精益开发专家&#xff0c;持续交付领域先行者。曾就职于百度&#xff0c;国内多个知名互联网公司的企业教练。 历年QCon技术大会的讲师和专题出品人。 这是一个新概念风起…

关联规则挖掘算法_基于Apriori关联规则的协同过滤算法

Apriori 算法apriori关联规则算法的原理设计较为简单&#xff0c;著名的“啤酒和尿布”说的就是Apriori算法&#xff0c;通俗来讲apriori旨在寻找频繁项集&#xff0c;以帮助商家将消费者有可能一起搭配购买的物品放置在同一个地方&#xff0c;提高消费者的购物效率和良好的购物…

【转】RabbitMQ六种队列模式-1.简单队列模式

前言 RabbitMQ六种队列模式-简单队列 [本文]RabbitMQ六种队列模式-工作队列RabbitMQ六种队列模式-发布订阅RabbitMQ六种队列模式-路由模式RabbitMQ六种队列模式-主题模式 在官网的教程中&#xff0c;描述了如上六类工作队列模式&#xff1a; 简单队列模式&#xff1a;最简单的…

【转】RabbitMQ六种队列模式-2.工作队列模式

前言 RabbitMQ六种队列模式-简单队列RabbitMQ六种队列模式-工作队列 [本文]RabbitMQ六种队列模式-发布订阅RabbitMQ六种队列模式-路由模式RabbitMQ六种队列模式-主题模式 上文我们了解了 RabbitMQ 六种队列模式中的简单队列&#xff0c;代码也是非常的简单&#xff0c;比较容易…