微信小游戏开发之场景切换和常驻节点传递数据

主题

  1. 场景切换
  2. 场景间数据传递方式
  3. 小游戏全局背景音效

特别说明

CocosCreator微信小游戏开发系列文章,是我在逐步开发过程中,基于官方文档之上,记录一些重点内容,以及对官方文档中有些知识点的补充和分析。

正文

引擎同时只会运行一个场景,当切换新场景时,默认会将当前场景内所有节点和其他实例销毁。

1. 场景切换

假设从场景A切换到新场景B,中间会经历那些过程呢?

场景B预加载preloadScene -> 场景B的onLoad -> 场景B的onStart -> 跳转到场景B -> 场景A资源释放

//后台静默预加载新场景,
cc.director.preloadScene("table", function () {
    cc.log("Next scene preloaded");
});
//预加载没完成,也可以调用
cc.director.loadScene("MyScene");
1.1 预加载阶段做了什么?
  • 会加载场景B中引用的静态资源,即属性检查器中引用的资源

  • 场景B中cc.resources和cc.assetManager加载的资源属于动态加载,不会在preloadScene阶段预加载

1.2 在onLoad和onStart方法中执行了过于耗时的操作,会导致页面黑屏或者跳转到场景B的速度很慢,造成无响应的假象。
1.3 场景A资源释放

场景A中引用的静态资源会被自动释放,但是动态加载的资源则需要开发者自己手动释放。

  • 对场景内单个资源的释放,可以使用release函数:
//cc.resources.load加载的单个资源释放,可以调用cc.resources.release
cc.resources.release("test assets/image", cc.SpriteFrame);
cc.resources.release("test assets/anim");

//也可以使用 cc.assetManager.releaseAsset 来释放特定的 Asset 实例。
cc.assetManager.releaseAsset(spriteFrame);
  • 单个资源出现被多个节点或者组件复用时,Asset Manager提供了一套基于引用计数的资源释放机制:
//每个组件加载资源时addRef()增加一个资源引用
cc.resources.load('image', cc.SpriteFrame, (err, spriteFrame) => {
  this.spriteFrame = spriteFrame;
  spriteFrame.addRef();
});

//每个组件destroy时,对应的调用decRef()减少一个资源引用
this.spriteFrame.decRef();
this.spriteFrame = null;

问题场景:

场景A在onLoad中动态加载了资源D,切到场景B中也动态加载了资源D,而根据引用计数的资源释放机制用法,在场景A中加载资源D时要addRef = 1,场景A销毁时要decRef = 0,资源D被释放了,但是这时候场景B中又动态加载了资源D要addRef + 1,就会出现场景B中资源D的isValid=false,导致资源无法显示了。而如果不decRef,场景B中的资源D会因为refCount不为0,而不会被释放。

结论:

从这个问题理解,引用计数的资源释放机制,应当是针对单个场景中多个组件引用相同资源D,才适合引用计数,在场景销毁时用来控制资源是否销毁的。

释放资源,要根据资源在各场景中的实际使用情形,结合release和引用计数来使用。

2. 场景间数据传递方式

2.1 常驻节点传递数据

场景A跳转场景B时,如何传递参数数据给场景B使用呢?

“cc.director.loadScene”方法没有携带参数启动场景的功能,CocosCreator是通过“常驻节点”进行场景资源管理和参数传递。“常驻节点”怎么理解呢?

当切换新场景时,默认会将当前场景内所有节点和其他实例销毁,而所谓“常驻节点”,是指在场景切换时不被自动销毁,常驻内存中的节点组件。那这个常驻节点应当建在哪里呢?

首先CocosCreator是推荐使用Canvas节点作为渲染根节点的,并且微信小游戏强制要求渲染根节点必须是Canvas。常驻节点创建的位置是和Canvas节点平级,即不能作为Canvas节点的子节点,而是应当在场景的根节点下,如下图所示。分析原因可能有两种:

  • 如果常驻节点在Canvas内,因为节点不会被销毁,会导致Canvas节点也不能销毁,多切换几个场景,内存可能就已经满了;
  • 从节点功能上看,常驻节点只是空节点,而Canvas属于渲染节点,它的子节点都是用于渲染UI使用,所以也不应该放到Canvas节点下。
常驻节点的创建位置

将StartData节点设置成常驻节点:

  //添加dataNode为常驻节点
  cc.game.addPersistRootNode(this.dataNode);
  //设置dataNode要传递的数据
  this.dataNode.data = {data : "123"}

在新场景中获取传递的数据:

  onLoad() {
      //从上一个场景的常驻节点上获取当前场景需要使用的参数
      var startData = cc.director.getScene().getChildByName('StartData');
      if (startData) {
          this.data = startData.data;
          // cc.log('页面传递的参数,从常驻节点中获得data:', this.data);
          
          //取消一个节点的常驻属性
          cc.game.removePersistRootNode(startData);
      }
      ...
  },

注意: cc.game.removePersistRootNode 并不会立即销毁指定节点,只是将节点还原为可在场景切换时销毁的节点。

2.2 使用全局变量

定义全局变量 window.Global:

  window.Global = {
      data: null
  };

由于所有脚本都强制声明为 "use strict",因此定义全局变量时的 window. 不可省略。
接着在需要使用的地方可直接初始化 Global 并访问它:

  // home.js

  cc.Class({
      extends: cc.Component,

      onLoad: function () {
          Global.data = { data : "123"};
      },
      
      // start 会在 onLoad 之后执行,所以这时 Global 已经初始化过了
      start: function () {
          this.txtLabel.string = Global.data.data;
      }
  });

注意:

  • 不推荐滥用全局变量;
  • 访问全局变量时,需确保全局变量已初始化和赋值,否则将会抛出异常;
  • 定义全局变量时,不能和系统已有的全局变量重名;
  • 你需要小心确保全局变量使用之前都已初始化和赋值。

3. 小游戏全局背景音效

全局背景音乐的播放,看完上面的内容应当知道怎么实现了吧,如果还不知道做的,你可以再仔细往上看一看。

  1. 创建常驻节点AudioNode

  2. 编写AudioManager.js音乐播放脚本

cc.Class({
  extends: cc.Component,

  properties: {
      bgMusic: {
          url: cc.AudioClip,
          default: null
      },
  },

  onLoad() {
      cc.game.addPersistRootNode(this.node);

      if (!this.bgMusic) {
            cc.assetManager.loadRemote('https://www.test.com/game_bgm.mp3', function(err, audio) {
                if (err) {
                    console.log("加载失败:" + err);
                }
    
                if (audio instanceof cc.AudioClip) {
                    this.bgMusic = audio;
                    //停止再开启背景音乐
                    this.playBgMusic();
                }
            }.bind(this));
        } else {
            this.playBgMusic();
        }
  },


  playBgMusic() {
      if (this.bgMusic) {
          this.bgMusicChannel = cc.audioEngine.play(this.bgMusic, true, 0.3)
      }
  },

  stopBgMusic: function () {
      if (this.bgMusicChannel !== undefined) {
          cc.audioEngine.stop(this.bgMusicChannel);
          this.bgMusicChannel = undefined;
      }
  },

});
  1. 把AudioManager.js脚本挂载到AudioNode节点上
挂载AudioManager.js

如果在属性面板没有设置bgMusic播放的音频资源,则动态播放默认音频资源。

结尾

既然您看到这了,说明文章对你还有用,帮忙点个赞再走吧,谢谢!

关注我的公众号「掉队程序员」,持续输出更多内容!

自己动手写,分解项目中的各个模块需求,通过查文档和搜索Cocos社区,解决碰到的问题,最终在微信上线了下面这款微信小游戏《成语锦衣卫》,欢迎大家扫码体验,并作为参考项目模版,开发出属于自己的小游戏

欢迎大家扫码体验

预告

下一节和朋友们说一说:微信登录功能的实现,CocosCreator第三方服务腾讯TCB云开发踩坑和微信云开发

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容