前言
最近由于业务原因开始接触微信小游戏的开发,踩了一些坑。下面开始写一下关于遇到的一些问题以及解决方法的总结,
一、开放数据域绘制图片问题
在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"
}
}
具体实现步骤如下:
新增临时素材 当我们想向用户发送一张图片时,并不能随心所欲地使用任意图片地址,如上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存放 })
- 接收用户发来的消息
这一步我们需要先配置好服务器,参考微信服务器接入指引这篇文章,需要注意的是,只有在验证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';
}
- 向用户发送图片
上一步中我们接收到微信转发过来的用户消息,具体格式可以参考微信客服消息这篇文章,我们可以获取到发送过来用户,只需要请求微信的接口,就可以把消息推送给该用户了。
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游戏