赞
踩
在游戏中加入排行榜是非常有必要的。本节教程就带大家了解下如何在微信小游戏中加入排行榜。
运行效果如下:
Cocos Creator版本:2.2.0
后台回复"排行榜",获取该项目完整文件:
其实Cocos官方在文档中已经提供了较为详细的说明,并给出了一个Demo,大家可以先去了解下。
下图显示了笔者在主域项目中创建的节点:
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高度也可以自动调整。
效果如下:
现在我们需要一个预制,在该预制节点上会显示各个玩家的信息。
设置好后的效果如下:
接下来新建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);
- }
对主域项目和子域项目分别进行构建(哪个先构建没关系)。
主域:
子域:
接着我们将子域项目下build文件夹中构建好的OpenDataDomain文件夹拷贝到主域项目下build文件夹下的wechatgame文件夹中:
P.S.其实我们在构建子域项目前修改下发布路径到主域的wechatgame文件夹中也可以。
如果微信开发者工具在引擎中配置好了的话,那我们打开主域项目的构建面板,点击运行就行了。
好,本节教程就到这,希望大家有所收获!
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。