随着游戏开发的完整度提高,技能系统的设计复杂性也愈来愈高,致使了用模板方式的配置方法和处理方法会致使如下几个问题:前端
- 代码冗余
- 排错困难
- 配置项冗余
- 熟悉业务流程时间长
- 扩展性低
通过我思考决定重写之。分析如下几个观点,因为早期设计上的局限,和实际开发预期的不符,技能系统也必然会成为策划脑洞大开的一个点,而且也会成为MOBA游戏体验的深度核心项之一。因而一个成熟的MOBA技能系统应该包含一下几点:编程
- 代码流程清晰
- 错误定位精确
- 配置项定位精确
- 熟悉业务流程时间短
- 扩展性强
应该还有一些我没有想到或者没有记录到的点,在此就说明以上几个。设计模式
有一些程序在设计一些高扩展性同时又是核心要素的系统时,不出意外的也会遇到以上的几个问题。安全
这里的核心关键就是:架构
在设计之初对将来的需求是未知且不可预测的。编辑器
那么我是怎么解决以上的几个问题的呢?函数
由于我一直在使用 Unity 作前端开发。深知Unity的ECS (实体组件系统) 架构体系带来的便利。spa
因而我打算根据ECS的架构方式的模子去设计,但不彻底根据ECS的架构来,保持对具体项目需求的贴切。设计
因而我设计了以下三个层:对象
- 流程控制层
- 原子函数层(技能)
- 逻辑层(技能)
有时候我认为这个设计很像行为树。好吧确实有点像,但又不是那么像。这里不深究,留疑。核心仍是留在解决需求上。
流程控制层具有如下几个组件:
- CtrlBase -> 做为全部流程控制的基类
- CtrlBreak -> 用于中断全部流程控制组件
- CtrlCondition -> 用于流程控制中的分支操做
- CtrlDelayTime -> 用于流程控制中的延时执行操做
- CtrlDuration -> 用于在一段时间内执行一组动做
- CtrlSequence -> 用于序列执行一组动做
- CtrlTimeLine 组件 -> 用于建立一个时间轴,让全部流程组件在这个时间轴上执行
原子函数层(技能)具有如下几个组件:
- SkillCondition -> 提供技能条件的断定
- SkillEntity -> 提供技能实体的操做
- SkillFightObjMap -> 提供战斗对象查询获取等操做
- SkillInOutValueToPlayer -> 提供对战斗对象角色的数值输入输出
- SkillPlayuerCtrl -> 提供对角色的控制操做
- SkillTarget -> 提供技能对象的具体信息
逻辑层(技能):
- SkillBase -> 全部逻辑层的基类 定义全部的技能逻辑层数据
- Hero1/skill_1 -> 英雄1的技能1逻辑对象
- Hero2/skill_2 -> 英雄2的技能2逻辑对象
- ...类推
从以上的结构中能够直接看出目前的冗余层在逻辑层,而逻辑层的支撑在控制层和原子函数层,随着开发深度的愈来愈高,控制层和原子函数层的操做组件会愈来愈多或功能性愈来愈强。则为逻辑层提供的操做/组合方式更为丰富,则可实现的动做会更为强大。
而且从排错来讲只要控制层和原子层确保无误(实际也必须无误),基本错误定位能直接找到对应技能的逻辑层,且逻辑层没有多余代码,每一句都和技能的具体逻辑有所关联,线性排错。难度低。如若错误出在原子或控制层则是一批技能同时出现问题,也好定位。
因此这里已经作到代码流程清晰,错误定位精确。
同时由于每一个技能有独立逻辑层则配置的定义也能够独立,这里也作到了配置项定位精确。
基于以上几点精肯定位的特性致使熟悉业务的时间就所以变短了。
又由于原子函数层/控制层的支持性可扩展,具体技能的业务逻辑可定制,因此扩展性强了。
基于这种设计模式,带来的好处可见是很是大的,可是同时也致使了必需要让程序长期来维护或定制具体的技能模块。因此我一直认为策划是能够具有一些脚本功底的,只要咱们保证原子函数层和控制层提供的是安全接口。则能够对策划放开脚本编写,甚至能够用弱类型解析类脚本语言来提供具体的技能逻辑定制。
还有一种方案是开发一款可以生成逻辑层的流程编辑器,将原子函数层和控制层反射导入。生成逻辑层代码。不过这个成本过高并且规则很差定制。有可能还没程序直接编程性价比更高。因此我没有选择开发流程编辑器的方式。
这个架构在我实际运用中,感受仍是很是好的,由于大多的技能其实类似性仍是蛮高的,若是技能难度不高,原子函数不须要迭代添加,则进行逻辑组合的时候实际效率很高。我刚刚开发完这套系统,重构现有的技能(10个左右)也就花了3个小时左右吧。相比模板开发的方式我认为在定制和排错扩展的方面效率要高的多,并且对开发者的友好度更高。
总结下来我认为全部的设计都应该创建在更贴切实际开发需求上,我认为全部的系统设计都应该创建在需求的不可预知和灵活性扩展上,同时也须要衡量它的性价比,不作过分设计,不墨守成规。