收藏
评论

【周知】Android 端将调整小游戏 “在屏 Canvas” 的放缩策略官方

Hi all,

    之后的版本中,微信 Android 端将调整 “在屏 Canvas” 的放缩策略,与 iOS 保持一致。请游戏开发者提前做好适配工作,该修改可能导致游戏界面模糊的问题。望周知。


1. 问题描述

    在之前的版本中,小游戏中,第一个 Canvas 即 “在屏Canvas” ,无论开发者怎样设置 width height,在底层都会将width height放缩为物理像素。(gl.viewport gl.scissor 等接口的底层,我们也做了对应的放缩,所以开发者感知不到这个逻辑)

    这种放缩,会让在屏Canvas无论如何设置 size 都是最清晰的状态。

    但是,这种放缩会使得渲染相对较慢,而有些游戏并不需要这种清晰度;同时也给一些重度游戏在使用 shader 接口时埋了坑,给游戏开发造成了不必要的困难。

    所以我们决定在之后的版本中,Android端去掉这个放缩逻辑,与 iOS 保持一致。


2. 如何适配

   下面用代码举例:在一台 wx.getSystemInfo 中返回 screenWidth = 360  screenHeight = 640 pixelRatio = 3 的机器上。在之前的版本中,你直接绘制文字就是清晰的。现在则需要主动设置

     canvas.width = screenWidth * pixelRatio; canvas.height = screenHeight * pixelRatio;

才能和之前达到一样的效果。

另外,对 “在屏 canvas” 的 width/height 的任何修改和适配,这种适配都不会影响游戏在老版本上的运行

    

如果你使用一些游戏引擎,请查阅游戏引擎的文档,如 cocos ,不需要自己修改 canvas 的宽高,只需要设置

    setRetinaEnable(true)


p.s.

我们自查发现大部分游戏,游戏主场景是没有问题的,但一些 loading 场景,则会有模糊的现象。请注意一下。


42738浏览
收藏

16 个评论

  • VEE
    VEE
    2019-02-01

    上面写的解决方案试过了,没用,白鹭引擎

    启用有黑屏一会儿,声音播放还延迟,整个游戏玩起来卡

    要怎么解决?

    明天都放假了,今天出这档子事,还能不能好好过年啊

    2019-02-01
    赞同 5
    回复
  • panda@Cocos
    panda@Cocos
    2019-01-31

    Cocos Creator 引擎在适配时原本限制了 devicePixelRatio 最大值为 2,因为传统浏览器在 devicePixelRatio 过大时会非常卡顿。但是由于部分手机的基础分辨率过低,2 倍并不能有效提升清晰度,为了解决这个问题,可以尝试下面的方案


    在发布后的 main.js 文件中的 onStart 函数里添加下列代码

    cc.ContainerStrategy.prototype._setupContainer = function (view, w, h) {

       var locCanvas = cc.game.canvas, locContainer = cc.game.container;

       if (!CC_WECHATGAME && cc.sys.os === cc.sys.OS_ANDROID) {

           document.body.style.width = (view._isRotated ? h : w) + 'px';

           document.body.style.height = (view._isRotated ? w : h) + 'px';    }    // Setup style    locContainer.style.width = locCanvas.style.width = w + 'px';    locContainer.style.height = locCanvas.style.height = h + 'px';    // Setup pixel ratio for retina display    var devicePixelRatio = view._devicePixelRatio = 1;

       if (view.isRetinaEnabled()) {        devicePixelRatio = view._devicePixelRatio = window.devicePixelRatio || 1;    }    // Setup canvas    locCanvas.width = w * devicePixelRatio;    locCanvas.height = h * devicePixelRatio; }; cc.view.enableRetina(true);


    为了不每次都更改代码,可以尝试自定义模版:

    https://docs.cocos.com/creator/manual/zh/publish/custom-project-build-template.html

    2019-01-31
    赞同 3
    回复 1
    • 2019-02-12

      大神,请问自定义模块要怎么写

      2019-02-12
      回复
  • keen
    keen
    2019-02-01

    求问,Phaser如何解决,只有安卓会模糊对吧。

    2019-02-01
    赞同 2
    回复 1
    • 自由自在
      自由自在
      2019-02-11

      解决了么? 同phaser 文字发虚 有的场景文字还变小了 而且滑动卡顿

      2019-02-11
      2
      回复
  • 听空
    听空
    2021-07-27

    phaser 2 字体模糊 。这个需要怎么配置。恳请帮忙解决下。

    2021-07-27
    赞同 1
    回复
  • 🐂火星牛
    🐂火星牛
    2020-03-16

    难怪fillText一直模糊。

    按pixelRatio扩大画布,写一个hook.js把context上与像素有关的函数override一下:

    /**
     * 画布缩放,只有sysInfo.pixelRatio扩大画布,贴图和文字才会清晰,但是离屏画布复制到前景时变慢很多。
     */
    
    
    //如果要扩大画布(高清),注释掉这一行
    //wx.tmGlobal.sysInfo.pixelRatio = 1;
    
    
    wx.tmGlobal.canvas.width = wx.tmGlobal.sysInfo.screenWidth * wx.tmGlobal.sysInfo.pixelRatio;
    wx.tmGlobal.canvas.height = wx.tmGlobal.sysInfo.screenHeight * wx.tmGlobal.sysInfo.pixelRatio;
    wx.tmGlobal.bkgCanvas.width = wx.tmGlobal.sysInfo.screenWidth * wx.tmGlobal.sysInfo.pixelRatio;
    wx.tmGlobal.bkgCanvas.height = wx.tmGlobal.sysInfo.screenHeight * wx.tmGlobal.sysInfo.pixelRatio;
    wx.tmGlobal.canvas3.width = wx.tmGlobal.sysInfo.screenWidth * wx.tmGlobal.sysInfo.pixelRatio;
    wx.tmGlobal.canvas3.height = wx.tmGlobal.sysInfo.screenHeight * wx.tmGlobal.sysInfo.pixelRatio;
    
    
    let CanvasRenderingContext2D = wx.tmGlobal.context.constructor;
    
    
    let fn_moveTo=CanvasRenderingContext2D.prototype.moveTo;
    CanvasRenderingContext2D.prototype.moveTo = function (x, y) {
      return fn_moveTo.call(this,
        x * wx.tmGlobal.sysInfo.pixelRatio,
        y * wx.tmGlobal.sysInfo.pixelRatio);
    }
    
    
    let fn_lineTo = CanvasRenderingContext2D.prototype.lineTo;
    CanvasRenderingContext2D.prototype.lineTo = function (x, y) {
      return fn_lineTo.call(this,
        x * wx.tmGlobal.sysInfo.pixelRatio,
        y * wx.tmGlobal.sysInfo.pixelRatio);
    }
    
    
    let fn_strokeRect = CanvasRenderingContext2D.prototype.strokeRect;
    CanvasRenderingContext2D.prototype.strokeRect = function (x, y, w, h) {
      return fn_strokeRect.call(this,
        x * wx.tmGlobal.sysInfo.pixelRatio,
        y * wx.tmGlobal.sysInfo.pixelRatio,
        w * wx.tmGlobal.sysInfo.pixelRatio,
        h * wx.tmGlobal.sysInfo.pixelRatio);
    };
    
    
    let fn_fillRect = CanvasRenderingContext2D.prototype.fillRect;
    CanvasRenderingContext2D.prototype.fillRect = function (x, y, w, h) {
      return fn_fillRect.call(this,
        x * wx.tmGlobal.sysInfo.pixelRatio,
        y * wx.tmGlobal.sysInfo.pixelRatio,
        w * wx.tmGlobal.sysInfo.pixelRatio,
        h * wx.tmGlobal.sysInfo.pixelRatio);
    };
    
    
    let fn_drawImage = CanvasRenderingContext2D.prototype.drawImage;
    CanvasRenderingContext2D.prototype.drawImage = function (img) {
      //console.log(arguments);
      let params = new Array(9);
      if (arguments.length == 3) {
        params[0] = arguments[0];        //img
        params[1] = 0;                   //sx
        params[2] = 0;                   //sy
        params[3] = arguments[0].width;  //sw
        params[4] = arguments[0].height; //sh
        params[5] = arguments[1];        //dx
        params[6] = arguments[2];        //dy
        params[7] = arguments[0].width;  //dw
        params[8] = arguments[0].height; //dh
      }
      else if (arguments.length == 5) {
        params[0] = arguments[0];        //img
        params[1] = 0;                   //sx
        params[2] = 0;                   //sy
        params[3] = arguments[0].width;  //sw
        params[4] = arguments[0].height; //sh
        params[5] = arguments[1];        //dx
        params[6] = arguments[2];        //dy
        params[7] = arguments[3];        //dw
        params[8] = arguments[4];        //dh
      }
      else params = arguments;
      for (let i = 5; i < params.length; i++) {
        params[i] = params[i] * wx.tmGlobal.sysInfo.pixelRatio;
      }
      //console.log(params);
      return fn_drawImage.apply(this, params);
    };
    
    
    let fn_fillText = CanvasRenderingContext2D.prototype.fillText;
    CanvasRenderingContext2D.prototype.fillText = function (s, x, y) {
      return fn_fillText.call(this,
        s, x * wx.tmGlobal.sysInfo.pixelRatio,
        y * wx.tmGlobal.sysInfo.pixelRatio);
    }
    
    
    let fn_createImageData = CanvasRenderingContext2D.prototype.createImageData;
    CanvasRenderingContext2D.prototype.createImageData = function (w, h) {
      return fn_createImageData.call(this,
        w * wx.tmGlobal.sysInfo.pixelRatio, h * wx.tmGlobal.sysInfo.pixelRatio);
    }
    
    
    let fn_getImageData = CanvasRenderingContext2D.prototype.getImageData;
    CanvasRenderingContext2D.prototype.getImageData = function (x, y, w, h) {
      return fn_getImageData.call(this,
        x * wx.tmGlobal.sysInfo.pixelRatio,
        y * wx.tmGlobal.sysInfo.pixelRatio,
        w * wx.tmGlobal.sysInfo.pixelRatio,
        h * wx.tmGlobal.sysInfo.pixelRatio);
    }
    
    
    let fn_putImageData = CanvasRenderingContext2D.prototype.putImageData;
    CanvasRenderingContext2D.prototype.putImageData = function (data, x, y) {
      return fn_putImageData.call(this, data,
        x * wx.tmGlobal.sysInfo.pixelRatio, y * wx.tmGlobal.sysInfo.pixelRatio);
    }
    

    果然清晰了:

    只是两个canvas复制时速度满了很多,应该就是慢piexlRatio倍吧。

    2020-03-16
    赞同
    回复 1
    • 听空
      听空
      2021-07-28
      大佬 这个写在哪里 可否详细的说下 新手  看不太懂 请帮下忙 谢谢
      2021-07-28
      回复
  • 🐂火星牛
    🐂火星牛
    2020-03-15

    难怪fillText画出的文字看起来是模糊的,如何处理呢?

    2020-03-15
    赞同
    回复
  • 邢涛
    邢涛
    2019-03-08

    shader 接口是什么接口?在哪可以查到用法?重度游戏怎么调用shader接口?

    2019-03-08
    赞同
    回复
  • 高雷
    高雷
    2019-02-26


    在安卓机 模拟器上都没问题, 在iphone手机上 显示的不对,如图


    代码如下:




    还需要其他设置才能把iPhone搞定吗?

    2019-02-26
    赞同
    回复 2
    • damonlei
      damonlei
      2019-02-26

      在iphone上具体是什么样?

      2019-02-26
      回复
    • 高雷
      高雷
      2019-02-26回复damonlei

      this.imgDensity = 1; //图片密度

      定义了这个变量 在使用他做判断时


      if (this.imgDensity === 1) //使用1倍密度图片

      却返回了 false


      不知道什么情况啊!


      2019-02-26
      回复
  • 2019-02-19

    Laya项目卡顿大家怎么解决的,求告知

    2019-02-19
    赞同
    回复
  • 龙
    2019-02-12

    试了下,上面提供的方法“可能会”没有用,所以有时候可以尝试一下

    renderer.setSize

    来调整


    2019-02-12
    赞同
    回复

正在加载...

登录 后发表内容