CocosCreator項目實戰(13):功能-排行榜


  1. 參考Cocos接入微信小遊戲官方文檔,爲了保護其社交關係鏈數據,微信小遊戲增加了開放數據域的概念。只有在開放數據域中才能訪問微信提供的wx.getFriendCloudStorage()wx.getGroupCloudStorage()兩個 API來實現排行榜功能。
  2. 查看微信開放接口API的官方文檔,瞭解相關用法。
  3. 參考《Cocos Creator遊戲實戰》實現微信小遊戲排行榜 進行排行榜功能開發。

一、主域設置

  1. box節點下創建rankBox節點,包含rankBgtitleBoxmainBoxbuttonBox。並設置其不可見。
    rankBg:顏色爲#FFFFFF78半透明白色,考慮到屏幕適配的情況,添加Widget組件,分別爲-30% -27% -35% -35%
    titleBox:包含titleBgtitleLabel,即排行榜文字標籤;
    mainBox:包含mainBgopenData,openData爲開放數據域;
    buttonBox:包含returnButtonshareButton

在這裏插入圖片描述

  1. openData節點下添加其他組件 -> WXSubContextView組件

在這裏插入圖片描述

  1. game.js進行相關函數的增加。首先在屬性中添加rankBoxrankButton。並與Canvas節點綁定。
    properties: {
		...
        rankBox: cc.Node,
        rankButton: cc.Button,
    },
  1. onLoad()方法中,添加對rankButton的click響應事件,調用showRanks方法。並添加initUserInfoButton()方法。
    onLoad() {
    	...
        this.initUserInfoButton();
        this.rankButton.node.on('click', this.showRanks, this);
    },
  1. 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
        });
    },
  1. 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();
        });
    },
  1. 構建發佈,需要在開放數據域代碼目錄中輸入子域項目名稱,筆者設置爲openData,點擊構建。

在這裏插入圖片描述


二、子域設置

  1. 新建一個openData項目,將Canvas的寬高設置爲主域openData節點的寬高。
  2. 在資源管理器中assets下新建prefabsscenesscripts文件夾,在scenes下新建openData場景
  3. 並在Canvas節點下新建UI節點 -> ScrollView節點命名爲rankScrollView,添加Widget組件與父節點對齊,設置Color屬性爲#CDC1B4。(Canvas下新建bg節點是爲了防止適配屏幕時出現黑邊,但預覽時發現不需要)。
  4. 刪除scrollBar節點,並對view節點添加Widget組件與父節點對齊。
  5. content節點添加Widget組件與父節點對齊,添加Layout組件設置Type爲VERTICAL、ResizeMode爲CONTAINER
  6. item節點添加Widget組件與父節點對齊,設置高度爲150,並在item節點下添加bgrankavatarnamescoreline
    bg:item的背景顏色,Color屬性爲#FAF8EF
    rank:item中顯示的用戶排名;
    avatar:item中顯示的用戶頭像;
    name:item中顯示的用戶暱稱;
    score:item中顯示的用戶最高分;
    line:高度3Sprite(單色)節點,呈線狀,用於分隔每個item。
  7. 將設置好的item拖到prefabs文件夾下作爲預製資源,對層級管理器中item節點取消可見。

在這裏插入圖片描述

  1. scrpit目錄下創建openData.js,與Canvas節點綁定。添加屬性itemPrefabcontent,與Canvas節點綁定。
    properties: {
        itemPrefab: cc.Prefab,
        content: cc.Node,
    },
  1. 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();
                    // this.scheduleOnce(function () { this.getFriendInfo() }, 0.25);
                }
                else {
                    this.content.removeAllChildren();
                }
            }
        });
    },
  1. 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);
            }
        });
    },
  1. setNewCloudScore(newKVData)調用wx.setUserCloudStorage()方法上傳雲託管分數。
    setNewCloudScore(newKVData) {
        wx.setUserCloudStorage({
            KVDataList: [newKVData],
            success: (res) => {
                console.log('update score success!');
            },
            fail: (res) => {
                console.log(res);
            }
        });
    },
  1. 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);
            }
        });
    },
  1. 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);
            }
        });
    },
  1. 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);
        }
    },
  1. createItem()方法用於生成item實體包括rankavatarUrlnickNamescore
    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);
    },
  1. 構建發佈,可設置發佈路徑爲主目錄./build/wechatgame目錄下,點擊構建。

在這裏插入圖片描述

  1. 微信開發者工具中預覽,可以看到,點擊排行榜按鈕,進行微信授權,之後正常顯示排行榜。(但此時沒有取消監聽,可以看到控制檯打印了move up語句)。

在這裏插入圖片描述


三、其他相關設置

  1. 監聽設置。在showRanks()添加對removeEventHandler()的調用,並禁用重新開始按鈕排行榜按鈕
    showRanks() {
        this.removeEventHandler();
        this.restartButton.onDisable();
        this.rankButton.onDisable();
		...
    },
  1. 返回按鈕。在屬性中添加returnButtonCanvas綁定。在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'
        });
    },
  1. 歷史最高分更新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;
        }
    },
  1. 微信開發者工具中預覽,設置SUCCESS爲32,可以看到:
    1)第一階段:分數、歷史最佳、排行榜上顯示的最高分均爲0;
    2)第二階段:第一次遊戲成功,分數、歷史最佳、排行榜上顯示的最高分均爲120,排行榜成功更新;
    3)第三階段:點擊再玩一次按鈕後,分數清零,歷史最佳仍爲120;
    4)第四階段:第二次遊戲過程中,分數變化,歷史最佳在分數大於120之後變化,排行榜上成功更新爲220。

在這裏插入圖片描述


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章