Go 状态模式:状态机 | 青训营笔记

117 阅读2分钟

前言

这两周人工智能课(Unity 3D,C#)在讲到状态机的编写,上一周老师讲的用了一堆 switch 做分支实在是太麻烦,代码复用率也不高。我自己在 U3D Learn 平台上学的角色状态机是用 ScriptableData 来做状态转换。

状态模式

当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。

状态机有3个组成部分:状态(State)、事件(Event)、动作(Action)。事件触发状态的转移及动作的执行。

简单代码实现

首先我们要有一个全局状态机来存放当前状态跟状态切换,状态是一个状态基类类型,子状态继承于状态基类。

package main  
  
import (  
    "fmt"  
    "time"  
)  
  
type fsm struct {  
    state state_base  
}  
  
func (t *fsm) change(state state_base) {  
    t.state = state  
    t.state.execute(t)  
}  
  
type state_base interface {  
    execute(iFsm *fsm)  
    update()  
}  
type state_on struct {  
    mFsm *fsm  
}  
  
func (t *state_on) execute(iFsm *fsm) {  
    t.mFsm = iFsm  
    fmt.Println("on")  
}  
func (t *state_on) update() {  
    t.mFsm.change(new(state_off))  
}  
  
type state_off struct {  
    mFsm *fsm  
}  
  
func (t *state_off) execute(iFsm *fsm) {  
    t.mFsm = iFsm  
    fmt.Println("off")  
}  
func (t *state_off) update() {  
    t.mFsm.change(new(state_on))  
}  
  
func main() {  
    var mFsm fsm  
    mFsm.change(new(state_on))  // 需要给个初始状态
    for {  
        time.Sleep(1 * time.Second)  // 等待 1 秒钟后更新状态
        mFsm.state.update()  
    }  
}

以上代码就是,我定义一个 fsm 为结构体,这是状态机的结构体,里面的 state 是一个基于状态基类 state_base 类型的成员变量,通过 change 方法传递一个新的子状态来进行状态切换。

state_base 接口提供两个方法:executeupdate,前者用于进入状态后执行,后者用于状态切换,在游戏开发中后者需要进行数据验证再进行状态切换。

state_onstate_off 是基于状态基类接口的子类,用于子类状态的功能实现。

如果不了解 interface 和 go 面向对象的可能需要补充一下这方面的知识:www.runoob.com/go/go-inter…

结语

因为刚学 go 没几天,对于 go 面向对象也不太熟悉,之前在 TypeScript 跟 C# 都写过状态机,所以还算是简单的。不过也是尝试写了好几次,前面几次都是因为忘记要改变结构体成员变量的话要使用地址传值,所以一直失败,后面慢慢想起来才记得要用地址传值。

参考资料:

mp.weixin.qq.com/s?__biz=MzU…