发布时间:2025-12-09 11:47:04 浏览次数:1
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/CJB_King/article/details/81502141
利用Phaser开发微信小游戏(排行榜小结)
小游戏中的开放数据域可用来保存游戏数据,可实现排行榜等功能,以下是我在项目中的实现方式,提供参考:
{
“deviceOrientation”: “portrait”,
"openDataContext":"src/myOpenDataContext"
}
Phaser.XTexture = function(xCanvas,x,y,w,h){ return new PIXI.Texture(new PIXI.BaseTexture(xCanvas),new PIXI.Rectangle(x,y,w,h)); };var openDataContext = wx.getOpenDataContext();var sharedCanvas = openDataContext.canvas;var pad = game.add.sprite(0,100, Phaser.XTexture(sharedCanvas,0,0,150,100)); openDataContext.postMessage({ action: 'get', data: { gameAspect: [game.width, game.height], score: Score }, });wx.onMessage((data) => { switch (data.action) { case 'save': wx.setUserCloudStorage({ KVDataList: [{ key: 'data', value: data.data.toString() }, { key: 'data', value: data.data.toString() }], success: function () { console.log('“Save OK …”'); } }); break; case 'get': getUserData(data); break; case 'getGrp': getGrpData(data); break; case 'close': clearShareCanvas(data); break; }})需要注意的是主域虽然可以操作sharedCanvas,但是主域得不到数据,主域只能向开放域传递一些基本数据,只能画一些背景边框,数据只能在开放域中画。
下面就我觉得比较几个重要的地方说下:
这里排行榜的显示,我用了两个Canvas
主域中可以通过:
var sharedCanvas = openDataContext.canvas;得到。
var sharedCanvas = wx.getSharedCanvas(); var ctx = sharedCanvas.getContext('2d');我把排行榜的静态数据绘制在SharedCanvas中,这里说的静态数据是指:排行榜的背景,标题,文字,用户进入后显示头像等等。
第二个canvas是我自己创建的canvas,是用来绘制用户排行信息,比如用户排名,用户分数,用户头像等等。
itemCanvas=wx.createCanvas(); itemCtx = itemCanvas.getContext('2d');var avatarImg = wx.createImage(); avatarImg.src = res.data[i].avatarUrl; avatarImg.onload = (function (cvs, avatarImage, i) { return function () { cvs.drawImage(avatarImage, data.data.gameAspect[0] * 0.11, data.data.gameAspect[0] * 0.1 + (i + 1) * 50, 35, 35); } })(itemCtx, avatarImg, i); //头像 itemCtx.fillStyle = "rgb(250, 250, 250)"; itemCtx.font = "16px Arial"; itemCtx.textAlign = "left"; itemCtx.textBaseline = "top"; itemCtx.fillText(i + 1, data.data.gameAspect[0] * 0.8, data.data.gameAspect[0] * 0.1 + 6 + (i + 1) * 50); // 名次 itemCtx.fillText(res.data[i].nickname, data.data.gameAspect[0] * 0.23, data.data.gameAspect[0] * 0.1 + 6 + (i + 1) * 50); // 昵称 itemCtx.fillText(res.data[i].KVDataList[0].value, data.data.gameAspect[0] * 0.6, data.data.gameAspect[0] * 0.1 + 6 + (i + 1) * 50); // 分数我们把用户排行信息绘制到自建的canvas上之后,还需要通过SharedCanvas把他显示在屏幕上
var sharedCanvas = wx.getSharedCanvas(); var context = sharedCanvas.getContext('2d'); context.drawImage(itemCanvas, 0, y, 750 - 80 * 2, res.windowHeight * 0.5, 0, res.windowHeight * 0.35, 750 - 80 * 2, res.windowHeight * 0.5); res.data.sort(sorter); // 先排个序// 排序函数(降序)var sorter = function (data1, data2) { var num1 = parseInt(data1.KVDataList[0].value); var num2 = parseInt(data2.KVDataList[0].value); if (num1 > num2) { return -1; } else if (num1 < num2) { return 1; //返回值大于0则交换两数的位置 } else { return 0; }}排行数据的滑动采用原生监听手势滑动方法实现的,通过监听onTouchMove方法得到滑动距离,清除数据区域后,根据这个距离重新绘制数据区域,在监听结束后判断滑动的上限和下限设置下就可以了。
let startY = undefined, moveY = 0; // 触摸移动事件 wx.onTouchMove(e => { let touch = e.touches[0]; // 触摸移动第一次触发的位置 if (startY === undefined) { startY = touch.clientY + moveY; } moveY = startY - touch.clientY; reDrawItem(moveY); }); wx.onTouchEnd(e => { startY = undefined; if (moveY < 0) { // 到顶 moveY = 0; } else if (moveY > itemCanvas.height*0.65) { // 到底 moveY = itemCanvas.height * 0.65; } reDrawItem(moveY); });开放域index.js的完整代码如下:
var itemCanvas, itemCtx;wx.onMessage((data) => { switch (data.action) { case 'save': wx.setUserCloudStorage({ KVDataList: [{ key: 'data', value: data.data.toString() }, { key: 'data', value: data.data.toString() }], success: function () { console.log('“Save OK …”'); } }); break; case 'get': getUserData(data); break; case 'getGrp': getGrpData(data); break; case 'close': clearShareCanvas(data); break; }})function loadRes(data,rankTitle) { Init(); itemCanvas=wx.createCanvas(); itemCtx = itemCanvas.getContext('2d'); // itemCanvas.width = data.data.gameAspect[0]-2*data.data.gameAspect[0] * 0.1; // itemCanvas.height = data.data.gameAspect[1] -2*data.data.gameAspect[0] * 0.6+100; var sharedCanvas = wx.getSharedCanvas(); var ctx = sharedCanvas.getContext('2d'); const bg = wx.createImage(); bg.src = "assets/img_480/bg.png"; bg.onload = () => { ctx.drawImage(bg, 0, 0, data.data.gameAspect[0], data.data.gameAspect[1]); //绘制主域的背景 const backBtn = wx.createImage(); backBtn.src = 'assets/img_480/back.png'; backBtn.onload = () => { ctx.drawImage(backBtn, 5, 10, 40, 40); //返回按钮 } const rankBg = wx.createImage(); rankBg.src = 'assets/img_480/pkk.png'; rankBg.onload = () => { ctx.drawImage(rankBg, (data.data.gameAspect[0] - data.data.gameAspect[0] * 0.9) / 2, (data.data.gameAspect[1] - data.data.gameAspect[1] * 0.6) / 2, data.data.gameAspect[0] * 0.9, data.data.gameAspect[1] * 0.7); //排行榜背景 console.log('wid=' + (data.data.gameAspect[0] - data.data.gameAspect[0] * 0.9) / 2); console.log('height=' + (data.data.gameAspect[1] - data.data.gameAspect[1] * 0.6) / 2); ctx.fillStyle = "rgb(0, 250, 0)"; ctx.font = "22px Arial"; ctx.textAlign = "left"; ctx.fillText(rankTitle, (data.data.gameAspect[0] - data.data.gameAspect[0] * 0.8) / 2, (data.data.gameAspect[1] - data.data.gameAspect[1] * 0.46) / 2); ctx.font = "15px Arial"; ctx.fillStyle = "rgb(250, 250, 0)"; ctx.fillText("头像", data.data.gameAspect[0] * 0.11, data.data.gameAspect[1] * 0.315); ctx.fillText("用户名", data.data.gameAspect[0] * 0.25, data.data.gameAspect[1] * 0.315); ctx.fillText("分数", data.data.gameAspect[0] * 0.59, data.data.gameAspect[1] * 0.315); ctx.fillText("排名", data.data.gameAspect[0] * 0.79, data.data.gameAspect[1] * 0.315); const qunPaiHang=wx.createImage(); qunPaiHang.src ="assets/img_480/share.png"; qunPaiHang.οnlοad=(function(ctx,img){ return function(){ ctx.drawImage(img, data.data.gameAspect[0] * 0.1, data.data.gameAspect[1] - data.data.gameAspect[1] *0.1); } })(ctx, qunPaiHang); } }} function getGrpData(data){ console.log("getGrp is Execute"); loadRes(data,'群排行'); var sharedCanvas=wx.getSharedCanvas(); var ctx=sharedCanvas.getContext('2d'); var avatarURl; wx.getUserInfo({ openIdList: ['selfOpenId'], lang: 'zh_CN', success: function (res) { avatarURl = res.data[0].avatarUrl; const avatarImg = wx.createImage(); avatarImg.src = avatarURl; avatarImg.onload = () => { //绘制头像 ctx.drawImage(avatarImg, (data.data.gameAspect[0] - data.data.gameAspect[0] * 0.2) / 2 + 15, 40, 50, 50); ctx.fillStyle = "rgb(250, 250, 250)"; ctx.font = "22px Arial"; ctx.textAlign = "left"; ctx.fillText(res.data[0].nickName, (data.data.gameAspect[0] - data.data.gameAspect[0] * 0.2) / 2, 120); //绘制用户名 }; wx.getGroupCloudStorage({ shareTicket: data.data.shareTicket, keyList:['data'], success:function(res){ res.data.sort(sorter); // 先排个序 for (let i = 0; i < res.data.length; i++) { var avatarImg = wx.createImage(); avatarImg.src = res.data[i].avatarUrl; avatarImg.onload = (function (cvs, avatarImage, i) { return function () { cvs.drawImage(avatarImage, data.data.gameAspect[0] * 0.11, data.data.gameAspect[0] * 0.1 + (i + 1) * 50, 35, 35); } })(itemCtx, avatarImg, i); //头像 itemCtx.fillStyle = "rgb(250, 250, 250)"; itemCtx.font = "16px Arial"; itemCtx.textAlign = "left"; itemCtx.textBaseline = "top"; itemCtx.fillText(i + 1, data.data.gameAspect[0] * 0.8, data.data.gameAspect[0] * 0.1 + 6 + (i + 1) * 50); // 名次 itemCtx.fillText(res.data[i].nickname, data.data.gameAspect[0] * 0.23, data.data.gameAspect[0] * 0.1 + 6 + (i + 1) * 50); // 昵称 itemCtx.fillText(res.data[i].KVDataList[0].value, data.data.gameAspect[0] * 0.6, data.data.gameAspect[0] * 0.1 + 6 + (i + 1) * 50); // 分数 reDrawItem(0); } }, fail:function(err){ if(err){ console.log(err); } } }); } })}function getUserData(data) { loadRes(data,'好友排行'); var sharedCanvas = wx.getSharedCanvas(); var ctx = sharedCanvas.getContext('2d'); var avatarURl; wx.getUserInfo({ openIdList: ['selfOpenId'], lang: 'zh_CN', success: function (res) { console.log('success', res.data) avatarURl = res.data[0].avatarUrl; const avatarImg = wx.createImage(); avatarImg.src = avatarURl; avatarImg.onload = () => { //绘制头像 ctx.drawImage(avatarImg, (data.data.gameAspect[0] - data.data.gameAspect[0] * 0.2) / 2 + 15, 40, 50, 50); ctx.fillStyle = "rgb(250, 250, 250)"; ctx.font = "22px Arial"; ctx.textAlign = "left"; ctx.fillText(res.data[0].nickName, (data.data.gameAspect[0] - data.data.gameAspect[0] * 0.2) / 2, 120); //绘制用户名 }; wx.getUserCloudStorage({ keyList: ['data'], success: function (getData) { var dataValue = getData.KVDataList[0].value; if (data.data.score > dataValue) { //如果打破历史纪录,将新纪录保存 wx.setUserCloudStorage({ KVDataList: [{ key: 'data', value: data.data.score.toString() }], success: function () { console.log('“打破记录,新数据已保存”'); } }); } else { wx.getFriendCloudStorage({ keyList: ['data'], success: function (res) { // var shareCanvas = wx.getSharedCanvas(); // var ctx = shareCanvas.getContext('2d'); res.data.sort(sorter); // 先排个序 for (let i = 0; i < res.data.length; i++) { var avatarImg = wx.createImage(); avatarImg.src = res.data[i].avatarUrl; avatarImg.onload = (function (cvs, avatarImage, i) { return function () { cvs.drawImage(avatarImage, data.data.gameAspect[0] * 0.11, data.data.gameAspect[0] * 0.1 + (i + 1) * 50, 35, 35); } })(itemCtx, avatarImg, i); //头像 itemCtx.fillStyle = "rgb(250, 250, 250)"; itemCtx.font = "16px Arial"; itemCtx.textAlign = "left"; itemCtx.textBaseline = "top"; itemCtx.fillText(i + 1, data.data.gameAspect[0] * 0.8, data.data.gameAspect[0] * 0.1 +6+ (i+1) * 50); // 名次 itemCtx.fillText(res.data[i].nickname, data.data.gameAspect[0] * 0.23, data.data.gameAspect[0] * 0.1 + 6 + (i + 1) * 50); // 昵称 itemCtx.fillText(res.data[i].KVDataList[0].value, data.data.gameAspect[0] * 0.6, data.data.gameAspect[0] * 0.1 + 6 + (i + 1) * 50); // 分数 reDrawItem(0); } } }); } } }); }, fail: (res) => { reject(res) } })}function clearShareCanvas(data) { var sharedCanvas = wx.getSharedCanvas(); var ctx = sharedCanvas.getContext('2d'); ctx.clearRect(0, 0, data.data.gameAspect[0], data.data.gameAspect[1]); var itemCtx = itemCanvas.getContext('2d'); itemCtx.clearRect(0, 0, data.data.gameAspect[0], data.data.gameAspect[1]); wx.offTouchMove(); wx.offTouchEnd();}// 排序函数(降序)var sorter = function (data1, data2) { var num1 = parseInt(data1.KVDataList[0].value); var num2 = parseInt(data2.KVDataList[0].value); if (num1 > num2) { return -1; } else if (num1 < num2) { return 1; //返回值大于0则交换两数的位置 } else { return 0; }}function Init(){ let startY = undefined, moveY = 0; // 触摸移动事件 wx.onTouchMove(e => { let touch = e.touches[0]; // 触摸移动第一次触发的位置 if (startY === undefined) { startY = touch.clientY + moveY; } moveY = startY - touch.clientY; reDrawItem(moveY); }); wx.onTouchEnd(e => { startY = undefined; if (moveY < 0) { // 到顶 moveY = 0; } else if (moveY > itemCanvas.height*0.65) { // 到底 moveY = itemCanvas.height * 0.65; } reDrawItem(moveY); });}// 因为头像绘制异步的问题,需要重新绘制function reDrawItem(y) { console.log("vv"+y); var sharedCanvas = wx.getSharedCanvas(); var context = sharedCanvas.getContext('2d'); wx.getSystemInfo({ success: function(res) { context.clearRect(res.windowWidth * 0.1, res.windowHeight * 0.35, res.windowWidth * 0.8, res.windowHeight*0.5); context.fillStyle = 'rgb(100,100,100)'; context.fillRect(res.windowWidth * 0.1, res.windowHeight * 0.35, res.windowWidth * 0.8, res.windowHeight*0.5); context.drawImage(itemCanvas, 0, y, 750 - 80 * 2, res.windowHeight * 0.5, 0, res.windowHeight * 0.35, 750 - 80 * 2, res.windowHeight * 0.5); //drawImage(画布,距离左,距离上,宽度缩放,高度缩放,渲染起始点X,渲染起始点Y,横向缩放显示,纵向缩放); // context.drawImage(itemCanvas, 0, y); // requestAnimationFrame(reDrawItem(0)); }, })}下面贴出思路:
//开放域中itemCanvas=wx.createCanvas(); itemCtx = itemCanvas.getContext('2d');var userDataArry=[];//中间 数据保存数组中省略...itemCtx.canvas.usersData=userDataArry;//主域中var openDataContext=wx.getOpenDataContext();var shareCanvas=openDataContext.canvas;var userData=shareCanvas.usersData;for(let i=0;i<userData.length;i++){ console.log(userData[i]); //这里可以打印出开放域中传递出来的数据}