有限状态机(Finite State Machine)
其在任意时刻都处于有限状态集合中的某一状态。当其获得一个改变信息时,将从当前状态转换到另一个状态,或者仍然保持在当前状态
拿游戏中的人物举例:就是人物无时无刻都是处于某种状态之中的
具体实现时,可以把角色不同的行为分成不同的状态,然后给某一状态写入方法。通过状态机去进行人物不同状态之间的切换
可参考学习:https://www.bilibili.com/video/BV14i4y1o7YF?p=83
使用状态机的理由
在实际开发中,人物可能会有很多状态动作,如果将这些状态动作都写着人物类当中,代码会非常冗杂,并且不好管理。一个对象的状态越多、发生的事件越多,就越适合采用有限状态机的写法。
实例
实例结构
此结构也可以看完后面的步骤再回过来看
一
在cocos creator
页面中先拖放一个精灵节点,为这个精灵节点创建一些像站立、跑步、攻击之类的animation
动画。 然后再在旁边设置一系列动作切换的按钮。
二
创建有限状态机的管理类FSMManager.ts
和状态类FSMState.ts
首先在状态类中,定义StateID
状态 ID,以及stateComponent
状态的拥有者,还有此状态所属的状态管理器fsmManager
export default class FSMState {
// 状态ID
StateID: number = -1;
// 所属的状态拥有者
stateComponent: cc.Component;
// 所属的状态管理器
fsmManager: FSMManager = null;
constructor(StateID: number, stateComponent: cc.Component, fsmManager: FSMManager) {
this.StateID = StateID;
this.stateComponent = stateComponent;
this.fsmManager = fsmManager;
}
// 进入状态
OnEnter() { }
// 状态更新
OnUpdate() { }
}
复制代码
在管理类当中,需要定义状态列表stateList
属性和当前的状态 ID currentID
属性,并且创建改变状态和更新调用方法
export default class FSMManager {
// 状态列表
stateList: FSMState[] = [];
// 当前状态ID
currentID: number = -1;
// 改变状态
changeState(stateID: number) {
this.currentID = stateID;
// 调用新状态id的enter方法
this.stateList[this.currentID].OnEnter();
}
// 更新调用
OnUpdate() {
if (this.currentID != -1) { this.stateList[this.currentID].OnUpdate(); }
}
}
复制代码
三
按照以上两个步骤,FSM 有限状态机的基础类就已经创建完毕了,接下来进行人物类personControl
以及各个动作类的单独编写。 各个基础动作了都继承自状态类FSMState.ts
然后在站立、跑步、攻击各个类中重写OnEnter
进入状态方法。
以下是跑步状态类,其他动作类都与其类似。
export default class runState extends FSMState {
// 进入状态
OnEnter() {
this.stateComponent.getComponent(cc.Animation).play('heroRun');
}
// 状态更新
OnUpdate() { }
}
复制代码
四
在personControl
人物类中,生成一个状态机管理器的实例,将现有的动作类生成实例,然后加入在此实例中的状态列表stateList
。
然后为此人物类创建运动方法,运动方法中只需要调用状态管理类中的changeState
改变状态方法,即可切换人物的状态
PS: 因为一个人物的动作状态可能会有很多,所以可以使用枚举和数组先存储好这些状态的编号以及类,然后在生成状态实例时使用for
循环进行生成
// 创建状态枚举
enum PersonState {
stand = 0,
run,
attack1,
attack2,
attack3
}
let stateClassArr = [
standState,
runState,
attack1,
attack2,
attack3
]
@ccclass
export default class personControl extends cc.Component {
// 动画
ani: cc.Animation;
// 状态机
fsmManager: FSMManager;
// onLoad () {}
start () {
this.ani = this.node.getComponent(cc.Animation);
this.fsmManager = new FSMManager();
// 创建几个动作状态
for(let i in PersonState) {
let index = Number(i);
if (!isNaN(index)) {
this.fsmManager.stateList.push(new stateClassArr[index](index, this, this.fsmManager));
}
}
}
// 站立
stand() {
this.fsmManager.changeState(PersonState.stand);
}
// 跑步
run() {
this.fsmManager.changeState(PersonState.run);
}
// 攻击
attack1() {
this.fsmManager.changeState(PersonState.attack1);
}
attack2() {
this.fsmManager.changeState(PersonState.attack2);
}
attack3() {
this.fsmManager.changeState(PersonState.attack3);
}
update (dt) { }
}
复制代码
五
最后将人物类中各个运动方法绑定到界面的按钮上面,然后运行,发现可以做到人物动作改变了
效果:
评论