状态机管理器FsmManager

背景

  很多需求要求我们需要有全局状态机,比如游戏进程在切屏时,我们需要进入后台状态,实现具体需求,比如后台下载,切屏暂停游戏等。当然我们不止一个全局状态机,为了维护这些全局状态机,方便获取指定全局状态机。框架加入了状态机管理器,主要用于统一管理所有公共状态机,实现状态机的生命周期函数,提供api。

使用

  具体使用逻辑与私有状态机类似,不同的是,由于公共状态机是向状态机管理器申请的状态机,所以不需要自行实现状态机的生命周期函数。优点是,所有类都能通过单例的状态机管理器,获取到该状态机。缺点也很明显,状态类不能拿到持有者对象,所以状态逻辑的实现具有局限性,可以通过传递可变参数、事件系统来满足需求。

声明状态机类

1
2
3
4
5
// 状态机类名用于,标识唯一全局状态机
// class 状态机类名:BaseFsm
public class MyFsm : BaseFsm
{
}

声明状态类

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
// class 状态类名 : IFsmState
public class State1 : IFsmState // 实现接口函数
{
public void OnEnter(params object[] objs)
{
// 可以用事件系统派发事件 OnEnterState1(params)
}

public void OnUpdate()
{
}

public void OnFixedUpdate()
{
}

public void OnExit()
{
}
}

public class State2 : IFsmState
{
// ……同上
}

初始化状态机

  任意地方初始化一次即可。出于后文的层次状态机设计的便利性,状态字典的key不再支持自定义类型,统一用Type类型,即用 状态类名作为状态定义名,通过 typeof(状态类名) 作为实参,所以也不需要状态定义类或枚举。

1
2
3
4
5
6
// 状态机.SetFsm(dict<Type, IFsmState>){状态类键值对}
fsm.SetFsm(new Dictionary<Type, IFsmState>()
{
{typeof(State1),new State1()},
{typeof(State2),new State2()},
});

使用状态机

任意位置都可以获取到该状态机,都可以初始化状态机,用状态机判断状态,切换状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 获取状态机
// FsmManager.Instance.GetFsm<状态机类名>()
var fsm = FsmManager.Instance.GetFsm<MyFsm>();

// 判断当前状态
// 状态机.IsState(typeof(状态类名));
if(fsm.IsState(typeof(State1)))
{
}

// 切换状态 (可变参数用于状态类的 OnEnter(params) )
// 状态机.ChangeFsmState(typeof(状态类名),params object[] 可变参数)
fsm.ChangeFsmState(typeof(State2), 20, 10.2f)

注意事项

  1. 为避免出现不可预测的问题,状态机初始化时,设置了状态字典 SetFsm() 后,并不会设置初始状态,此时处于空状态,需要手动设置初始状态 ChangeFsmState()。

内部实现

状态机管理系统仅维护所有公共状态机,私有状态机详见状态机模板FSM

  1. 为了达到状态机处处可得,处处可用的目的,需要创建单例,外部通过类名即可访问状态机管理器,通过状态机管理器获取需要的状态机。
  2. 为了实现状态机管理器内所有状态机的生命周期函数,需要交由GameManager,传递生命周期函数。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class FsmManager : BaseSingleTon<FsmManager>, IMonoManager
    {
    // IMonoManager的接口函数,由GameManager传递
    public void Update()
    {
    foreach 所有状态机.OnFsmUpdate();
    }

    public void FixedUpdate()
    {
    foreach 所有状态机.OnFsmFixedUpdate();
    }
    }