Unity高级——状态机——有限状态机


一、状态机


状态机能够分离逻辑代码,提高代码的可维护性和重用性


unity 状态机 layer unity 状态机entry_宋晓波


本节课我们来学习,在Unity中使用状态机,来实现一些逻辑的划分,首先我们需要了解一下,为什么开发的时候使用状态机?

之前有过开发经验的朋友,可能会知道在应用开发中,最常用的一种框架就是MVC框架。

也就是视图模型控制器这个框架,但是我们在游戏开发中,会发现很难去应用MVC框架。

是因为我们的游戏开发,并不像网站或者其他应用开发那样,模型,视图和控制器在游戏开发的过程中,它们的界限很模糊,划分的不是很清晰。这是因为我们游戏类型的不同,游戏本身底层架构就会相差很远!而且在游戏中,不同的游戏对象往往存在大量的交互的这种现象。

所以,这种垂直的MVC框架就不太适用于游戏开发。但是我依然可以在游戏开发UI部分使用MVC框架。

除了UI,我们也需要某种程度上去分离游戏中的一些程序代码。比如说我们游戏中需要些一个脚本来控制角色的一些逻辑。角色的移动,攻击等属性时,我们不可能把代码放在一个脚本中完成,我们肯定要通过一定的方法,把它们划分成多个脚本或者说多个部分,依次来实现。因为这样把复杂的代码划分成一个一个小部分去实现,可以提高我们代码的可维护性,以及重用性,这也就是为什么我们要使用状态机的原因!



状态机就可以帮助我们分离逻辑代码。


二、有限状态机


有限状态机(FSM)简称状态机


FSM的状态是有限个数的




unity 状态机 layer unity 状态机entry_unity 状态机 layer_02

有限状态机就是为了表示有限个状态,以及这些状态直接的过渡行为的一个模型。在游戏的开发过程中,有限状态机能够将一个复杂的功能或者说复杂的逻辑简化为若干个稳定的状态!之后,在这些状态中进行事件的判断。



举一个例子:以人物角色为例


人物角色我们使用状态机来实现人物的复杂的逻辑的话。我们首先会根据我们的游戏玩法或者功能,来把游戏角色划分为不同个状态。如游戏角色处于闲置的状态,也有可能处于攻击的状态,可能处于行走的状态,可能处于副本的状态,交接任务的状态等等……

我们把这些逻辑代码都按照状态来划分开来之后,我们在单独在某个状态中,实现特定的代码,如果把这些游戏角色划分出有一个是战斗状态,只要战斗相关的代码我们都会放在战斗状态中去实现。肯定不能放到行走的状态中去实现的。



这个就是使用状态机来帮助我们逻辑代码进行分离。



举例:灯泡的状态图



unity 状态机 layer unity 状态机entry_unity_03




灯泡分为两个状态:开和关。在任意时刻,灯泡要么处于开的状态,要么处于关的状态。如果我们当前灯泡是开着的,如果我们想把灯泡关闭,我们只需要关闭开关就可以了。反过来,如果我们当前灯泡是关着的,我们想要打开灯泡,只需要打开开关即可。



在这个灯泡的状态图中我们可以分类出两个状态,这里面的状态(State)就是为了存储灯泡的一些信息的或者执行某些动作。



unity 状态机 layer unity 状态机entry_unity3d_04



如果我们从开的状态切换大关的状态这中间就叫状态过渡(Transition)



unity 状态机 layer unity 状态机entry_宋晓波_05



状态过渡就是用来描述:状态直接的转换的。


我们关闭开关和打开开关之间就是状态过渡的条件,它们的作用就是用来触发一个状态过渡的,我们称为过渡事件(Event)!




unity 状态机 layer unity 状态机entry_unity 状态机 layer_06

我们在开或者关的状态中,还会有一个动作,这个动作可能是持续执行的或者一瞬间执行的,称为动作(Action)!



unity 状态机 layer unity 状态机entry_unity_07



图片中所有元素组合到一起,就是一个状态机!


三、回到Unity中进行演示——把灯泡这个功能Unity中实现一下


首先为了项目准备了一些材质球,然后我们就开始



unity 状态机 layer unity 状态机entry_unity_08



在场景中创建一个Plane——然后我们把Plane染成绿色,然后在创建中,创建一个Cube,给Cube染一个紫色,然后我们调整摄像机,对准Cube……未完待续……




unity 状态机 layer unity 状态机entry_unity_09

为了能实现更明显的效果,我们删除默认的光源——添加一个Point Linght点光源,然后条件点光源的位置和大小。

如果要实现开关的效果,我们对intensity进行控制!

 

unity 状态机 layer unity 状态机entry_unity 状态机 layer_10

准备工作做好之后,接下来我们添加一个脚本,用来控制灯光——灯光控制器!

当按下键盘的O键 灯打开,当按下键盘的C键灯关闭。

首先我们新建一个C#脚本——命名为LightController

 

unity 状态机 layer unity 状态机entry_unity_11

双击新创建的LightController——进入代码界面

1. using UnityEngine;  
2. using System.Collections;  
3.   
4. public class LightController : MonoBehaviour {  
5.   
6. private Light _light;  
7.   
8. void Awake(){  
9.         _light = GetComponent<Light> ();  
10.     }  
11.   
12. void  Update(){  
13. //当前的脚步就是状态机  
14. //用户按键时间就是状态切换的条件——事件  
15. if(Input.GetKeyDown(KeyCode.O)){  
16.   
17. //灯的光强从0变为1时,就是状态的过渡  
18. //打开灯  
19. //灯开着的状态  
20.             _light.intensity=1f;  
21.       
22.         }  
23.   
24. if(Input.GetKeyDown(KeyCode.C)){  
25.   
26. //灯的光强从1变为0时,就是状态的过渡  
27. //关闭灯  
28. //灯处于关着的状态  
29.             _light.intensity=0f;  
30.           
31.         }  
32.     }  
33. }