微信小游戏开发小记

前言

最近由于业务原因开始接触微信小游戏的开发,踩了一些坑。下面开始写一下关于遇到的一些问题以及解决方法的总结,


一、开放数据域绘制图片问题

在DOM 环境中使用Canvans 绘制图片我们一般是使用如下的方式:

var img = document.getElementById('img');
ctx.drawImage(img, 10, 10);

drawImage 的第一个参数可以用HTMLImageElement,HTMLCanvasElement或者HTMLVideoElement作为参数,但是在开放数据域下不存在DOM 操作,我们需要使用如下的方式去绘制图片;

let pic = wx.createImage(); 
pic.src = url;
// 如果是网络图片,则需加载完成后绘制
// pic.onload = () => {
  ctx.drawImage(pic, 10, 10);
// }

二、开放数据域性能问题

由于开放域不能向主域发送数据,传统上的思路是主域需要刷新ShareCanvas并绘制到主屏上,但这样就会导致性能上的开销过大,仅仅用来绘制排行榜的话是十分不明智的做法,Egret 有一个脏渲染的概念,如果页面没有“脏”,即是没有变化的元素,则不会重新渲染Canvans ,从而减少了重绘次数,优化了渲染性能,具体的实现思路如下:

let requestAnimationFrameID; // 记录requestAnimationFrame的ID
let isDirty = true; // 标志是否为脏
/**
 * 每次渲染时,判断是否“脏”了,若是,则重新渲染
 */
function render() {
  if (isDirty) {
    context.setTransform(1, 0, 0, 1, 0, 0); // 坐标系复位
    context.clearRect(0, 0, sharedCanvas.width, sharedCanvas.height); // 清除 Canvans 画布
    drawElements();  //绘制排行榜,或者其他元素
    isDirty = false;
  }
  requestAnimationFrame(render);
}

三、UI 同步问题

微信小游戏有一个十分坑的地方:4M的限制。当我们需要绘制排行榜但又需要让ui 与主域一致的时候就会出现很尴尬的状况:如果将ui代码在开放域和主域都放一份,这会让体积大大增加,如果使用的是游戏框架,同步绘制代码的难度也会增加。

那么,我们可以怎么解决这个问题呢?

我的实现思路是,开放域的存在目前也只是获取好友或群共玩好友的关系数据,对于大多数游戏,只在绘制排行榜伤上有用。因此,排行榜可以仅绘制关系数据,即,只绘制头像、排行这一类数据,绘制时对尺寸进行比例缩放,而背景则在主域进行绘制,然后再把排行榜垫在背景上。这种方法仅适用于只绘制不那么复杂的排行榜的需求,对于需要绘制更复杂的界面的功能来说还是鸡肋的,尚未见到或想出一个更好的方法。


四、客服消息回回复图片功能

不少的小游戏都有客服功能的需求(emmm,比如回复公众号图片引导关注),但是微信的客服系统是不支持回复图片的,这个时候就需要自己接入客服功能。微信的发送图片信息的body 格式如下:

  "touser":"OPENID",
    "msgtype":"image",
    "image":
    {
      "media_id":"MEDIA_ID"
    }
}

具体实现步骤如下:

  1. 新增临时素材 当我们想向用户发送一张图片时,并不能随心所欲地使用任意图片地址,如上json所示,微信只提供一个mediaid,这个mediaid是我们调用新增临时素材接口提交到微信服务器上之后,返回的一个图片标识,接口如下:

    https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE

    参数说明:
    access_token: 调用接口凭证
    type:媒体类型,固定填写为 image
    media:form-data中媒体文件标识,有filename、filelength、content-type等信息
    然后我们需要实现一个可以上传图片的页面,node端接收并发送到微信服务器上,如果成功获取到 mediaid之后我们就可以存放在数据库或缓存上对应appid 的地方以便后续发送图片使用

    let token = wechat.getMiniAccessToken(); // 自己实现获取当前小程序/小游戏的access token的函数,appid 要对应,否则mediaid是不会回复到用户的
    const options = {
      url: `https://api.weixin.qq.com/cgi-bin/media/upload?access_token=${token.access_token}&type=image`,
      formData: body.fields,
    };
    
        request.post(options, (err, res, data) => {
      // 将回传的对象中的mediaid 对应appid存放
    })
  2. 接收用户发来的消息

这一步我们需要先配置好服务器,参考微信服务器接入指引这篇文章,需要注意的是,只有在验证url是否合法的情况下,才会带有echostr 参数,以此我们可以判断当前请求是否为服务器验证,如果带有echostr 参数,我们只需要在确认签名无误之后,把echostr 原样返回就可以了。如果没有echostr参数,则是微信转发过来的用户发来的消息,此时我们就要进入下一步去发送图片了。

  const {
    signature, timestamp, nonce, echostr,
  } = this.query;
  const { body } = this.request;
  if (echostr) { // 用于配置客服服务器使用
    const result = wechat.checkSign(timestamp, nonce, signature); // 校验签名是否正确
    this.body = result ? echostr : 'err signature'; 
  } else {
    wechat.sengMsg(body); // 进入下一步发送图片
    this.body = 'success';
  }
  1. 向用户发送图片

上一步中我们接收到微信转发过来的用户消息,具体格式可以参考微信客服消息这篇文章,我们可以获取到发送过来用户,只需要请求微信的接口,就可以把消息推送给该用户了。

  const mediaId = '需要发送的图片的mediaid';
  let token = wechat.getMiniAccessToken(); // 当前小程序/小游戏的access token
  const options = {
    url: `https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=${token.access_token}`,
    body: {
      touser: data.FromUserName, // 需要发送的用户
      msgtype: 'image',
      image: {
        media_id: mediaId,
      },
    },
    json: true,
  };
  request.post(options, (err, res, data) => {
    // 发送之后的处理函数
  });

结语

笔者对于微信小游戏也只能算是刚入门,以上内容也只是几天开发完之后的一些经验,不算成熟,如有错误,希望指正,互相成长,谢谢。
图片来源:http://www.hp91.cn/ h5游戏

你可能感兴趣的:(游戏开发)