CocosCreator开源框架SCL之弹框管理

自述

弹框框架,本人已经发过一次贴了,地址,但该文仅仅是介绍该框架的用法,而且当时也的确是为CocosStore准备的一篇介绍,所以没有整体考虑。现在因为我已经考虑整体开源一个开发框架,即上文提到的基于CocosCreator的SCL框架开源白皮书,因此我又重新整理了一系列东西,然后针对该文有些人的评论,我来解释一下。

  1. 的确是个人第一次做开源项目,经验不足,而且需要整理的地方很多,所以我也描述了,时间比较久,而且不会一次性整理出来。
  2. 我个人希望这套框架,不单单是解决某个问题,也不仅仅是造一个重复的轮子,而是学会分析问题、解决问题以及归纳问题。
  3. 开源的意义,除了贡献,另一方面也是想提升自己,以及对框架进行充实,毕竟对个人的力量是有限的,错误也在所难免。
  4. 在上文中,我也提到了,该框架适合休闲类、轻度游戏使用,毕竟性能、功能都没经历过大型项目历练,但普通合成类、模拟经营类,是有线上运行的项目的,而且用户量在百万以上,应该能胜任。
  5. 文章中从头至尾没有提到需要关注公众号才能获取,git地址也附在文末,所以我希望各位评论者能稍微看下文章。
  6. 当然能赞助我一下,比如购买用这个框架开发的小游戏翻棋子游戏,或者关注我的公众号,给我涨粉,那我当然高兴。

正文

弹框的产生

一开始我们面对的需求,可能仅仅只是在游戏中,要最上层显示一个对话框,比如胜利啊、道具提示啊等等,这种需要一个简单的做法就是,在场景中拼了UI界面,然后隐藏起来,然后等需要的时候显示出来,不需要的时候隐藏起来。这样做的好处就是:

  1. 界面与场景相结合,效果一目了解,
  2. 使用简单,仅需控制显示隐藏即可,
  3. 加载完毕后,使用时,几乎没有卡顿等。

但弊端也很明显:

  1. 如果界面较多,加载较慢
  2. 都在场景中,不利于维护,特别是多人协作
  3. 逻辑结构不清楚

这个时候,我们借助prefab,将UI制作成prefab,基本就能解决以上问题了,然而,新的问题就是:

  1. 每次使用需要实例化
  2. 层级不好控制

弹框的进化

以上经历,可能每个人都会遇到,当遇到的次数多了,可能每个人都会想到需要设计一个弹框的管理类。现在,我们就来设计一个吧。

首先我们需要管理什么?

其实就是弹框的显示和隐藏,所以我们的弹框应该是(本文代码皆为伪代码)

show(){
    let node = instantiate(prefab);
    node.parent = parent;
}

hide(node){
    node.destroy();
}

那么,我们后续的实现,都是基于这两个方法进行的,继续我们要实现的东西。

  1. 我们并不需要每次都实例化,可以添加缓存
getNode(name){
    if(!this.nodes.get(name)) {
        let node = createNode();
        this.nodes.set(name, node);
    }
    return this.nodes.get(name);
}
  1. 显示新弹框的时候,旧弹框要不要隐藏的控制
show(isKeep){
    if(!isKeep) {
        hideAllPopup();
    }
}
  1. 有时候,我们有个重要弹框,比如账号弹出提醒,显然,这种弹框是不能覆盖的。

首先,你可以设置两个父节点来控制重要弹框,但这显然脱离了我们的统一控制框架,这里我们使用层级的概念,即低层级的弹框,即使后弹出,也不能覆盖之前弹出的弹框。

show(priority){
    if(cur > priority) {
        addTempList(node);
        return;
    }
}
  1. 传递参数

我们获取node上的节点需要使用

node.getComponent(组件名)

如果每次弹框需要重复调用该方法,并不方便,我们需要考虑集成到show中去,可是组件名每次传递也不方便,所以我们定义一个弹框父类PopupBase,这样,我们获取该父组件即可。

show(params){
    node.getComponent(PopupBase).init(params);
}

我们在这两个方法中,加入我们需要的方法,这样一个完整的弹框管理就出来了。可能就是一个能满足大部分需求的弹框管理了。然后,我们再考虑两个优化:

  1. 加入弹框动画。

在我的方案中,是在show中,加入一个tween,并预置了两个tween:缩放和渐现。

/**
 * 默认的缩放动画
 */
const scaleTween: Tween<Node> = tween().to(0.2, { scale: v3(1.1, 1.1, 1) }).to(0.05, { scale: v3(1, 1, 1) });
/**
 * 默认的渐现动画
 */
const fadeTween: Tween<UIOpacity> = tween().to(0.25, { opacity: 255 });
  1. 放置点击穿透。

在我的方案中,弹框前会先显示一个node,并挂载了拦截组件,当动画播放完毕后,在隐藏。

this.blockInputNode.addComponent(BlockInputEvents);

我们解决了哪些痛点

  1. 弹框的依次显示队列问题
  2. 弹框的优先级问题
  3. 一个prefab可以多次实例化的问题
  4. 弹出过程中,背景穿透的问题

弹框的后续优化

  1. 如何自定义弹框效果?

  2. 如果是多场景方案,需要切换场景,销毁当前场景的弹框,什么方案比较合适?

  3. 资源如何合理销毁?

如果各位有什么好的方案,欢迎在git上提交~

github: https://github.com/dream93/scl
gitee(同步github):https://gitee.com/dream93/scl

因为目前主推3.0 所以我目前主要在整理3.0的版本,2.0版本请使用旧地址的2.x分支,然后参考3.0的部分优化。

github: https://github.com/dream93/ccc_libs

gitee(同步github): https://gitee.com/dream93/ccc_libs

公众号:
wx_gh

3赞

最近正好做这方面的调优,如果prefab实例化的时候,动态加载和实例化的东西有点多的话,弹窗的弹出动画就会有卡顿的效果。如果在show之前,加个prepare阶段(类似于onLoad,唯一的不同时自己可以控制这个阶段需要预加载一些什么东西),这样在真正的需要显示出来active=true的时候,动画会流畅一点

在demo中,提供了一个preload的方法,可以提前预加载prefab