前言
这两周人工智能课(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 接口提供两个方法:execute 和 update,前者用于进入状态后执行,后者用于状态切换,在游戏开发中后者需要进行数据验证再进行状态切换。
state_on 和 state_off 是基于状态基类接口的子类,用于子类状态的功能实现。
如果不了解 interface 和 go 面向对象的可能需要补充一下这方面的知识:www.runoob.com/go/go-inter…
结语
因为刚学 go 没几天,对于 go 面向对象也不太熟悉,之前在 TypeScript 跟 C# 都写过状态机,所以还算是简单的。不过也是尝试写了好几次,前面几次都是因为忘记要改变结构体成员变量的话要使用地址传值,所以一直失败,后面慢慢想起来才记得要用地址传值。