微信小游戏花屏

周末手痒,试了试微信小游戏的开发,写了个俄罗斯方块,名曰“漫打俄罗斯方块”。

先创建画布:

/**
 * 俄罗斯方块
 * @author wxh
 */
wx.tmGlobal = {
  name:"清新俄罗斯方块"
};
wx.tmGlobal.sysInfo = wx.getSystemInfoSync();
//console.log("sysInfo:",wx.tmGlobal.sysInfo);
wx.tmGlobal.canvas = wx.createCanvas();
wx.tmGlobal.context = wx.tmGlobal.canvas.getContext('2d');

可怜,连按钮都要自己绘制到画布上,wx框架为何不提供一个函数绘制普通按钮,只有一个wx.createUserInfoButton函数可以绘制一个用户授权按钮。准备用来获取微信用户账号,上传积分:

var button = wx.createUserInfoButton({
  type: 'image',
  image:"images/upload.png",
  style: {
    left: wx.tmGlobal.canvas.width-45,
    top: wx.tmGlobal.sysInfo.statusBarHeight + 40,
    width: 40,
    height: 40,
    //lineHeight: 40,
    backgroundColor: 'blue',
    color: 'white',
    textAlign: 'center',
    //fontSize: 16,
    borderRadius: 4
  }
});
button.show();
button.onTap((res) => {
  wx.showModal({
    title: '',
    content: JSON.stringify(res)
  });
  //console.log(res);
});

按钮的图标,这里有雷锋:https://www.iconfont.cn

再绘制棋盘格子,然后用timer让当前block往下掉:

  g_timer = setInterval(function () {
    if (g_status != "run") return;
    tryMoveBlock('down');
  }, t);

在模拟器中看起来都ok,但是在android实体机中,就出现了花屏:

哦,一般的游戏,为了避免闪烁,都会搞个双buffer,或者双画布,先在背景的画布中绘制好(多次擦除、绘制),然后一次贴到前景画布上。微信小游戏中如何做呢?

看文档,说还可以创建第2个第3个...canvas,叫“离屏画布”,不会显示出来。于是搞一个:

wx.tmGlobal.bkgCanvas = wx.createCanvas();
wx.tmGlobal.bkgContext = wx.tmGlobal.bkgCanvas.getContext('2d');

背景画布先反复擦除,绘制,然后一次贴出来:

function updateCanvas(){
  wx.tmGlobal.context.clearRect(0, 0, wx.tmGlobal.canvas.width, wx.tmGlobal.canvas.height);
  wx.tmGlobal.context.drawImage(wx.tmGlobal.bkgCanvas,0,0,
    wx.tmGlobal.canvas.width,wx.tmGlobal.canvas.height);
}

注意,clearRect是必须的,否则会花屏。

如何擦除一个格子呢?

我是在棋盘背景图和格子绘制完毕后,用g_bkgImageData把画布数据保存起来:

function drawQiPan() {
  wx.tmGlobal.bkgContext.fillStyle = "white";
  wx.tmGlobal.bkgContext.font = "16px Arial";
  wx.tmGlobal.bkgContext.fillText(wx.tmGlobal.name, 5+g_gap*4+5, wx.tmGlobal.sysInfo.statusBarHeight+25);

  wx.tmGlobal.bkgContext.drawImage(image_bkg, g_margin.left, g_margin.top,
    wx.tmGlobal.bkgCanvas.width - g_margin.left - g_margin.right,
    wx.tmGlobal.bkgCanvas.height - g_margin.top - g_margin.bottom);

  wx.tmGlobal.bkgContext.strokeStyle = "gray";
  //画纵线
  for (let col = 0; col <= g_colCount; col++) {
    wx.tmGlobal.bkgContext.moveTo(g_margin.left + (col + 1) * g_gap, 
      g_margin.top + g_gap);
    wx.tmGlobal.bkgContext.lineTo(g_margin.left + (col + 1) * g_gap, 
      g_margin.top + g_gap+g_rowCount * g_gap);
  }
  wx.tmGlobal.bkgContext.stroke();
  
  //画外框
  wx.tmGlobal.bkgContext.strokeRect(g_margin.left + g_gap-3, g_margin.top + g_gap-3, 
    g_colCount * g_gap+6,
    g_rowCount * g_gap+6
  );
  //保存完整背景图,用于局部恢复
  g_bkgImageData = wx.tmGlobal.bkgContext.getImageData(0,0,
    wx.tmGlobal.bkgCanvas.width,wx.tmGlobal.bkgCanvas.height);
}

擦除格子cell时,从g_bkgImageData 取出原来的一块,用putImageData贴上去:

//获取大背景图的一个局部
function getBackgroundCell(x,y,w,h){
  let data=wx.tmGlobal.bkgContext.createImageData(w,h);//new Array(w*h*4);
  for(let c=0;c<w;c++){
    for(let r=0;r<h;r++){
      var p1 = (r * w + c)*4;
      var p2 = ((y+r) * wx.tmGlobal.canvas.width + x+c)*4;
      data.data[p1+0] = g_bkgImageData.data[p2+0];  //red
      data.data[p1+1] = g_bkgImageData.data[p2+1];  //green
      data.data[p1+2] = g_bkgImageData.data[p2+2];  //blue
      data.data[p1+3] = g_bkgImageData.data[p2+3];  //alpha
    }
  }
  return data;
}

function eraseCell_xy(x, y) {
  let imgData=getBackgroundCell(x, y, g_gap, g_gap);
  wx.tmGlobal.bkgContext.putImageData(imgData,x,y);
}

用imagedata和putImageData的方法速度太慢,可以保存一个背景canvas,然后需要的时候直接用drawImage来局部恢复,速度快很多。

function drawQiPan() {
  ...
  //保存完整背景图,用于局部恢复
    wx.tmGlobal.context_qipan.clearRect(0, 0, 
      wx.tmGlobal.canvas_qipan.width, wx.tmGlobal.canvas_qipan.height);
    wx.tmGlobal.context_qipan.drawImage(wx.tmGlobal.canvas_bkg,0,0);
}
function eraseZone(x, y,w,h) {
  x = x * wx.tmGlobal.sysInfo.pixelRatio;
  y = y * wx.tmGlobal.sysInfo.pixelRatio;
  w = w * wx.tmGlobal.sysInfo.pixelRatio;
  h = h * wx.tmGlobal.sysInfo.pixelRatio;
  //有clearRect时,在微信pc版上运行会有一个黑色边框
  //如果drawImage的绘图模式是覆盖,应该不需要clearRect
  //wx.tmGlobal.ctx_bkg.clearRect(x, y, w, h);
  wx.tmGlobal.ctx_bkg.drawImage(wx.tmGlobal.canvas_qipan, 
    x, y, w, h, x, y, w, h);
}

效果:

 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

火星牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值