本文 Game Framework 版本:3.1.1
本文 Unity3D 版本:2017.3
更多GF教程和实例:https://github.com/mutouzdl/gameframework_demo.git
转载请注明,原文地址:http://www.benmutou.com/archives/2643
文章来源:笨木头与游戏开发
最近有朋友需要Game Framework状态机的使用教程,所以我就简单说说状态机的用法吧。
本Demo只介绍Game Framework框架状态机的使用方式,至于什么是有限状态机,以及状态机的最佳使用方式,大家自行学习。
1.FsmState(有限状态机基类)
状态机包括角色的各个状态,只要让我们的状态类继承FsmState即可。
在继承FsmState的时候需要指定一个类型,这个类型就是状态的持有者。比如我们有一个英雄,英雄有行走和站立的状态,那么,这些状态的持有者就是这个英雄。
本Demo演示一个英雄的行走和站立状态切换,其中英雄是GameFramework中的Entity,如果大家还记得Demo6的话,我们创建实体的时候需要一个实体逻辑处理类,这个逻辑处理类就可以作为状态的持有者。
我们来看代码:
1 2 3 4 5 6 7 8 9 10 11 |
public class Demo10_ProcedureLaunch : ProcedureBase { protected override void OnEnter(ProcedureOwner procedureOwner) { base.OnEnter(procedureOwner); // 获取框架实体组件 EntityComponent entityComponent = UnityGameFramework.Runtime.GameEntry.GetComponent<EntityComponent>(); // 创建实体 entityComponent.ShowEntity<Demo10_HeroLogic>(1, "Assets/Demo10/CubeEntity.prefab", "EntityGroup"); } } |
在初始场景里加载一个实体,实体的预制体大家自己去源码下载,我就不演示怎么创建这个预制体了。
其中Demo10_HeroLogic是这个实体的逻辑处理类。
于是,站立状态类和行走状态类要这么创建:
public class Demo10_HeroIdleState : FsmState<Demo10_HeroLogic>
public class Demo10_HeroWalkState : FsmState<Demo10_HeroLogic>
和之前说的一样,状态类继承了FsmState,并且需要指定状态的持有者。
2.站立状态类(HeroIdleState)
我们来看看站立状态类的具体实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public class Demo10_HeroIdleState : FsmState<Demo10_HeroLogic> { protected override void OnInit (IFsm<Demo10_HeroLogic> fsm) { } protected override void OnEnter (IFsm<Demo10_HeroLogic> fsm) { Log.Info("进入站立状态"); } protected override void OnUpdate (IFsm<Demo10_HeroLogic> fsm, float elapseSeconds, float realElapseSeconds) { /* 按W、S或者上下方向键移动 */ float inputVertical = Input.GetAxis ("Vertical"); if (inputVertical != 0) { /* 移动 */ ChangeState<Demo10_HeroWalkState>(fsm); } } protected override void OnLeave (IFsm<Demo10_HeroLogic> fsm, bool isShutdown) { } protected override void OnDestroy (IFsm<Demo10_HeroLogic> fsm) { base.OnDestroy (fsm); } } |
是不是角色状态类似曾相识?(旁白:并没有)
没错,你们猜对了,这和流程的生命周期简直一模一样。(旁白:不是的,我压根没有猜过)
因为…流程就是状态类!流程就是状态类!流程就是,状态类。
所以,大家应该和容易理解状态类的用法。
如果我没有瞎猜错的话,对于状态类的各个生命周期,我们用的最多的会是OnEnter(进入状态时调用)和OnUpdate(轮询)。
比如,在进入站立状态时,切换到站立动画,在OnUpdate中判断是否切换到其它状态。这个大家根据实际情况使用。
Demo里的站立状态会判断是否按下了移动键,如果是,则切换到行走状态。
3.行走状态类(HeroWalkState)
至于行走状态,基本上和站立状态一样,只是OnUpdate稍有不同:
如果按下了移动键,则调用状态持有者的Forward函数进行移动(这是自己写的函数,大家看源码即可)。
如果没有按下移动键,则切换回站立状态。
于是,在按下移动键和松开移动键的时候,英雄就会在行走和站立之间不断切换。
4.Owner(持有者)
状态类的每一个生命周期函数都会有一个fsm对象,通过fsm.Owner可以获得状态机持有者对象,这里的Owner就是我们的Demo10_HeroLogic类了。
因此,在各个状态里,可以对持有者进行操作。
5.让状态机启动
状态类有了,持有者有了,但是,它们怎么运作起来?
这个就要看Demo10_HeroLogic类了:
启动状态注意有以下步骤:
a.创建状态数组,有多少个状态类,都加到数组里
b.通过框架的FsmComponent组件的CreateFsm函数创建状态机,需要指定持有者类型、持有者对象、状态数组
c.调用状态机的Start函数启动初始状态,需要指定状态类型
6.运行
OK,现在一切都准备好,下载源码,运行游戏,看看效果吧。
按下键盘的w、s或者上下方向键控制英雄(就是,那个蓝色的方块)移动,如果一切顺利的话,应该要看到以下输出:
我还在场景里创建了地形,这是为了更清除地看到英雄的,咳咳,是蓝色方块的移动。
另外,按A和D还能旋转角度,很厉害吧(所以有个屁用啊)。
好了,状态机的使用就介绍这么多,只要理清了FsmState和持有者,其它的看看API文档就行了。
木大木大,你在切换线程哪部分通过判断VerticalInput的值判断角色状态时,我怎么没办法转换到idle状态,貌似verticalInput值并不能到0,是版本更新的问题吗
你没有按键盘的时候,Input.GetAxis (“Vertical”)的值打印出来是多少呢?
请教下大神,这个例子里假如我想创建两个英雄,也就是我ShowEntity两次 赋予不同的ID,如下:
entityComponent.ShowEntity(1, “Assets/Demo10/CubeEntity.prefab”,
“EntityGroup”);
entityComponent.ShowEntity(2, “Assets/Demo10/CubeEntity.prefab”,
“EntityGroup”);
但是unity却报错了,说FSM已经存在了,如下:
Show entity failure, entity id ‘2’, asset name ‘Assets/Demo10/CubeEntity.prefab’, entity group name ‘EntityGroup’, error message ‘GameFramework.GameFrameworkException: Already exist FSM ‘Demo10_HeroLogic’.
难道说,所有英雄实例都必须公用一个FSM吗? 谢谢。
是因为状态机的名称不能重复,你可以这样创建:(“StateFsm” + this.Id, this, new FsmState [] {
stateFsm = GameEntry.Fsm.CreateFsm
new FightEntityCDIdleState (),
new FightEntityAtkCDState (),
});
第一个参数:【”StateFsm” + this.Id】,这样每个实体的FSM名称都不相同。
请问大神,为什么cube前进的逻辑代码不放在WalkState中去实现而要放在实体logic中去实现呢,我想如果WalkState用来控制行走,那代码放在这里不是更合适吗,不然仅仅只是做状态监测会不会不合理。
我懂了,是不是因为state类并不是继承自MonoBehaviour的原因,所以还是要依赖Logic来操作
也许更准确的原因是,State只是控制状态的转换,具体逻辑,还是由对象自身来实现。
感谢分享,想问问大神现在游戏做的怎么样了 瞻仰瞻仰
就是《炼裙者2第九感》,之前是给玩家群的一点点人测,现在是在TapTap上测试(人也超少),游戏很简陋,不存在瞻仰什么的( ╯□╰ )
感谢~大赞,正在为入门这个框架烦恼时候~看到了你的分享,是我辈楷模~
(●ˇ∀ˇ●)(自豪)
太棒了!相见恨晚!
从讲StarForce第一篇,跟着写到Demo10,逐步了解了GF这个框架的功能,感谢木头的分享!
后面也会自己写一些模块Demo ~。~
哈哈,记得告诉我你发布文章的地方
拜读了,多多学习总是好的!