微信小游戲 開放數據域 子域多場景切換 Cocos


微信開放數據域作為一個獨立的項目,與主項目隔離,但保留主域(游戲主項目)向子域(微信開放數據域)的單向通知功能。
具體步驟,分為以下:

1.主域子域整合

1.1 主域掛載。主域的掛載點(顯示開放數據域的視窗)添加 Cocos組件'SubContextView'

1.2 子域創建。子域項目創建的 Canvas 尺寸與主域掛載點的視窗保持相同尺寸比例,即寬高比例相同。且,Canvas 下的 Main Camera 中需設置攝像機透明度為 0,否則在主域中顯示,會出現一個黑色背景遮罩。

1.3 構建。由於子域也是一個獨立的cocos項目,構建完包體過大,所以主域、子域構建過程需要裁剪一些冗余的引擎(項目-項目設置-模塊設置),以減小整體包體。構建過程,需要注意主項目的 “開放數據域代碼目錄” 與子項目的 “游戲名稱” 須相同,子項目的發布路徑建議指向主項目的發布包目錄下 “開放數據域代碼目錄” 位置。

2.通信及開放數據獲取

2.1 子域監聽。子域中調用 wx.onMessage(function callback) api 來監聽主域發送的消息。

2.2 主域通知。主域需要發送通知時,調用 wx.getOpenDataContext()?.postMessage(Object message),參考 微信小游戲文檔 wx.getOpenDataContext() 部分。

// main.js
wx.getOpenDataContext()?.postMessage({
  type: 'updateMaxScore',
  score,
})

// sub.js
wx.onMessage(data => {
  switch (data.type) {
    case 'updateMaxScore': {
      // do soming:
      break;
    }
})

2.3 開放數據獲取。在子域中調用 wx.setUserCloudStorage(Object object)用來存儲用戶的托管數據(可在主域調用,不建議),調用 wx.getFriendCloudStorage(Object object)用以拉取全部存儲過托管數據的好友的托管數據。

// sub.js
async setUserCloud(score: number, timescope) {
  // 此處數據遵循微信小游戲文檔中,排行榜要求而定。
  // 須以此數據格式,才能被收錄
  let data = {
    wxgame: {
      score,
      update_time: Math.floor(timescope/1000)
    }
  }
  let kvScore = { "key": "maxScore", "value": score + '' };
  let kvTime = { "key": "timescope", "value": timescope + '' };
  // 根據具體業務需要來選擇是否增加以下條目,僅作用於 接收‘排行榜超越提醒’系統通知、小游戲中心排行榜顯示
  let kvRank = { "key": "weekRank", "value": JSON.stringify(data) };
  
  await new Promise((resolve, reject) => {
    wx.setUserCloudStorage({
      KVDataList: [kvScore, kvTime, kvRank],
      success: res => {
        console.warn('openData 推送完成', res)
        resolve(res)
      },
      fail: err => {
        console.log(err);
        reject(err)
      }
    })
  })
}

2.4 其他相關數據。除好友數據外,可以獲取
潛在好友數據 wx.getPotentialFriendList()
用戶自己的數據 wx.getUserCloudStorage()
用戶身份信息 wx.getUserInfo()
群同玩成員的游戲數據 wx.getGroupCloudStorage 等。

2.5 繪制列表(好友排行榜),可通過 ScrollView 組件渲染滾動列表。設置微信頭像:

/** 微信頭像地址不含圖片后綴,需要額外補充 
 * { ext: '.png' }
 */ 否則無法繪制
setRemoteImage( target: cc.Sprite, url: string, confirm?){
  cc.assetManager.loadRemote(url, { ext: '.png' },(err, texture)=>{
    if(err){
      console.error("加載失敗", err)
    }else{
      try{
        // sprite.spriteFrame = new cc.SpriteFrame(texture);
        target.spriteFrame = new cc.SpriteFrame(texture)
        confirm && confirm();
      } catch (error) {
        console.error("加載遠程圖片錯誤 == ", error);
      }
    }
  })
}

3.多場景切換

3.1 對於一個項目而言,只有一個子域,不同場景下的不同尺寸形態,可以看做是一個子域所顯隱的不同部分,通過 wx.postMessage 通知子域切換。

3.2 子域中,不同尺寸的節點,按照所需尺寸設置。wx.onMessage 收到通知后控制顯示隱藏不同的展示節點。並同步設置 Canvas 的尺寸。

/***/
set rankType (type: number) {
  this._rankType = value

  // 控制節點顯隱
  this.node_fullRank.active = !type
  this.node_shortRank.active = !!type
  this.node_potential.active = type=== 1
  this.node_surpass.active = type=== 2
  this.node_topRank.active = type=== 3

  if(type){
    // 形態1
    // 取子域中Canvas組件,並設置其寬高為設計尺寸
    this.node.parent.getComponent(cc.Canvas).designResolution = cc.size(536,358);
    this.node.parent.getComponent(cc.Widget).updateAlignment()
    // 設置掛靠節點寬高為設計尺寸
    this.node.width = 536
    this.node.height = 358
  }else{
    // 形態2
    this.node.parent.getComponent(cc.Canvas).designResolution = cc.size(600,850);
    this.node.parent.getComponent(cc.Widget).updateAlignment()
    this.node.width = 600
    this.node.height = 850
  }
  
}
get rankType () {
  return this._rankType
}
/***/

3.3 主域中切換不同開放域場景后,需及時更新視圖,否則變更后的尺寸會跟隨上一個場景尺寸,導致下一個場景發生拉伸現象。

// ...
wx.getOpenDataContext()?.postMessage({
  type: 'switchRoute',
  value: 1,
})
// ...
canvasUpdate(){
  // 重置視圖尺寸 縮放
  // this.subContext 為主域中 SubContextView 組件
  this.subContext.reset()
  setTimeout(()=>{
    // 更新貼圖 對應觸摸點
    this.subContext.updateSubContextViewport()
    console.log('%c updateContext', 'background: #22aa66;color: #fff')
  }, 1000)
}

詳見 Git: wxGame_utils

注意

  1. 子域畫布繪制到主域后,默認只在首次更新視圖,假如主域的掛載點是在預制體中加載出來,或者有移動過程(彈框的彈出效果),會導致渲染后觸摸事件發生偏移,甚至無效。此時需要手動更新視圖。
    獲取主域掛載點的 SubContextView 組件,調用其 updateSubContextViewportreset方法即可。參考 SubContextView 類型

  2. 子域切換場景過程中,繪制發生偏移,可設置子域 Canvas 組件的 widget 組件的 Align Mode 為 'ALWAYS' ,但是此方法會在子域的每一幀進行對齊,性能消耗大。
    可考慮替代方案,在適當時機(改變節點尺寸后),手動調用widget對齊方法:this.node.parent.getComponent(cc.Widget).updateAlignment()

  3. 文檔中提到,子域會隨着首屏同時加載 onLoad,但是有些機型,仍然會延遲 onLoad事件的調用,直到 subContext 掛載點顯示為 true 才執行。假如wx.onMessage() 定義在onLoad中,就會導致主域向子域的通信 postMessage() 沒法及時監聽到。
    可在顯示subContext 掛載點后延遲執行通知。或在主域的onLoad中,手動推送一個偽通知,觸發子域的onLoad,或在主域中主動調用子域 onLoad:subContextView.onLoad()

  4. 子域界面尺寸發生改變后,無法通過 getComponent(cc.Canvas).designResolution = cc.size(536, 358) 方式來設定 Canvas 節點大小。
    可在主域中主動調用子域 onLoad:subContextView.onLoad()。參考 微信子域界面變形

  5. 兩個開放數據域,快速切換過程中,可能會發生並行行為,前者的邏輯運行在關閉節點后沒有及時中斷,繪制行為在異步執行中,覆蓋了后者的繪制。
    在運行的關鍵環節,增加狀態判斷,控制邏輯運算只在正確的狀態下進行。否則終止。

本文參考 cocos 接入微信小游戲的開放數據域
轉載請標出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM