• 微信小游戏 开放数据域 子域多场景切换 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 接入微信小游戏的开放数据域
    转载请标出处。

  • 相关阅读:
    类和迭代器
    使用委托调用函数
    自定义类和集合
    带函数的参数返回函数的最大值
    使用程序调试输出窗口
    自定义类
    类和结构
    全局参数
    带参数的函数返回数组之和
    IS运算符
  • 原文地址:https://www.cnblogs.com/_error/p/14635065.html
Copyright © 2020-2023  润新知