想要一个在项目任意地方调用的直接打开游戏页面的单例实现方案

看标题可能大家没太明白我的需求,我举个例子:
例如现在有一个首页页面的预制件:panel_main
和一个对应的脚本组件:MainPanel.ts
常用做单例的做法就是:
private static _ins: MainPanel = null;
public static get Ins() {
return this._ins;
}
onLoad() {
MainPanel._ins = this;
}

但是这样会有一个问题的,因为必须要onLoad后才能得到单例实力,所以必须要通过其他方式先加载进场景,总之首次调用MainPanel .Ins的时候是得不到实例的。

所以我就想做个Panel的基类Panel.ts继承cc.Component.
Panel实现open()方法,MainPane继承Panel
然后在项目的任意代码任意时刻都能直接通过MainPanel.Ins.open()来弹出页面,但是这样也还是解决不了首次需要加载预制件有回调的问题,首次无法得到MainPanel.Ins。
求大佬指点有没有好的方案,让我首次也直接能MainPanel.Ins.open()打开页面的比较好的实现方案。关键是首次需要加载panel_main预制件并且创建节点。


let viewObj = { "prefabName": node };

public open(prefabName, openCall)
{
    let node = viewObj[prefabName];
    if (!node) {
        createNode().then((node) => {
            addNode();
            viewObj[prefabName] = node;
            openCall();
        })
    }
    else {
        addNode(node);
    }

}

大概这样子,然后这样子。

node是用prefab生成出来的,而又希望绑定的class是单例。如果万一有需要node多个打开的需求,class单例的指向就会混乱。
可否把class不要写成组件,单纯的class用来管理prefab的加载和创建node和show和hide,这个class本身是个单例。
或者用处理单例的管理方法,类似getSingle(MainPanel).show();
getSingle会生成MainPanel的单例。

感谢你的分享,我之前就是这么做的,如果没有就创建,但创建的时候必然有回调,打开是可以通过回调打开,不过首次调用还是没法获得单例。

我只对游戏页面做单例,普通UI节点不会这样做的。游戏页面一般都是唯一的

没明白你的具体需求,不过贴一个我的全局加载提示框的处理方式,看是否符合你的最终需求。实现思路不是同一种方式。

export default class Loading {

  static loading?: cc.Node

  static active = false

  static show(str: string) {

    this.active = true

    if (!cc.isValid(this.loading)) {

      cc.loader.loadRes('prefabs/loading', cc.Prefab, (err, prefab) => {

        if (err) {

          cc.error(err.message || err)

          return

        }

        if (this.active) {

          this.loading = cc.instantiate(prefab) as cc.Node

          cc.find('text/label_text', this.loading).getComponent(cc.Label).string = str

          cc.find('Canvas/content', cc.director.getScene()).addChild(this.loading)

        }

      })

    } else {

      cc.find('text/label_text', this.loading).getComponent(cc.Label).string = str

    }

  }

  static hide() {

    this.active = false

    cc.isValid(this.loading) && this.loading.destroy()

  }

}

任意文件需要用时引入:

import Loading from '../utils/loading'

Loading.show('游戏加载中')

Loading.hide()

感谢你哈!如果我的MainPanel.ts也用普通类的话,按你这个方案是完全没毛病的,之前在laya和egret上都是这样做的,这次我是想用cc.Component的生命周期和接口,所以我就既想要你这种方便的单例调用又想要作为组件挂在节点上,看来我太贪了!还是使用普通单例吧!