微信小游戲開發(fā)之場景切換和常駐節(jié)點(diǎn)傳遞數(shù)據(jù)

主題

  1. 場景切換
  2. 場景間數(shù)據(jù)傳遞方式
  3. 小游戲全局背景音效

特別說明

CocosCreator微信小游戲開發(fā)系列文章,是我在逐步開發(fā)過程中,基于官方文檔之上,記錄一些重點(diǎn)內(nèi)容脆贵,以及對官方文檔中有些知識點(diǎn)的補(bǔ)充和分析。

正文

引擎同時只會運(yùn)行一個場景起暮,當(dāng)切換新場景時卖氨,默認(rèn)會將當(dāng)前場景內(nèi)所有節(jié)點(diǎn)和其他實(shí)例銷毀。

1. 場景切換

假設(shè)從場景A切換到新場景B,中間會經(jīng)歷那些過程呢双泪?

場景B預(yù)加載preloadScene -> 場景B的onLoad -> 場景B的onStart -> 跳轉(zhuǎn)到場景B -> 場景A資源釋放

//后臺靜默預(yù)加載新場景持搜,
cc.director.preloadScene("table", function () {
    cc.log("Next scene preloaded");
});
//預(yù)加載沒完成,也可以調(diào)用
cc.director.loadScene("MyScene");
1.1 預(yù)加載階段做了什么焙矛?
  • 會加載場景B中引用的靜態(tài)資源葫盼,即屬性檢查器中引用的資源

  • 場景B中cc.resources和cc.assetManager加載的資源屬于動態(tài)加載,不會在preloadScene階段預(yù)加載

1.2 在onLoad和onStart方法中執(zhí)行了過于耗時的操作村斟,會導(dǎo)致頁面黑屏或者跳轉(zhuǎn)到場景B的速度很慢贫导,造成無響應(yīng)的假象。
1.3 場景A資源釋放

場景A中引用的靜態(tài)資源會被自動釋放蟆盹,但是動態(tài)加載的資源則需要開發(fā)者自己手動釋放孩灯。

  • 對場景內(nèi)單個資源的釋放,可以使用release函數(shù):
//cc.resources.load加載的單個資源釋放逾滥,可以調(diào)用cc.resources.release
cc.resources.release("test assets/image", cc.SpriteFrame);
cc.resources.release("test assets/anim");

//也可以使用 cc.assetManager.releaseAsset 來釋放特定的 Asset 實(shí)例峰档。
cc.assetManager.releaseAsset(spriteFrame);
  • 單個資源出現(xiàn)被多個節(jié)點(diǎn)或者組件復(fù)用時,Asset Manager提供了一套基于引用計數(shù)的資源釋放機(jī)制:
//每個組件加載資源時addRef()增加一個資源引用
cc.resources.load('image', cc.SpriteFrame, (err, spriteFrame) => {
  this.spriteFrame = spriteFrame;
  spriteFrame.addRef();
});

//每個組件destroy時寨昙,對應(yīng)的調(diào)用decRef()減少一個資源引用
this.spriteFrame.decRef();
this.spriteFrame = null;

問題場景:

場景A在onLoad中動態(tài)加載了資源D讥巡,切到場景B中也動態(tài)加載了資源D,而根據(jù)引用計數(shù)的資源釋放機(jī)制用法舔哪,在場景A中加載資源D時要addRef = 1欢顷,場景A銷毀時要decRef = 0,資源D被釋放了捉蚤,但是這時候場景B中又動態(tài)加載了資源D要addRef + 1抬驴,就會出現(xiàn)場景B中資源D的isValid=false,導(dǎo)致資源無法顯示了缆巧。而如果不decRef布持,場景B中的資源D會因為refCount不為0,而不會被釋放陕悬。

結(jié)論:

從這個問題理解题暖,引用計數(shù)的資源釋放機(jī)制,應(yīng)當(dāng)是針對單個場景中多個組件引用相同資源D墩莫,才適合引用計數(shù),在場景銷毀時用來控制資源是否銷毀的逞敷。

釋放資源狂秦,要根據(jù)資源在各場景中的實(shí)際使用情形,結(jié)合release和引用計數(shù)來使用推捐。

2. 場景間數(shù)據(jù)傳遞方式

2.1 常駐節(jié)點(diǎn)傳遞數(shù)據(jù)

場景A跳轉(zhuǎn)場景B時裂问,如何傳遞參數(shù)數(shù)據(jù)給場景B使用呢?

“cc.director.loadScene”方法沒有攜帶參數(shù)啟動場景的功能,CocosCreator是通過“常駐節(jié)點(diǎn)”進(jìn)行場景資源管理和參數(shù)傳遞堪簿∪“常駐節(jié)點(diǎn)”怎么理解呢?

當(dāng)切換新場景時椭更,默認(rèn)會將當(dāng)前場景內(nèi)所有節(jié)點(diǎn)和其他實(shí)例銷毀哪审,而所謂“常駐節(jié)點(diǎn)”,是指在場景切換時不被自動銷毀虑瀑,常駐內(nèi)存中的節(jié)點(diǎn)組件湿滓。那這個常駐節(jié)點(diǎn)應(yīng)當(dāng)建在哪里呢?

首先CocosCreator是推薦使用Canvas節(jié)點(diǎn)作為渲染根節(jié)點(diǎn)的舌狗,并且微信小游戲強(qiáng)制要求渲染根節(jié)點(diǎn)必須是Canvas叽奥。常駐節(jié)點(diǎn)創(chuàng)建的位置是和Canvas節(jié)點(diǎn)平級,即不能作為Canvas節(jié)點(diǎn)的子節(jié)點(diǎn)痛侍,而是應(yīng)當(dāng)在場景的根節(jié)點(diǎn)下朝氓,如下圖所示。分析原因可能有兩種:

  • 如果常駐節(jié)點(diǎn)在Canvas內(nèi)主届,因為節(jié)點(diǎn)不會被銷毀赵哲,會導(dǎo)致Canvas節(jié)點(diǎn)也不能銷毀,多切換幾個場景岂膳,內(nèi)存可能就已經(jīng)滿了誓竿;
  • 從節(jié)點(diǎn)功能上看,常駐節(jié)點(diǎn)只是空節(jié)點(diǎn)谈截,而Canvas屬于渲染節(jié)點(diǎn)筷屡,它的子節(jié)點(diǎn)都是用于渲染UI使用,所以也不應(yīng)該放到Canvas節(jié)點(diǎn)下簸喂。
常駐節(jié)點(diǎn)的創(chuàng)建位置

將StartData節(jié)點(diǎn)設(shè)置成常駐節(jié)點(diǎn):

  //添加dataNode為常駐節(jié)點(diǎn)
  cc.game.addPersistRootNode(this.dataNode);
  //設(shè)置dataNode要傳遞的數(shù)據(jù)
  this.dataNode.data = {data : "123"}

在新場景中獲取傳遞的數(shù)據(jù):

  onLoad() {
      //從上一個場景的常駐節(jié)點(diǎn)上獲取當(dāng)前場景需要使用的參數(shù)
      var startData = cc.director.getScene().getChildByName('StartData');
      if (startData) {
          this.data = startData.data;
          // cc.log('頁面?zhèn)鬟f的參數(shù)毙死,從常駐節(jié)點(diǎn)中獲得data:', this.data);
          
          //取消一個節(jié)點(diǎn)的常駐屬性
          cc.game.removePersistRootNode(startData);
      }
      ...
  },

注意: cc.game.removePersistRootNode 并不會立即銷毀指定節(jié)點(diǎn),只是將節(jié)點(diǎn)還原為可在場景切換時銷毀的節(jié)點(diǎn)喻鳄。

2.2 使用全局變量

定義全局變量 window.Global:

  window.Global = {
      data: null
  };

由于所有腳本都強(qiáng)制聲明為 "use strict"扼倘,因此定義全局變量時的 window. 不可省略。
接著在需要使用的地方可直接初始化 Global 并訪問它:

  // home.js

  cc.Class({
      extends: cc.Component,

      onLoad: function () {
          Global.data = { data : "123"};
      },
      
      // start 會在 onLoad 之后執(zhí)行除呵,所以這時 Global 已經(jīng)初始化過了
      start: function () {
          this.txtLabel.string = Global.data.data;
      }
  });

注意:

  • 不推薦濫用全局變量再菊;
  • 訪問全局變量時,需確保全局變量已初始化和賦值颜曾,否則將會拋出異常纠拔;
  • 定義全局變量時,不能和系統(tǒng)已有的全局變量重名泛豪;
  • 你需要小心確保全局變量使用之前都已初始化和賦值稠诲。

3. 小游戲全局背景音效

全局背景音樂的播放侦鹏,看完上面的內(nèi)容應(yīng)當(dāng)知道怎么實(shí)現(xiàn)了吧,如果還不知道做的臀叙,你可以再仔細(xì)往上看一看略水。

  1. 創(chuàng)建常駐節(jié)點(diǎn)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節(jié)點(diǎn)上
掛載AudioManager.js

如果在屬性面板沒有設(shè)置bgMusic播放的音頻資源劝萤,則動態(tài)播放默認(rèn)音頻資源渊涝。

結(jié)尾

既然您看到這了,說明文章對你還有用稳其,幫忙點(diǎn)個贊再走吧驶赏,謝謝!

關(guān)注我的公眾號「掉隊程序員」既鞠,持續(xù)輸出更多內(nèi)容煤傍!

自己動手寫,分解項目中的各個模塊需求嘱蛋,通過查文檔和搜索Cocos社區(qū)蚯姆,解決碰到的問題,最終在微信上線了下面這款微信小游戲《成語錦衣衛(wèi)》洒敏,歡迎大家掃碼體驗龄恋,并作為參考項目模版,開發(fā)出屬于自己的小游戲

歡迎大家掃碼體驗

預(yù)告

下一節(jié)和朋友們說一說:微信登錄功能的實(shí)現(xiàn)凶伙,CocosCreator第三方服務(wù)騰訊TCB云開發(fā)踩坑和微信云開發(fā)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末郭毕,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子函荣,更是在濱河造成了極大的恐慌显押,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件傻挂,死亡現(xiàn)場離奇詭異乘碑,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)金拒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門兽肤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人绪抛,你說我怎么就攤上這事资铡。” “怎么了幢码?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵笤休,是天一觀的道長。 經(jīng)常有香客問我蛤育,道長宛官,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任瓦糕,我火速辦了婚禮底洗,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘咕娄。我一直安慰自己亥揖,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布圣勒。 她就那樣靜靜地躺著喂柒,像睡著了一般课锌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天凛篙,我揣著相機(jī)與錄音,去河邊找鬼卖漫。 笑死捞魁,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的用含。 我是一名探鬼主播矮慕,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼啄骇!你這毒婦竟也來了痴鳄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤缸夹,失蹤者是張志新(化名)和其女友劉穎痪寻,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體明未,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡槽华,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了趟妥。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片猫态。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖披摄,靈堂內(nèi)的尸體忽然破棺而出亲雪,到底是詐尸還是另有隱情,我是刑警寧澤疚膊,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布义辕,位于F島的核電站,受9級特大地震影響寓盗,放射性物質(zhì)發(fā)生泄漏灌砖。R本人自食惡果不足惜璧函,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望基显。 院中可真熱鬧蘸吓,春花似錦、人聲如沸撩幽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽窜醉。三九已至宪萄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間榨惰,已是汗流浹背拜英。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留琅催,地道東北人聊记。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像恢暖,于是被迫代替她去往敵國和親排监。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容