微信小游戏排行榜设计技术梳理
要制作排行榜,我们需要使用一个数组totalGroup来存储同玩好友的数据,totalGroup中同玩好友数据格式如下:
1 const totalGroup = [ 2 { 3 key: 1,//用户排名 4 name: "xiaoming",//用户昵称 5 url: avatarUrl,//用户头像地址 6 img:image,//用户头像,根据头像地址生成image 7 scroes: 95//用户得分 8 }, 9 10 { 11 key: 2, 12 name: "xiaohua", 13 url: avatarUrl, 14 img:image, 15 scroes: 90 16 }, 17 //... 18 ]
当游戏完成时,玩家得分会上传至用户托管数据,totalGroup根据用户同玩好友托管数据进行更新,排行榜根据totalGroup中的数据进行渲染。
游戏各阶段实现的功能总结如下:
1.游戏初始化时
根据同玩好友数据更新totalGroup;
2.游戏完成时
将玩家得分上传至用户托管数据
3.玩家打开排行榜时
根据同玩好友数据更新totalGroup,然后根据totalGroup渲染排行榜;
本文不会详解排行榜的渲染,主要分析下面两个问题:
1.上传玩家得分至用户托管数据
2.根据同玩好友数据更新totalGroup
一、上传玩家得分至用户托管数据
由于游戏逻辑是在主域中编写的,所以需要在主域中把得分等数据传入开方数据域(关于主域和开放数据域的概念请参考官方文档,这里不详述),接口如下:
1 //主域中编写 2 function setScore(score){ 3 var openDataContext = new WxgameOpenDataContext(); 4 5 var info={ 6 command:"setScore", 7 score:score, 8 timeStamp:new Date().getTime() 9 }; 10 11 openDataContext.postMessage(info); 12 }
这里的timeStamp属性是得分时的时间戳,为了实现只对本周同玩好友进行排行的功能。然后在开方数据域中接受并处理信息:
1 //在开方数据域中编写 2 wx.onMessage((data) => { 3 if (data.command == 'setScore'){ 4 setScore(data);//处理得分 5 }else if(data.command == 'preload'){ 6 //游戏初始化时预加载资源和根据同玩好友数据更新totalGroup; 7 }else if(data.command == 'open'){ 8 //根据同玩好友数据更新totalGroup及渲染排行榜; 9 } 10 });
在setStore中先判断分数是否是本周最高分,若是则将分数上传至用户托管数据:
1 //在开方数据域中编写 2 function setScore(data){ 3 var score=data.score; 4 var timestamp=data.timeStamp; 5 6 /* 7 判断totalGroup是否存在当前用户,若不存在则更新分数,若存在则判 断其中的分数是否大于score,若大于则退出,否则更新分数。 8 */ 9 for(var i=0;i<totalGroup.length;i++){ 10 var name=totalGroup[i].name; 11 var lastScore=totalGroup[i].scroes; 12 var username=userData[0].nickname;//userData中存储用户数据信息,在游戏加载时初始化,代码附在后面 13 if (username == name && lastScore >= score){ 14 return; 15 } 16 } 17 18 //更新用户托管数据 19 return new Promise((resolve, reject) => { 20 wx.setUserCloudStorage({ 21 KVDataList: [{ 22 key: "score", 23 value: JSON.stringify(score), 24 }, { 25 key: "timestamp", 26 value: JSON.stringify(timestamp), 27 }, ], 28 29 success: function (res) { 30 resolve(); 31 }, 32 }) 33 }) 34 }
获取用户数据userData,游戏初始化时执行
1 //在开方数据域中编写 2 wx.getUserInfo({ 3 openIdList: ['selfOpenId'], 4 lang: '', 5 success: function(res) { 6 userData=res.data; 7 }, 8 })
二、根据同玩好友数据更新totalGroup
为了实现只对本周玩家分数进行排行的功能,totalGroup中只存储本周玩家的数据;
1 function updateTotalGroup (){ 2 3 //按分数大小进行排序的排序函数 4 function compare(obj1, obj2) { 5 var score1 = parseInt(obj1.scroes); 6 var score2 = parseInt(obj2.scroes); 7 if (score1 > score2) { 8 return -1; 9 } else { 10 return 1; 11 } 12 } 13 14 wx.getFriendCloudStorage({ 15 keyList: ["score","timestamp"], 16 success: function (res) { 17 //先清空totolGroup 18 totalGroup.splice(0,totalGroup.length); 19 var data = res.data; 20 21 for (let i = 0; i < data.length; i++) { 22 if (data[i].KVDataList.length<2){ 23 continue; 24 } 25 //获取得分的时间戳并判断是否是本周,如果是则将数据存入totalGroup 26 var timestamp=data[i].KVDataList[1].value; 27 if (isCurrentWeek(timestamp)){ 28 var obj = { 29 key: i, 30 openid:data[i].openid, 31 name: data[i].nickname, 32 url: data[i].avatarUrl, 33 img: null, 34 scroes: data[i].KVDataList[0].value 35 } 36 totalGroup.push(obj); 37 } 38 } 39 //排序及设置头像 40 totalGroup.sort(compare); 41 for (let i = 0; i < totalGroup.length; i++) { 42 const img = wx.createImage(); 43 img.src = totalGroup[i].url; 44 totalGroup[i].img = img; 45 totalGroup[i].key = i + 1; 46 } 47 //渲染排行榜 48 renderRank(totalGroup)//实现过程省略 49 50 }) 51 }
通过时间戳判断分数是否是本周更新:
1 function isCurrentWeek(timestamp){ 2 if(timestamp==undefined){ 3 return false; 4 } 5 var date=new Date(), 6 day=date.getDay()==0?7:date.getDate(), 7 hours=date.getHours(), 8 minutes=date.getMinutes(), 9 seconds = date.getSeconds(), 10 timefromSunday=(day*24*3600+hours*3600+minutes*60+seconds)*1000,//星期日凌晨0点到此时的毫秒数 11 time=date.getTime()-timefromSunday;//1970年1月1人至上周日凌晨的毫秒数; 12 13 return parseInt(timestamp)>time//若时间戳大于周日,则时间戳标志的事件发生在本周; 14 }
三、显示排行榜
在开方数据中渲染完排行榜后,在主域中可通过下面接口获取在开方数据域中创建的canvas;
const openDataContext = wx.getOpenDataContext();
const sharedCanvas = openDataContext.canvas;