- 參考Cocos接入微信小遊戲官方文檔,爲了保護其社交關係鏈數據,微信小遊戲增加了
開放數據域
的概念。只有在開放數據域中才能訪問微信提供的wx.getFriendCloudStorage()
和wx.getGroupCloudStorage()
兩個 API來實現排行榜功能。
- 查看微信開放接口API的官方文檔,瞭解相關用法。
- 參考《Cocos Creator遊戲實戰》實現微信小遊戲排行榜 進行排行榜功能開發。
一、主域設置
- 在
box節點
下創建rankBox節點
,包含rankBg
、titleBox
、mainBox
、buttonBox
。並設置其不可見。
rankBg:顏色爲#FFFFFF78
半透明白色,考慮到屏幕適配的情況,添加Widget組件
,分別爲-30% -27% -35% -35%
;
titleBox:包含titleBg
、titleLabel
,即排行榜文字標籤;
mainBox:包含mainBg
、openData
,openData爲開放數據域;
buttonBox:包含returnButton
、shareButton
。
- 在
openData節點
下添加其他組件
-> WXSubContextView組件
。
- 對
game.js
進行相關函數的增加。首先在屬性中添加rankBox
、rankButton
。並與Canvas節點
綁定。
properties: {
...
rankBox: cc.Node,
rankButton: cc.Button,
},
- 在
onLoad()方法
中,添加對rankButton的click
響應事件,調用showRanks方法
。並添加initUserInfoButton()方法。
onLoad() {
...
this.initUserInfoButton();
this.rankButton.node.on('click', this.showRanks, this);
},
showRanks()方法
,將rankBox
顯示可見,並調用wx.getOpenDataContext().postMessage()方法
發送score(這裏先取了100以內隨機數)
,與子域進行通信生成排行榜內容。
showRanks() {
if (typeof wx === 'undefined') {
return;
}
this.rankBox.active = true;
let score = Math.round(Math.random() * 100);
wx.getOpenDataContext().postMessage({
message: score
});
},
initUserInfoButton()方法
爲官方文檔中微信小遊戲用戶授權相關。
initUserInfoButton() {
if (typeof wx === 'undefined') {
return;
}
let systemInfo = wx.getSystemInfoSync();
let width = systemInfo.windowWidth;
let height = systemInfo.windowHeight;
let button = wx.createUserInfoButton({
type: 'text',
text: '',
style: {
left: 0,
top: 0,
width: width,
height: height,
lineHeight: 40,
backgroundColor: '#00000000',
color: '#00000000',
textAlign: 'center',
fontSize: 10,
borderRadius: 4
}
});
button.onTap((res) => {
if (res.userInfo) {
console.log('authorized success!');
}
else {
console.log('authorized fail!');
}
button.hide();
button.destroy();
});
},
- 構建發佈,需要在
開放數據域代碼目錄
中輸入子域項目名稱,筆者設置爲openData
,點擊構建。
二、子域設置
- 新建一個
openData項目
,將Canvas的寬高設置爲主域openData節點
的寬高。
- 在資源管理器中assets下新建
prefabs
、scenes
、scripts
文件夾,在scenes下新建openData場景
。
- 並在
Canvas節點
下新建UI節點
-> ScrollView
節點命名爲rankScrollView
,添加Widget組件
與父節點對齊,設置Color屬性爲#CDC1B4
。(Canvas下新建bg節點是爲了防止適配屏幕時出現黑邊,但預覽時發現不需要)。
- 刪除
scrollBar節點
,並對view節點
添加Widget組件
與父節點對齊。
- 對
content節點
添加Widget組件
與父節點對齊,添加Layout組件
設置Type爲VERTICAL
、ResizeMode爲CONTAINER
。
item節點
添加Widget組件
與父節點對齊,設置高度爲150
,並在item節點下添加bg
、rank
、avatar
、name
、score
、line
。
bg:item的背景顏色,Color屬性爲#FAF8EF
;
rank:item中顯示的用戶排名;
avatar:item中顯示的用戶頭像;
name:item中顯示的用戶暱稱;
score:item中顯示的用戶最高分;
line:高度3
的Sprite(單色)節點
,呈線狀,用於分隔每個item。
- 將設置好的
item
拖到prefabs文件夾下作爲預製資源
,對層級管理器中item節點取消可見。
- 在
scrpit目錄
下創建openData.js
,與Canvas節點綁定。添加屬性itemPrefab
、content
,與Canvas節點綁定。
properties: {
itemPrefab: cc.Prefab,
content: cc.Node,
},
onLoad()
中調用wx.onMessage()方法
,如果從主域中傳入的message不是clear字串,則與雲託管上的分數比較,初始化排行榜列表rankList
,傳入玩家數據,getPlayerInfo()
用於測試;getFriendInfo()方法
用於獲取好友的數據,設置了0.25s
的時延,因爲在實際預覽過程中出現compareScore()方法
沒結束就調用getFriendInfo()
出錯的情況。
onLoad() {
if (typeof wx === 'undefined') {
return;
}
wx.onMessage(data => {
if (data.message != undefined) {
if (data.message != 'clear') {
this.score = data.message;
this.compareScore();
this.rankList= [];
this.getPlayerInfo();
}
else {
this.content.removeAllChildren();
}
}
});
},
compareOldScore()方法
調用wx.getUserCloudStorage()方法
。首先判斷有沒有云託管分數,如果沒有則直接創建一個newKVData
變量,並調用setNewCloudScore()方法
將傳過來的分數設置到雲託管;如果有云託管分數,則比較新分數和雲託管分數,若新分數大則將新分數存入雲託管。
compareScore() {
wx.getUserCloudStorage({
keyList: ['score'],
success: (res) => {
if (res.KVDataList.length > 0) {
let KVData = res.KVDataList[0];
let storedScore = Number(KVData['value']);
if (this.score > storedScore) {
let newKVData = { key: 'score', value: String(this.score) }
this.setNewCloudScore(newKVData);
}
}
else {
let newKVData = { key: 'score', value: String(this.score) }
this.setNewCloudScore(newKVData);
}
},
fail: (res) => {
console.log(res);
}
});
},
setNewCloudScore(newKVData)
調用wx.setUserCloudStorage()方法
上傳雲託管分數。
setNewCloudScore(newKVData) {
wx.setUserCloudStorage({
KVDataList: [newKVData],
success: (res) => {
console.log('update score success!');
},
fail: (res) => {
console.log(res);
}
});
},
getPlayerInfo()
調用wx.getUserInfo()方法
用於測試,用自己的信息模擬50名不同分數的玩家。
getPlayerInfo() {
wx.getUserInfo({
openIdList: ['selfOpenId'],
lang: 'zh_CN',
success: (res) => {
let userInfo = res.data[0];
for (let i = 0; i < 50; i++) {
this.rankList.push({
nickName: userInfo.nickName,
avatarUrl: userInfo.avatarUrl,
score: Math.round(Math.random() * 100)
});
}
this.makeRanks();
},
fail: (res) => {
console.log(res);
}
});
},
getFriendInfo()
調用wx.getFriendCloudStorage()方法
,往rankList
中傳入數據。
getFriendInfo() {
wx.getFriendCloudStorage({
keyList: ['score'],
success: (res) => {
for (let i = 0; i < res.data.length; i++) {
this.rankList.push({
nickName: res.data[i].nickname,
avatarUrl: res.data[i].avatarUrl,
score: res.data[i].KVDataList[0]['value'],
});
}
this.makeRanks();
},
fail: (res) => {
console.log(res);
}
});
},
makeRanks()方法
用於在rankList
進行正確排序,排序完調用createItem()方法
生成item。
makeRanks() {
this.rankList.sort((a, b) => {
return b['score'] - a['score'];
});
for (let i = 0; i < this.rankList.length; i++) {
let nickName = this.rankList[i]['nickName'];
let avatarUrl = this.rankList[i]['avatarUrl'];
let score = this.rankList[i]['score'];
this.createItem(i + 1, nickName, avatarUrl, score);
}
},
createItem()方法
用於生成item實體包括rank
、avatarUrl
、nickName
、score
。
createItem(rank, nickName, avatarUrl, score) {
let item = cc.instantiate(this.itemPrefab);
item.children[1].getComponent(cc.Label).string = rank <= 9 ? ' ' + rank : rank;
cc.loader.load({ url: avatarUrl, type: 'png' }, (err, texture) => {
if (err) console.error(err);
item.children[2].getComponent(cc.Sprite).spriteFrame = new cc.SpriteFrame(texture);
});
item.children[3].getComponent(cc.Label).string = '暱稱:' + nickName;
item.children[4].getComponent(cc.Label).string = '最高分:' + score;
this.content.addChild(item);
},
- 構建發佈,可設置發佈路徑爲主目錄
./build/wechatgame目錄
下,點擊構建。
- 在
微信開發者工具
中預覽,可以看到,點擊排行榜按鈕,進行微信授權,之後正常顯示排行榜。(但此時沒有取消監聽,可以看到控制檯打印了move up
語句)。
三、其他相關設置
- 監聽設置。在
showRanks()
添加對removeEventHandler()
的調用,並禁用重新開始按鈕
和排行榜按鈕
。
showRanks() {
this.removeEventHandler();
this.restartButton.onDisable();
this.rankButton.onDisable();
...
},
- 返回按鈕。在屬性中添加
returnButton
與Canvas
綁定。在onLoad()
監聽按鈕點擊觸發returnGame()
。returnGame()添加屏幕滑動監聽,啓用重新開始按鈕
和排行榜按鈕
,並將rankBox
顯示不可見,並再次與子域通信發送clear字串
,請求刪除之前生成的排行榜信息(如果不刪除,下次打開排行榜時會有重複內容出現)。
properties: {
...
returnButton: cc.Button,
},
onLoad() {
...
this.returnButton.node.on('click', this.returnGame, this);
},
...
returnGame() {
this.addEventHandler();
this.restartButton.onEnable();
this.rankButton.onEnable();
this.rankBox.active = false;
if (typeof wx === 'undefined') {
return;
}
wx.getOpenDataContext().postMessage({
message: 'clear'
});
},
- 歷史最高分更新
updateBest(number)方法
。可參考updateScore()方法
,同時在init()時讀取本地最高分,在遊戲過程中只有當score > best
時才更新最高分。
init() {
...
this.updateBest(cc.sys.localStorage.getItem('best'));
...
},
afterMove(hasMoved) {
if (hasMoved) {
this.updateScore(this.score);
this.updateBest(this.score);
...
}
...
},
...
updateBest(number) {
this.best = cc.sys.localStorage.getItem('best');
if (!this.best || number >= this.best) {
cc.sys.localStorage.setItem('best', number);
this.best = number;
this.bestLabel.string = number;
}
},
- 在
微信開發者工具
中預覽,設置SUCCESS爲32
,可以看到:
1)第一階段:分數、歷史最佳、排行榜上顯示的最高分均爲0;
2)第二階段:第一次遊戲成功,分數、歷史最佳、排行榜上顯示的最高分均爲120,排行榜成功更新;
3)第三階段:點擊再玩一次按鈕後,分數清零,歷史最佳仍爲120;
4)第四階段:第二次遊戲過程中,分數變化,歷史最佳在分數大於120之後變化,排行榜上成功更新爲220。