游戏UI管理的一点思考:如何优雅地处理复杂的窗口层级

有的时候还有优先级,那就上优先级队列,不讲究的话拿数组操作也行

还有那种启动过程中 策划要求关一个框再弹下一个框的, 那就再做一个等待队列

哈哈哈哈
越来越复杂了,根据项目情况灵活调整

这个真的最开始怎么设计都有问题,策划要每个道具有不同的获取途径,可以直接跳转各个玩法或者功能,然后还能返回。这种还很容易出bug…

应该是跳转到不同的界面,有的能返回,有的不能返回

其实就算是分层弹窗,也可以维护一个打开队列的。你说的这种情况,打开e后一般可以隐藏pop层,关闭e后恢复pop层

:expressionless:我们项目还要求打开界面后,不能看到有任意资源加载的过程(说是图片出现闪现的情况,其实就是图片资源还没加载完),就是先打开界面,图片还在加载,加载完显示资源,觉得这个体验不好。。。硬是给做成了等所有资源加载完再显示界面,后来又说界面打开太久了。。。尼玛了。换谁来都做不了这两者兼顾的

嗯。同意lz的做法,我们就是这样的。

有人提倡stack的做法,在实际用下来,硬分层对一些批量操作更加友好,例如Hide / CloseAll(Layer.PopUp)等。而且有些层级可以有特殊处理方式,例如不同的摄像机或者拉伸策略等。所以如果确有stack的需求,可以在某几层内部做一个stack就好。

我们还有一个UI的Cache策略,就是Close并不是马上释放资源,而是做一个超时释放(例如半分钟)机制。这样在一段时间内再次open会快很多。

分层机制相对比较直观。我个人的框架就分了 8 层。默认打开的界面放到 UI 层就好了。
但分层和不分层本质是一样的,就像一维数组和二维数组的区别而已。只是哪种表达让你更习惯而已。一旦写好管理器,分不分层,都是管理器内部的事情,没什么区别。

另外说2个:UI 的关闭,以及 UI 的交互。

第一点:UI 的关闭,应该通过自身提供 closeSelf 这样的方法,这个方法本质是通过 UI 管理器去删除自身。

第二点: 一个新 UI 打开的时候,如何处理其他的界面:
一种是主动式的,就是主动去控制其他类型的界面应该怎么处理(比如说 lz 提到的 HideAll 这样的配置,这种配置其实不太全面,因为新的界面并不知道其他界面的特性,比如优先级)。
另一种是被动式的,就是新界面弹出的时候,主动广播自身特性,其他界面去监听这种信息,然后结合自身特性去做处理。这种就相当于给每个打开的界面创建一个【UI 交互】对象,这个对象里去定义其他特性和自身特性的交集,然后做出反馈。(UI 一定是相互的行为,所以这种考虑彼此特性的设计才比较通用)

典型的既要又要 :joy:。他这个需求只能把预制体等资源提前加载了,不要等点开时再加载了,这样搞你整个资源管理方案都要大改了

我抬一下这个地方的杠,还是有区别的,分层在场景树上,每个层级都是一个单独父节点,方便做隐藏,设置拉伸等操作。挂一些对本层界面的处理也方便。

意思是两者表达是等价的。只要封装好了管理器,用起来就是一样的。
只是一维的表达不直观,不利于后续扩展,所以推荐还是要分层表达。

核心还是在于交互行为。一个新的界面打开、关闭、隐藏、复用后显示,其他界面如何去响应。
我认为应该是【每个界面额外引入一个响应规则对象】

不同的层的【响应规则对象】通常情况下走各自层级默认。
特殊界面和其他界面有特殊交互行为,响应规则对象就增加【响应规则】即可。
界面管理器根据【响应规则】对各个界面做响应。

:pleading_face:进游戏前提前加载又会占用内存(再细分一点的话,就是需要根据模块开启来做按需加载预制体、或者资源的配置,做成动态加载的),又需要控制内存,又需要处理成按需加载。。。之前也说过了,这两者一般各自取舍,又或者想要界面打开快,那么就在其他资源加载完显示的时候作牺牲,或者显示的时候做个展示效果也行,做不到既要又要。既要又要的这种,换一个更强的引擎都做不了(因为对于玩家,万一特么手机就是低端机玩的,又要兼顾低端机)

:upside_down_face:然后我发现cocos的资源格式,全都是json文件、以及一堆的字符串占用,项目越大,文件数越多,非贴图内存都占用贼多。。。

这公司入职半年,这个项目根本没有什么框架、架构的,都随便写的,用的2.4.11的引擎版本,2个月后,说现在的引擎版本不满足做3D小游戏,要整个项目升级到3.8.5.。。。简直日了 :upside_down_face:

是预制体资源不释放是吗?节点实例呢?缓存不?

是的,折中的方案就是你说的按模块来加载。比如进游戏先加载好一级界面,打开某一级界面就加载下边的二级界面。这样就要你改整个资源管理了。

如果做了纹理压缩和资源释放,纹理其实占不了太多内存。我做过实验,一个空的Empty2D的工程打小游戏去微信做云测试都有快600M内存

节点缓存不缓存都可以,我们是缓存的。

挺全面的,不过窗口注册我习惯写分包的公共模块里,去走公共单例,注册窗口配置,好处就是维护比较统一,也支持风格化配置
prefab,都是以 uiXx 或者 xxUI 结尾,创建即会生成模板配置代码,刚开始用 windowXx 嫌弃太长了,都用 UIMgr,强迫症了都