《Cocos Creator游戏实战》实现微信小游戏排行榜

实现微信小游戏排行榜

 

完成主域项目

完成子域项目

构建运行


在游戏中加入排行榜是非常有必要的。本节教程就带大家了解下如何在微信小游戏中加入排行榜。

运行效果如下:

Cocos Creator版本:2.2.0

后台回复"排行榜",获取该项目完整文件:

其实Cocos官方在文档中已经提供了较为详细的说明,并给出了一个Demo,大家可以先去了解下。

请大家点击该链接查看微信开放数据域各个API的用法。

完成主域项目

下图显示了笔者在主域项目中创建的节点:

1. bg节点用作背景,颜色为白色。

2. showRanksBtn是一个按钮节点,用于显示和关闭排行榜。

3. WXSubContextView节点非常关键,我们必须通过它来显示开放数据域(以下统称子域)中的贴图。它上面挂有WXSubContextView组件。

注:对各个节点的尺寸和属性设置,请大家直接打开项目去查看下,笔者这里不再赘述。

进行适当布局后,显示如下:

新建一个ShowRanks.js脚本,并挂到Canvas节点上。脚本编写如下:

// ShowRanks.js
cc.Class({
    extends: cc.Component,

    properties: {
        wxSubContextView: cc.Node       //主域视窗容器
    },

    // LIFE-CYCLE CALLBACKS:

    onLoad () {
        // 获取授权
        this.initUserInfoButton();
    },

    showRanks() {
        if (typeof wx === 'undefined') {
            return;
        }

        if (!this.wxSubContextView.active) {
            // 设置容器可见
            this.wxSubContextView.active = true;

            // 设置随机数(把这个当做玩家的分数)
            let score = Math.round(Math.random()*10);

            // 发送结算分数到开放域
            wx.getOpenDataContext().postMessage({
                message: score
            });
        }
        else {
            // 设置容器不可见,即关闭排行榜,并让开放域清空排名信息
            this.wxSubContextView.active = false;
            wx.getOpenDataContext().postMessage({
                message: 'clear'
            });
        }
    },

    initUserInfoButton () {
        // 微信授权,此代码来自Cocos官方
        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('授权成功!');
            }
            else {
                console.log('授权失败!');
            }

            button.hide();
            button.destroy();
        });
    },
});

1. initUserInfoButton这个方法用于用户授权,大家不必对该方法留意过多,照抄就行(调用微信开放数据域中的方法前需要用户授权)。

2. 重点是showRanks方法,每次玩家点击按钮后,都会调用该方法。

其中我们首先判断WXSubContextView节点是否可见,若不是,则显示可见并调用wx.getOpenDataContext().postMessage()发送当前玩家的分数,与子域进行通信请求生成排行榜内容。

若WXSubContextView可见,那么我们设置其active属性为false,并再次与子域通信,请求删除之前生成的排行榜信息。如果不删除,那么等玩家下次再点击按钮打开排行榜时,会发现有重复内容出现。

完成子域项目

子域节点内容如下:

1. 首选确保Canvas节点大小同主域中的WXSubContextView大小相同,记得将Fit Height和Fit Width都勾选上。

2. bg为背景,颜色为白色,跟主域背景颜色一样(这由项目素材决定,不必跟笔者这里一样)。

3. rankScrollView是一个滑动视窗节点(笔者删除了一些用不到的子节点),读者可以将该视窗的背景换成自己的素材。

注意笔者这里在content节点上加了一个Layout组件,并将Type和Resize Mode分别设置为VERTICAL和CONTAINER。因为content下会有很多的子节点生成,这样做可以更好地排版,content高度也可以自动调整。

效果如下:

现在我们需要一个预制,在该预制节点上会显示各个玩家的信息。

  1. rank子节点用于显示名次。
  2. avatar子节点用于显示微信头像。
  3. nameTip子节点显示固定文本Name:。
  4. scoreTip子节点显示固定文本Score:。
  5. name子节点显示玩家的微信名。
  6. score子节点显示玩家的分数。

设置好后的效果如下:

接下来新建OpenData.js脚本,在properties中添加以下两个属性:

// OpenData.js
properties: {
    itemPrefab: cc.Prefab,    // item预制
    content: cc.Node,         // content节点
},

onLoad方法实现如下:

// OpenData.js
onLoad () {
    if (typeof wx === 'undefined') {
        return;
    }

    wx.onMessage( data => {
        if (data.message) {
            if (data.message != 'clear') {
                this.score = data.message;                  // 将主域传过来的分数保存在this.score中
                this.compareOldNewScore();                  // 将当前玩家的新分数和之前玩的分数进行比较

                this.allInfoList = [];                      // 所有玩家的数据保存在这个数组中,用于排序
                this.getFriendInfo();                       // 获取同城好友信息(当前玩家的信息也会返回)
                // this.getPlayerInfo();                    // 用于读者Demo测试,实际项目中调用getFriendInfo()
            }
            else {
                this.content.removeAllChildren();           // 关闭排行榜时清空节点
            }

        }
    });
},

在子域中我们调用wx.onMessage方法获取从主域传过来的数据。如果主域传来的是'clear',那么我们就清空content节点下的所有子节点;如果传来的是分数,那么我们首先调用this.compareOldNewScore方法来比较该分数与之前的云托管分数。接着调用getFriendInfo()来获取所有玩家的信息(在该方法中会进行排名)。

由于不是实际上线项目(没有其他好友云托管的数据),所以读者在微信开发工具上运行该项目后,会发现生成的排名只有读者一人。那为了缓解这种尴尬,笔者放了getPlayerInfo方法,读者可以使用该方法来生成多个玩家信息(其实就是多个自己啦)。当然实际项目中要用getFriendInfo()。

this.compareOldNewScore方法实现如下:

// OpenData.js
compareOldNewScore() {
    // 将传过来的新分数和之前玩的分数进行比较
    wx.getUserCloudStorage({
        keyList: ['score'],
        success: (res) => {
            if (res.KVDataList.length) {
                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);
        }
    });
},

在该方法中我们调用 wx.getUserCloudStorage()来获取自己的云托管分数(之前玩过保存到云托管上的分数)。如果调用成功,则首选判断有没有云托管分数(因为这可能是第一次玩),如果没有那么我们直接创建一个newKVData变量,并调用setNewCloudScore方法将传过来的分数设置到云托管。如果之前玩过,那么我们来比较下新分数和云托管上的分数,看看哪个比较高。若新分数较大,则同理将新分数存入云托管。

setNewCloudScore方法实现如下:

setNewCloudScore (newKVData) {
    // 设置新云托管分数(第一次游戏时,也调用该方法设置云托管分数)
    wx.setUserCloudStorage({
        KVDataList: [newKVData],
        success: (res) => {
            console.log('更新玩家分数成功!');
        },
        fail: (res) => {
            console.log(res);
        }
    });
},

大家可以去微信小游戏API文档上看下具体解释。

更新:请读者在主域中比较分数,并调用wx.setUserCloudStorage这个API来更新云托管分数(该API可以在主域中使用),否则玩家只有在点击了排行榜按钮后才会将分数存入云托管。


逻辑:将每局分数与存储在本地的最高分进行比较,如果超过历史最高分数则同时更新本地和云托管数据。不需要再将分数传到子域。

getPlayerInfo方法笔者略过,这里重点讲下getFriendInfo方法:

// OpenData.js
getFriendInfo () {
    // 获取同城好友信息(包括自身)
    wx.getFriendCloudStorage({
        keyList: ['score'],
        success: (res) => {
            for (let i = 0; i < res.data.length; i++) {
                // 获取玩家微信名,头像url和分数
                let nickName = res.data[i].nickname;
                let avatarUrl = res.data[i].avatarUrl;
                let score = 0;
                if (res.data[i].KVDataList.length)
                    score = res.data[i].KVDataList[0]['value'];

                // 加入到数组中
                this.allInfoList.push({
                    nickName: nickName,
                    avatarUrl: avatarUrl,
                    score: score
                });
            }

            // 开始排名
            this.makeRanks();
        },

        fail: (res) => {
            console.log(res);
        }
    });
},

在该方法中笔者调用wx.getFriendCloudStorage()获取同城好友的云托管数据(只要好友玩过你的游戏,那他们的信息就可以从云托管中读取到)。注意wx.getFriendCloudStorage()也会返回自身的数据。

如果调用成功,我们就循环读取玩家的信息,并将数据添加到allInfoList数组中。获取完毕之后,就可以调用makeRanks方法进行排名了。

makeRanks方法编写如下:

// OpenData.js
makeRanks () {
    // 首先将allInfoList内部元素进行排序,根据分数来降序排列
    this.allInfoList.sort((a, b) => {
        return b['score'] - a['score'];
    });
    
    // 根据各个玩家的分数制作排名
    for (let i=0; i<this.allInfoList.length; i++) {
        let nickName = this.allInfoList[i]['nickName'];
        let avatarUrl = this.allInfoList[i]['avatarUrl'];
        let score = this.allInfoList[i]['score'];
        this.createItem(i+1, nickName, avatarUrl, score);
    }
},

第一步必须先对allInfoList内的元素按照分数进行排序,分数高排在最前。

接着循环数组,调用createItem方法生成预制:

// OpenData.js
createItem (rank, nickName, avatarUrl, score) {
    // 生成item
    let item = cc.instantiate(this.itemPrefab);
    
    // 排名
    item.children[0].getComponent(cc.Label).string = String(rank);
    // 微信名
    item.children[4].getComponent(cc.Label).string = nickName;
    // 分数
    item.children[5].getComponent(cc.Label).string = score;
    // 头像
    cc.loader.load({url: avatarUrl, type: 'png'}, (err, texture) => {
        if (err) console.error(err);
        item.children[1].getComponent(cc.Sprite).spriteFrame = new cc.SpriteFrame(texture);
    });

    // 添加到content中
    this.content.addChild(item);
}

构建运行

对主域项目和子域项目分别进行构建(哪个先构建没关系)。

主域:

  1. 发布平台选择微信小游戏。
  2. appid中填写自己小游戏的appid。
  3. 开放数据域代码目录填写子域项目文件夹名称。
  4. 填好之后点击构建。

子域:

  1. 发布平台选择微信小游戏开放数据域。
  2. 选好之后点击构建。

接着我们将子域项目下build文件夹中构建好的OpenDataDomain文件夹拷贝到主域项目下build文件夹下的wechatgame文件夹中:

P.S.其实我们在构建子域项目前修改下发布路径到主域的wechatgame文件夹中也可以。

如果微信开发者工具在引擎中配置好了的话,那我们打开主域项目的构建面板,点击运行就行了。

好,本节教程就到这,希望大家有所收获!

  • 14
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

la_vie_est_belle

谢谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值