新手小白福音:CocosCreator微信小游戏排行榜保姆级教程,它来了~
做游戏,那就避免不了整个排行榜功能,因为对于一个游戏来说,排行榜绝对是必不可少的一个功能,它在一定程度上能给增加玩家的活跃度,从而大大的提高游戏自身的曝光量。
那么今天,就让小威带大家一起走进“怎样给微信小游戏加入排行榜功能”的茶话会吧~不是自夸,绝对干货,新手入门开发者的福音~不接受任何反驳,你要反驳那就算你赢~hahaha~
其他的前置内容就不用我多说了嘛,自行解决,今天重点只说排行榜,为了用户隐私和数据安全,微信的好友数据只能在开放数据域中使用,那么这个时候就会有客官会问:神马是开放数据域?很好,给你一个小心心。
对于微信开放数据域,Cocos官方有相关文档进行解释,如图:
对于如何整合,Cocos官方也有详细说明,如图:
好了,直接进入主题吧,首先我们需要在主项目(以下称主域)中增加显示排行榜的触发按钮,以及搭建要显示排行榜(以下称子域)的窗口UI结构(这里我们尽可能的将除了数据部分之外的功能都放在主域中展示,不要问为什么,因为问了我也不会说,哈哈哈~还有就是今天重点只说好友榜,其他的暂时无视~)
重点来了,有注意到topContent这个节点了波(这个名字根据你喜欢随意),这个节点上有个SubContextView组件,要有这个属性,这个节点才会成为子域的容器窗口,子域的内容也才会显示在主域上,所以这个节点的大小要跟子域大小保持一致,不然嘛,你懂得~
接下来就是今天的重头戏咯,竖起你的小耳朵仔细听,当我们在主域中点击排行榜按钮的时候,我们除了要显示主域中显示排行榜的窗口外,还需要通过wx.postMessage向子域发送指令信息,以此来获取排行榜数据或者设置玩家成绩(因为获取开放数据域数据的api只能在子域中调用,所以主域只能发送相关指令,子域根据对应指令执行相关api)。
cc.Class({ extends: cc.Component, properties: { FriendcontentBg:cc.Node, FriendBtn:cc.Node, }, //关闭排行榜 hide() { this.node.active = false; wx.postMessage({ type: 'close_rank' }); }, //上一页 prePage(userInfo) { if (window.wx) { if(this.FriendcontentBg.active){ wx.postMessage({ type: 'pre_page', userinfo: { openid: userInfo.openid, avatar: userInfo.avatar, nickName: userInfo.nickname, score: userInfo.MaxScor } }); } } }, //下一页 nextPage(userInfo) { if (window.wx) { if(this.FriendcontentBg.active){ wx.postMessage({ type: 'next_page', userinfo: { openid: userInfo.openid, avatar: userInfo.avatar, nickName: userInfo.nickname, score: userInfo.MaxScor } }); } } }, //发送数据给私域 postMsg(top_name,userinfo) { window.sharedCanvas.width = 658; window.sharedCanvas.height = 810; window.wx.postMessage({ type: top_name, name: "", size: { width: 658, height: 810 }, userinfo: { openid: userinfo.openid, avatar: userinfo.avatar, nickName: userinfo.nickname, score: userinfo.MaxScore } }); }, //展示排行榜 show() { this.node.active = true; this.scheduleOnce(() => { this.postMsg("show_rank"); }, 1); this.FriendcontentBg.active = true this.FriendBtn.active = true }, });
下面我们新建一个子域项目,需要注意的是子域中的Canvas节点组件的大小要设置成与主域的容器节点大小一致,否则运行效果会与预期有所出入。
接着,我们就制作排行榜的布局,并将写好的列表制作成预制体rankitem,这里跟普通页面布局一样,就不一一赘述了。
编写rankitem脚本,并添加到预制体rankitem上,主要是设置头像、昵称、分数、地址等信息。
const { get } = require('http'); var util = require('util'); cc.Class({ extends: cc.Component, properties: { secondSpr: { default: null, type: cc.SpriteFrame }, thirdSpr: { default: null, type: cc.SpriteFrame }, _number: 0, _avatar: '', _nickName: '', _score: 0, _city:'', number: { get() { return this._number; }, set(value) { var spr = this.node.getChildByName('art'); var order = this.node.getChildByName('num'); if (value > 3 || value=="无") { spr.active = false; order.active = true; var label = order.getComponent(cc.Label); label.string = value; } else { spr.active = true; order.active = false; var spr1 = spr.getComponent(cc.Sprite); if (value == 2) { spr1.spriteFrame = this.secondSpr; } else if (value == 3) { spr1.spriteFrame = this.thirdSpr; } } this._number = value; } }, avatar: { get() { return this._avatar; }, set(value) { util.loadImg(value, (sf) => { var avatar = this.node.getChildByName('avatar').getChildByName("sub").getComponent(cc.Sprite); avatar.spriteFrame = sf; }); this._avatar = value; } }, nickName: { get() { return this._nickName; }, set(value) { var nick = this.node.getChildByName('nick'); if (nick) { var label = nick.getComponent(cc.Label); label.string = value; } this._nickName = value; } }, city: { get() { return this._city; }, set(value) { var city = this.node.getChildByName('city'); var city_icon = this.node.getChildByName('city').getChildByName("address") if(value){ city_icon.active = true; if (city) { var label = city.getComponent(cc.Label); label.string = value; } this._city = value; }else{ city_icon.active = false; city.active = false; } } }, score: { get() { return this._score; }, set(value) { var label = this.node.getChildByName('score').getComponent(cc.Label); label.string = value; this._score = value; } } }, });
编写rank脚本,主要是获取成绩和展示成绩列表的功能,在子域中,我们需要使用wx.onMessage来监听主域发送过来的指令。
var rankItem = require('rankitem'); var util = require('util'); var etype = { rankwrap: 1, } cc.Class({ extends: cc.Component, properties: { subElement: { default: [], type: cc.Node }, rankWrap: { default: null, type: cc.Node }, rankItem: { default: null, type: cc.Prefab }, Mycontent: { default: null, type: cc.Node }, prebt: { default: null, type: cc.Node }, nextbt: { default: null, type: cc.Node }, loading: { default: null, type: cc.Node }, }, //获取数据存储的key getFlag() { return 'game_top_list' }, //关闭排行榜 closRank() { this.sumpage = 1; this.curpage = 1; this.rankWrap.removeAllChildren(); this.Mycontent.removeAllChildren(); }, //处理排行榜数据并渲染排行榜信息 updateRank(data, offset, userinfo,page) { this.rankWrap.removeAllChildren(); if (offset == 0) { } let openId = userinfo.openid; let MyInfo = this.MyInfoss if(page != "page"){ MyInfo = { number: "未上榜", avatar: userinfo.avatar, nickName: userinfo.nickName, score: userinfo.score + "分", city: "" }; } data.forEach((v, i) => { var obj = v.KVDataList.find(v1 => v1.key == this.getFlag()) || { value: 0 }; if(obj.value ==""){ obj.value = 0; } var param = { number: offset + i + 1, avatar: v.avatarUrl, nickName: v.nickname, score: obj.value + "分", city: "" } //获取自己所在排名 if (page != "page" && v.openid == openId) { MyInfo.number = offset + i + 1; MyInfo.avatar = v.avatarUrl; MyInfo.nickName = v.nickname; MyInfo.score = obj.value + "分"; MyInfo.city = ""; this.MyInfoss = MyInfo } //渲染排行榜数据信息 var item = cc.instantiate(this.rankItem); item.parent = this.rankWrap; var curitem = item.getComponent('rankitem'); for (var k in param) { curitem[k] = param[k]; } }); //渲染自己所在榜信息 this.Mycontent.removeAllChildren(); var items = cc.instantiate(this.rankItem); items.parent = this.Mycontent; var curitems = items.getComponent("rankitem"); for (var ks in MyInfo) { curitems[ks] = MyInfo[ks]; } //上一页 下一页按钮 this.prebt.active = this.curpage == 1 ? false : true; this.nextbt.active = this.curpage == this.sumpage ? false : true; //关闭加载动画 this.hideLoading(); }, //上一页 prePage(userinfo) { this.getRankData((data, offset) => this.updateRank(data, offset, userinfo,"page"), null, this.curpage); }, //下一页 nextPage(userinfo) { this.curpage = Math.min(this.curpage + 1, this.sumpage); this.getRankData((data, offset) => this.updateRank(data, offset, userinfo,"page"), null, this.curpage); }, //获取排行榜数据 getRankData(cb, score, page) { //获取排行榜数据 if (page && page > 1 && this.rankData) { var offset = (page - 1) * 6; cb(this.rankData.slice(offset, offset + 6), offset); return; } if (window.wx) { window.wx.getFriendCloudStorage({ type: "group", keyList: [this.getFlag()], extra: { sortKey: this.getFlag(), // 指定的key需 groupId: "level_group" }, success: res => { var data = res.data; data.forEach(v2 => { v2.KVDataList = v2.KVDataList.map(v1 => { if (v1.key == this.getFlag()) { var vobj = JSON.parse(v1.value); if (typeof (vobj) != "number") { v1.value = vobj.ttgame.score; v1.update_time = vobj.ttgame.update_time; } } return v1; }) }); if (score) { var selfitem = data.find(v1 => v1.avatarUrl == this.selfAvatar); if (selfitem) { var selfObj = selfitem.KVDataList.find(v1 => v1.key == this.getFlag()); selfObj.value = score; } else { data.push({ nickname: this.selfNick, avatarUrl: this.selfAvatar, KVDataList: [{ key: this.getFlag(), value: score }] }); } } data.sort((a, b) => { if (a.KVDataList.length == 0 && b.KVDataList.length == 0) { return 0; } if (a.KVDataList.length == 0) { return 1; } if (b.KVDataList.length == 0) { return -1; } var obj1 = b.KVDataList.find(v1 => v1.key == this.getFlag()); var obj2 = a.KVDataList.find(v1 => v1.key == this.getFlag()); return obj1.value - obj2.value; }); //获取当前所属周的周一和周日时间戳 var times = util.getMondayAndSundayTimestamps(); var datas = []; //过滤非本周成绩的数据 data.forEach(v1 => { if (v1.KVDataList[0].key ==this.getFlag() && v1.KVDataList[0].update_time >= times.monday && v1.KVDataList[0].update_time <= times.sunday) { datas.push(v1); } }) this.rankData = datas; //分页数据 this.sumpage = Math.ceil(datas.length / 6); if (page) { var offset = (page - 1) * 6; datas = datas.slice(offset, offset + 6); } cb(datas, offset); }, }); } }, //展示排行榜信息 showRank(size, name, userinfo) { //显示加载动画 this.showLoading(); this.playerName = name; this.subElement.forEach(v => v.active = false); this.subElement[etype.rankwrap].active = true; var sz = cc.director.getWinSize(); this.getRankData((data, offset) => this.updateRank(data, offset, userinfo,""), null, 1); }, //显示加载动画 showLoading() { this.loading.active = true; }, //关闭加载动画 hideLoading() { this.loading.active = false; }, // onLoad() { this.sumpage = 1; this.curpage = 1; this.MyInfoss = []; if (window.wx) { //监听来自主域的指令 wx.onMessage(msg => { if (msg.type == "show_rank") { this.curpage = 1; this.showRank(msg.size, msg.name, msg.userinfo); }else if (msg.type == "pre_page") { this.prePage(msg.userinfo,msg.top_type); }else if (msg.type == "next_page") { this.nextPage(msg.userinfo,msg.top_type); }else if (msg.type == "close_rank") { this.closRank(); } }) } }, });
这时候,可能有人会问,那怎么提交好友的成绩到微信开放域呢?真棒,这都被你发现了,奖励你大聪明一个~
设置成绩很简单,先封装提交分数的方法setScore:
setScore(key, value) {
if (window.wx) { var recordCurTime = Date.parse(new Date()); const data = { ttgame: { score: value, update_time: Math.floor((new Date()).getTime() / 1000), }, }; if (window.wx) { wx.setUserCloudStorage({ KVDataList: [ { key: key, value: JSON.stringify(data) }, ], }); } } }
然后再游戏结束的时候调用这个方法即可:
this.setScore("game_top_list", 8888888);
终于到了我们的最后一步咯,你猜的没错,就是打包~首先是在主域项目中打开构建发布面板,设置好相关参数,并将开放数据域代码目录设置为你的子域项目名称,然后进行构建操作。
接着就是子域项目进行构建发布,将发布平台设置为微信小游戏开放数据域,发布路径设置为主域项目打包的根目录(一般是你的主项目目录下build/wechatgame/),然后进行项目构建。
全部构建完成之后,我们打开微信开发者工具来运行我们的主项目,这个时候点击排行榜就能看到排行列表啦~很激动有木有(如果你看不到数据的话,那就说明还没有上传过分数)~
好咯,以上就是袁小威此次所有的分享了,小弟不才,各位客官老爷多多包涵,奏事酱紫,我们下次见~
很赞哦! (0)
赏
上一篇: 微信小程序之HTML富文本解析