引擎:CocoCreator2.1.0
语言:TypeScript
Git仓库地址:https://github.com/superXfx/GameDesignPatterns.git
定义——
允许对象通过改变 内部状态 来改变它的 行为。看起来就像是改变了它的类。
简而言之状态即是行为,通过改变状态来改变行为,改变状态可以是对象本身或其管理者。
此demo中使用状态机来实现拖动触发器的逻辑。
类图——
状态切换图——
从类图中我们可以发现StateMachine ,StateFactory ,StateBase ,CtrlBase类占据比重非常大,并且是独立与具体业务逻辑存在的。
这么做的好处是,当我需要 基于状态机 实现业务逻辑时,可以不受游戏引擎,甚至平台,语言的限制,而做到“架构”上的统一,并且业务层永远不需要知晓或修改以上类的代码。
另外,当项目有多名开发者时,使用 给予状态机的架构 可以将编码风格统一起来,当交叉维护时只需要读一读定义状态枚举的文件(此游戏中命名为Const_State_Drag,下面会看到),就可以理解整个游戏的逻辑。
下面我们来看看代码的具体实现。
实现业务逻辑分四步
1、思考状态的划分并定义状态枚举
2、实现状态类
3、实现状态工厂类
4、实现ctrl类
<第一步> ——思考状态的划分并定义状态枚举
每个枚举对应一个ctrl类,用来管理对应的组件,从状态枚举可以很容易的理解状态机的运行流程。
详情见上面的“状态切换图”
<第二步> ——实现状态类
每个状态定义一个继承StateBase的状态类。交由StateMatch的管理和切换。
这样状态间是解耦的,互相不需要知道彼此的存在。
<第三步> ——实现状态工厂类
调用其创建状态实例,实现状态机与状态的解耦。
<第四步> ——实现ctrl类
最核心的就是这一句—— this.setFSM( new StateMachine( this, new StateFactory()) );
为ctrl赋值一个 状态机 并且传入对应的 状态工厂。
这样整个状态机体系就搭建起来了。
下面详细分析DragCtrl
DragCtrl负责管理自身和OptionCtrl ,AnswerCtrl的状态切换,这么做的理由是为了避免“意大利面条”式的逻辑切换,这是状态机天然的缺点——所以将切换集中在一处。
touchMove(),touchEnd()函数将选中Option的设为Move态,实现拖动
在touchEnd()则判断如果没有放到AnswerCtrl区则将状态改为Back,这样OptionCtrl就飞回原处。
放到AnswerCtrl区的话,则将AnswerCtrl改为ShowAnswer态。
综上,在实际项目中,结合状态机和组件开发思想,将“组件”的逻辑分成多个状态,可以很容易的理解和扩展它。
我的经验是将game运行流程分为loading,playing,win,fail等。
具体组件有若干个状态,组件之间严格解耦。
只有gameCtrl起到“胶水”的作用,知晓其他组件的存在,并控制组件的状态切换。
下一篇,游戏设计模式 之 策略模式
https://www.jianshu.com/p/14b7ae0effd3
效率工具——代码半自动化生成——码妖
https://www.jianshu.com/p/882fc17ccbde