微信小遊戲排行榜設計技術梳理

snsart發表於2019-06-10

要製作排行榜,我們需要使用一個陣列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;

 

相關文章