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。

在这里插入图片描述


  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值