通用游戏UI框架的设计与实现 #6
AILHC
started this conversation in
Game Development Blogs
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
前言
这个月月初,我发了几篇文章分享了我写框架的心路历程和一些自己的想法。
感兴趣的可以通过文末链接回顾。
同时我发布了我的第一个开源渐进式H5游戏开发框架: EasyGameFrameworkOpen
提供强大轻量级的核心库:模块管理库 @ailhc/egf-core。可以无缝接入任意引擎游戏项目
以及提供一个基于rollup的typescript库构建工具: @ailhc/egf-cli,可以构建出适合任意引擎项目的js库和单一.d.ts声明文件 类似cocos.d.ts声明文件。
在之前的文章中,我也预告了,还有后续的分享。后续的分享也是关于框架其他库的设计与实现的。
虽然文章还没出,但一直在更新。
大家可以关注框架的github仓库,如果可以,给个star哦。
![](https://camo.githubusercontent.com/c96385ccb20c435df3f50dce6b8cd6028671101dc9f2e83ea7e8656163b34744/68747470733a2f2f636f64696e672d70616765732d6275636b65742d3433343134372d373538383739352d343537342d3336373533352d313235353533303038302e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f696d672f2545362541462539342545352542462538332e6a7067)
为什么鸽了这么久才更新呢?
本来预期是上个星期更新的。
但是涅~( ̄▽ ̄)~*
鸽子🕊 : 别哔哔,鸽了就是鸽了,赶紧进入正题~
我: 好嘞~
背景
做游戏,绝大部分,UI交互界面是必不可少的。
当项目的UI界面多起来的时候,而且策划们的需求千奇百怪,迭代频繁的时候,就会让我们非常头疼。
接下来我将以我稚嫩的笔触分享我是如何分析和解决这个头疼问题的。
这个议题偏向主观和开放,每个人都有自己的业务开发经历和想法,而我就在此抛砖引玉,献丑了。
如有不足,请各位多多指教🙏( •̀ ω •́ )✧
本质需求
我们来看两种情景
策划提了一个需求:一个有五彩斑斓的黑背景的文本提示界面B->程序员去实现界面B的逻辑
点击A按钮->显示B界面
这两个情景就是我们开发中最最最常见,最最最本质的两个需求:
实现UI界面逻辑
调用界面
那么我们头疼也就是这两个需求的实现,我分别讲一下
UI逻辑的实现
UI逻辑的实现是各种各样,需求也是千奇百怪。
而且这个实现可能不是一步就位的,可能还需要迭代,重做等。
那么在这种情况下,我作为UI逻辑的开发者,我希望
这样高可扩展,高自由度,对外界透明可以让开发者更加专注高效地实现和迭代UI逻辑。
UI的调用
我们在项目开发中可能会有各种UI调用的需求:
UI调用最复杂也是最常用的是显示调用,比如
其他常用的是
还有一些特殊的
比如:预加载指定界面(不显示),获取指定界面依赖的资源(用于批量加载多个界面依赖的资源)
除了对功能的需求,还有对接口扩展性的需求
因为在不同项目中,或者不同项目阶段中,可能会增加一些需求,需要扩展接口参数的。
但如果接口参数太多,调用就可能会很长很麻烦。
所以会希望,接口有更强的扩展性,而且在不改动底层的情况增加接口就能实现需求。
回头一看好像是自己给自己挖坑啊。不过造轮子的,不都是自己找坑挖坑吗?
分析完需求,我们就可以着手去设计接口了
接口设计
一个简单的流程图
![框架流程图](https://camo.githubusercontent.com/b595ca5c4f36e479aedc7ba8eed327d9b20f4a9549e4bff7979d6e401a7af1a2/68747470733a2f2f636f64696e672d70616765732d6275636b65742d3433343134372d373538383739352d343537342d3336373533352d313235353533303038302e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f696d672f646973706c61792d6374726c2d6672616d65776f726b2e6a7067)
再看一张UML图
![框架UML](https://camo.githubusercontent.com/7cd2e647e3772cd058c67c82e09a4e13c1600ccc0f2ecd7e77cc311d56521344/68747470733a2f2f636f64696e672d70616765732d6275636b65742d3433343134372d373538383739352d343537342d3336373533352d313235353533303038302e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f696d672f646973706c61792d6374726c2d756d6c6a70672e6a7067)
UI控制器的接口设计
UI控制器的职责就是:实现UI逻辑
这个接口不依赖任何引擎的接口和类。每个引擎项目实现对应的基类
管理器和业务不需要关注UI逻辑是怎么实现的,只需要调用接口并按照对外的数据接口传数据对象就可以了
其他的接口就很简单了,省略
我重点讲一下,onShow这个接口的设计
第一版的设计是
这样的设计,只能实现自定义透传显示数据的,但是要想实现管理逻辑的扩展而不改动onShow接口,就会非常麻烦
比如:
我想扩展管理器,给UI控制传一个显示完成的回调:派发UI显示完成事件,让UI逻辑中动画播放完,或者其他延迟操作结束后调用。
那按照第一版的设计,那么只能加个参数:onShow(onShowData?:any,showEnd?:VoidFunction)
这个时候就是得修改ICtrl这个接口设计了。一个还可以,那如果变成了两个三个四个参数呢?就会变得复杂。
现在的设计就可以解决这个问题,扩展透传的config参数的接口,不会增加接口参数,不改变接口
这个灵感来自axios这个库,一个易用、简洁且高效的http库
关于自定义资源处理实现
有自定义资源处理需求的UI控制器,需要实现这个接口
那么管理器就会调用这个自定义的资源处理接口,而不是走通用的资源处理了
这样的接口设计可以说是在UI被管理的同时,给予了UI逻辑实现者极大的自由度,可以专注高效地实现和迭代,以及任意扩展
极大的自由度是有代价的,就是不能开箱即用。需要去实现接口,其实也很简单,所以这个是值得的。
具体的demo示例可以看:egf-ccc-full中的实现
继续讲UI管理器的设计
UI管理器的设计
UI 管理器的职责就是:提供接口让业务去调用UI
这里有一些TypeScript的类型编程魔法。可以实现及其强大的类型提示。看不懂的可以先忽略,先来讲一下接口设计
在设计这个UI管理接口时,一直念着:职责是管理UI,提供接口调用UI,不做多余的事情。
为什么?因为脑子里总有很多功能想要塞进去,但其实都只是我想要的不必要的功能
所以设计得很克制,资源处理接口外包出去了,因为职责是管理UI,提供接口调用UI
什么栈式UI管理啊,也没有做,因为并不是所有项目都需要,只是特殊需求。
所有项目都需要的是:管理UI,提供接口调用UI。
既然讲到管理UI,那游戏开发中都有哪些UI呢?
如果按具体的讲,各有各的说法,什么Dialog啊,Tips啊,Window啊等等,说不完的!
我抽象一下,按照同时存在多少个UI实例来分:只有两种类型的UI
单例UI
比如:通用加载界面,养成界面,角色展示界面,战斗界面等等,同时有且仅有一个实例存在
![角色展示](https://camo.githubusercontent.com/e563488636cdc549ee70255074a3a9694faf270ad8817b9d6a715106c47bdbb9/68747470733a2f2f636f64696e672d70616765732d6275636b65742d3433343134372d373538383739352d343537342d3336373533352d313235353533303038302e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f696d672f61666b2545382541372539322545382538392542322545352542312539352545372541342542412545372539352538432545392539442541322e706e67)
多实例UI
![属性提升tips](https://camo.githubusercontent.com/e84334822c5e405c28c1405646138f29bd1914aafa3ca8f76533e7a76105944e/68747470733a2f2f636f64696e672d70616765732d6275636b65742d3433343134372d373538383739352d343537342d3336373533352d313235353533303038302e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f696d672f536e617073686f745f32303230313231333231353931382e706e67)
比如:奖励获得tips,属性提升tips
那业务逻辑通过UI管理器
这个抽象逻辑是我能想到的所有游戏项目都通用的逻辑。
那UI管理的接口设计就应该是:提供调用单例UI和多实例UI的接口。仅此
大家估计都看到了很多特殊的类型声明,下面我简单的讲一下这些类型声明的作用
类型提示优化
如果想要更加舒适的接口调用体验,那么就必须榨干typescript的类型系统提供的能力(ps:有为什么不用?)
为什么要设计这样的类型提示?
关于typescript类型编程参考资料
编写TypeScript工具类型,你需要知道的知识
TypeScript 的工具类型
深入 TypeScript 的类型系统
TypeScript系列(三)从编程语言到Conditional Types
其他可能性
虽然这篇文章讲的是UI管理框架
但其实我代码里和接口设计的方向并不限制只是UI管理,你可以用于管理各种抽象显示单位
UI只是其中一种,这个抽象显示单位可以是
它不只是UI框架,它是通用显示管理框架
总结
关于UI框架的设计,提出UI业务实现中的两个本质的需求
分析本质需求,提出更加细化的需求
根据需求设计和实现了一套跨引擎零依赖高效灵活高可扩展的UI框架。
适用于所有游戏引擎项目,可以根据自身需求任意扩展
并且通过研究typescript的类型编程,为接口调用提供了超级舒适的类型提示
具体的实现逻辑和CocosCreator2.4.2的demo,大家可以移步框架
GitHub仓库:
EasyGameFrameworkOpen
如果觉得不错,大家可以给个star,谢谢~
谢谢大家阅读我的文章~
最后
欢迎关注我的公众号,更多内容持续更新
公众号搜索:玩转游戏开发
或扫码:![img](https://camo.githubusercontent.com/ff49d98c6bae1df436218b70bc0fd0aa05623561731a0695efbfcda84a86dfe6/68747470733a2f2f636f64696e672d70616765732d6275636b65742d3433343134372d373538383739352d343537342d3336373533352d313235353533303038302e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f696d672f32303230313132383136343032332e706e67)
QQ 群: 1103157878 (欢迎前来讨论吹水)
博客主页: https://ailhc.github.io/
掘金: https://juejin.cn/user/3069492195769469
github: https://github.com/AILHC
Beta Was this translation helpful? Give feedback.
All reactions