简单的前言
在平时我们会玩到一些RPG游戏,其中的角色能走能跑能飞能打架,打架的时候还能释放各种眼花缭乱的技能,我们为这个角色赋予了很多特性,这个时候就需要编写一套状态管理系统来对不同状态之间的切换进行统一的管理。
由于角色在某一时间只会处于一种状态,不可能边飞边站立嘛!,因此适合用有限状态机(FSM)进行管理 ,这篇文章将会以小怪状态管理为例,简单介绍FSM在Unity中的实现。寒假写的代码可以拿来摸鱼啦。
写代码前的构思
首先先,我们需要理清楚不同状态之间的逻辑联系,画好图,才能条理清晰地打出好康的代码。
我们的小怪,设定是在没探测到角色时巡逻,探测到角色时追击,接近敌人时攻击,HP为0时死亡。巡逻的设定是到达巡逻点时站着不动一段时间,然后前往下个巡逻点。
能想到的状态有:
- 站着不动 Idle
- 走向下个巡逻点 Patrol
- 追击 Chase
- 攻击 Attack
- 死亡 Die
还不算很复杂,下面画出好丑好丑好丑的关系图。
下面来写代码啦。
代码展示
接口定义
每种状态独立创建为一个类,都有状态进入,状态进行,状态退出三个的方法(也就是函数,C#中称之为方法),这样能使得写出来的代码比较具有扩展性。(比如扩展成多层状态机?)
既然每种状态写成类,而且每种状态的结构大致相同,那么就需要定义一个接口,来实现对不同状态的调用。
public interface EState
{
void StateIn();
void StateStay();
void StateExit();
}
有了接口,我们就可以写出各个状态的框架啦!
不过先不用着急写各个状态的内容,框架搭好后,就来写SFM了。
搭建FSM
封装小怪的各种参数
public class EParam
{
public int HP;
public float moveSpeed; //巡逻速度
public float chaseSpeed; //追击速度
public float idleTime; //站立时间
public Transform[] partolPoint; //巡逻点
public float chaseRange; //追击范围
public Animator animator; //小怪的动画,如果有的话
public Transform player; //如果检测到玩家,则不为null
public EState current; //当前状态
}
检索状态
由于我们将状态写成类,直接调用费时费力,因此利用到Dictionary来实现不同状态的调用。
//先定义枚举类型StateType作为Dictionary的Key
public enum StateType
{
Idle,Patrol,Chase,Attack,Die
}
public class FSM : MonoBehaviour
{
//以StateType为Key,Estate为value,创建Dictionary对象states
private Dictionary<StateType, EState> states = new Dictionary<StateType, EState>();
public EParam param;
private EState currentState;
//在Start函数中注册状态,并将初始状态设置为Idle
private void Start()
{
states.Add(StateType.Idle, new IdleState(this));
states.Add(StateType.Patrol, new PatrolState(this));
states.Add(StateType.Attack, new AttackState(this));
states.Add(StateType.Die, new DieState(this));
states.Add