微信小游戏花屏

周末手痒,试了试微信小游戏的开发,写个俄罗斯方块。

先创建画布:

/**
 * 俄罗斯方块
 * @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是必须的,否则会花屏。

扫描二维码关注公众号,回复: 11211736 查看本文章

如何擦除一个格子呢?

我是在棋盘背景图和格子绘制完毕后,用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);
}

效果:

原创文章 159 获赞 11 访问量 36万+

猜你喜欢

转载自blog.csdn.net/acrodelphi/article/details/98473243