cocos-creator使用记录10_微信小游戏排行榜

1.安装cocos creator1.9.1
详细情况请看官方“接入微信小游戏的子域”,如下链接
http://docs.cocos.com/creator/manual/zh/publish/publish-wechatgame-sub-domain.html


作为参考也可以看赖肖的微博:
https://blog.csdn.net/laixiao_hero/article/details/80056195


2.实例
2.1.项目的创建
以下以我的项目为例。
主域项目目录:D:\cocosCreator_workspace\driver
排行榜项目(子域项目)目录:D:\cocosCreator_workspace\driverRank


主域项目场景文件:
start.fire //开始界面(启动场景)
game.fire  //游戏界面
rank.fire  //排行榜界面


排行榜项目(子域项目)场景文件:
fiveRank.fire   //要在结束界面显示的5人排行榜
friendRank.fire //好友排行榜
groupRank.fire  //群排行榜
rankMain.fire   //项目启动场景(只有画布一个节点,节点上挂了对应的切场景脚本)


注意:玩家看到的排行榜是由主域提供的滚动区背景、子域提供的滚动区内容组合而成的。
    简言之,把所有除了子项之外的界面元素放在主域中,子域只负责提供内容。


2.2.构建发布相关设置
主域项目---------
游戏名称:mrdriver
发布平台:Wechat Game
发布路径:D:\cocosCreator_workspace\web\mrdriver
渲染模式:自动


子域项目
游戏名称:children
发布平台:Wechat Game
发布路径:D:\cocosCreator_workspace\web\mrdriver\wechatgame
渲染模式:Canvas
小游戏子域工程:勾选


2.3.主域向子域发消息
以下以我的项目的在进入主域的排行榜界面为例。
Rank.js(主域)----------------------
var common = require('Common'); //全局变量
cc.Class({
    extends: cc.Component,
    properties: {
        subTitle: cc.Label, //标题
        tipsUINode: cc.Node, //提示文本节点
        lookGroupBtnNode: cc.Node, //查看群排行按钮
        subDomainCanvas: cc.Sprite, //子域画布
    },
    onLoad: function() {
        //用于临时保存子域画布的纹理
        this.subDomainTexture = new cc.Texture2D();
        //返回按钮只一次的开关
        this.playing = 0;
        //是否可以显示好友排行
        this.isCanShowFriendRank = false;
        //是否可以显示群排行
        this.isCanShowGroupRank = false;
        //发起群排行按钮
        this.lookGroupBtnNode.active = false;
        //隐藏自动消失提示框
        this.tipsUINode.active = false;
//预加载开始界面
cc.director.preloadScene("start");
        //初始化到好友榜页面
        this.reset();
    },
    reset: function(){ //恢复到默认的好友排行页
        this.subTitle.string = "好友排行榜";
        this.playing = 0;
        this.isCanShowFriendRank = true;
        this.isCanShowGroupRank = false;
        this.lookGroupBtnNode.active = true;


        if(!common.isHasWXRank) return;
        console.log("排行榜通知子域:friendRank");
        wx.postMessage({ message: "friendRank" }); //通知子域运行场景friendRank
    },
    onReturnBtnClicked: function(){ //返回按钮
        cc.log("点击返回按钮");
        if(this.playing == 0){
            this.playing = 1;
            common.previousSceneIndex = 3;
            cc.director.loadScene("start"); //从好友排行页面返回开始界面


            if(!common.isHasWXRank) return;
            console.log("排行榜通知子域:关闭");
            wx.postMessage({ message: "rankMain" }); 
        }
    },
    onLookGroupBtnClicked: function(){ //查看群排行按钮(实际是分享)
        cc.log("点击查看群排行按钮");
        if(!common.isHasWXRank) return;
        var self = this;
        cc.loader.loadRes("texture/share",function(err,data){
            wx.shareAppMessage({
                title: "不怕,就来PK!",
                imageUrl: data.url,
                success(res){
                    console.log("转发成功!!!")
                    if(res.shareTickets == null || res.shareTickets == undefined || res.shareTickets == ""){ //没有群信息,说明分享的是个人
                        console.log("排行榜res.shareTickets is null");
                        self.showTipsUI("查看群排行请分享到群"); //自动消失提示框
                    }else{ //有群信息
                        console.log("排行榜res.shareTickets is not null");
                        console.log(res);
                        self.subTitle.string = "群排行榜";
                        if(res.shareTickets.length > 0){
                            console.log("res.shareTickets:" + res.shareTickets);
                            self.lookGroupBtnNode.active = false;
                            wx.postMessage({ message: "groupRank" + res.shareTickets[0] }); //通知子域运行场景groupRank
                        }
                    }
                },
                fail(res){
                    console.log("转发失败!!!")
                } 
            })
        }); 
    },
    showTipsUI: function(content){ //显示自动消失提示框
        if(this.tipsUINode.active){
            this.tipsUINode.getComponent("FadeOut").init();
        }
        this.tipsUINode.getComponent("FadeOut").fadeDuration = 2;
        this.tipsUINode.getComponent("SetContent").setContent(content);
        this.tipsUINode.active = true;
    },
    update: function(dt){
        if(!common.isHasWXRank) return;
        if(this.isCanShowFriendRank || this.isCanShowGroupRank){ //显示子域的画布
            if (!this.subDomainTexture) return;
            this.subDomainTexture.initWithElement(sharedCanvas);
            this.subDomainTexture.handleLoadedTexture();
            this.subDomainCanvas.spriteFrame = new cc.SpriteFrame(this.subDomainTexture);
        }
    },
});

RankMain.js(子域)---------------------------------------
var common = require('Common'); //全局变量
cc.Class({
    extends: cc.Component,
    properties: {
    },
    onLoad: function() {
        wx.onMessage(data => {
            if(data.message == "rankMain"){ //主场景
                cc.director.loadScene("rankMain");
            }else if(data.message == "friendRank"){ //好友排行榜
                cc.director.loadScene("friendRank");
            }else if(data.message == "fiveRank"){ //5人排行榜
                cc.director.loadScene("fiveRank");
            }else{ 
                var str = data.message.substr(0,9);
                if(str == "groupRank"){ //群排行榜(这里将群的shareTicket加在"groupRank"后一起传过来)
                    common.groupShareTicket = data.message.substr(9, data.message.length - 9);
                    cc.director.loadScene("groupRank");
                }
            }
        });
    },
});

2.4.获得自己的信息
wx.getUserInfo({
openIdList: ['selfOpenId'],
lang: 'zh_CN',
success(res){
if(res.data){
console.log(res.data);
if(res.data[0].nickName != undefined && res.data[0].avatarUrl != undefined){
self.selfName.string = res.data[0].nickName;
//console.log("自己的信息1:nickname=" + res.data[0].nickName);
self.createImage(self.selfHead, res.data[0].avatarUrl);
//console.log("自己的信息1:avatarUrl=" + res.data[0].avatarUrl);
self.selfNode.active = true;
}else{
console.log("自己的信息1:undefined");
}
}                
},
fail(){
//console.log(res)
console.log("获取自己的信息失败");
}
})
由上,这里只列举了获得自己的名字和头像信息,其他还可以获得性别、城市等。
注意:若你查看微信官方的wx.getUserInfo的API说明,其中说可以获取自己openid,但实际上在打印
    的信息中显示的openid是'selfOpenId'。因此我们在后面获得自己的排名,是先在以上这一步保
存自己的名字和头像信息,再查询自己的名字和头像信息来确定自己在排行榜中的索引,从而获
得自己的排名。

2.5.获得自己的托管数据
wx.getUserCloudStorage({
keyList: ["driver_MaxScore"],
success(res){
console.log("自己的托管数据");
if(res.KVDataList){
var dList = res.KVDataList;
console.log("自己的托管数据1:dList.length=" + dList.length);
for(var i = 0; i < dList.length; i++){
if(dList[i].key == "driver_MaxScore"){
console.log("自己的托管数据1:" + dList[i].value);
self.selfScore.string = dList[i].value;
break;
}
}
}                
},
fail(){
//console.log(res)
console.log("获取自己的托管数据失败");
}
})


2.6.获得微信同玩好友
wx.getFriendCloudStorage({
keyList: ["driver_MaxScore"],
success(res){
console.log(res)
if(res.data){
self.tips.active = false;
//按maxScore从大到小排列
self.sortList(res.data, false); 
for(var i = 0; i < res.data.length; i++){
var item = cc.instantiate(self.RankItem, i); //生成node节点
item.parent = self.content;
item.getComponent("RankItem").initView(res.data[i], i);  

self.content.height = self.RankItem.data.height * res.data.length;
//获得自己对应的data索引
var selfDataIndex = null;
//先比较昵称
var sameNameList = [];
for(var i = 0; i < res.data.length; i++){
if(res.data[i].nickname == self.selfName){
sameNameList.push(i);
}
}
if(sameNameList.length < 1){
console.log("Rank:好友的信息1:未找到同名自己");
}else if(sameNameList.length == 1){
console.log("Rank:好友的信息2:找到1个同名自己");
selfDataIndex = sameNameList[0];
}else{
//再比较头像
var sameHeadList = [];
for(var i = 0; i < sameNameList.length; i++){
if(res.data[i].avatarUrl == self.selfHead){
sameHeadList.push(i);
}
}
if(sameHeadList.length < 1){
console.log("Rank:好友的信息3:未找到同头像自己");
}else if(sameHeadList.length == 1){
selfDataIndex = sameHeadList[0];
}else{
//再比较最高积分
var sameMaxScoreList = [];
for(var i = 0; i < sameNameList.length; i++){
var dList = res.data[sameNameList[i]].KVDataList;
for(var j = 0; j < dList.length; j++){
if(dList[j].key == "driver_MaxScore" && dList[j].value == self.selfScore){
sameMaxScoreList.push(i);
}
}
}
if(sameMaxScoreList.length < 1){
console.log("Rank:好友的信息3:未找到同周最高积分自己");
}else if(sameMaxScoreList.length == 1){
selfDataIndex = sameMaxScoreList[0];
}else{ //到这里,发现多个同昵称、同头像、同最高积分的玩家,只能随机了
var value = Math.floor(Math.random() * (sameMaxScoreList.length - 1 + 1) + 1) - 1;
selfDataIndex = sameMaxScoreList[value - 1];
}
}
}
console.log("Rank:selfDataIndex=" + selfDataIndex);
//设置自己的信息
self.setSelfInfo(selfDataIndex); 
}else{
self.tips.active = true;
}               
},
fail(){
//console.log(res)
console.log("Rank:获取好友的信息失败");
self.tips.active = true;
}
})


2.7.获得微信群同玩好友
wx.getGroupCloudStorage({
shareTicket: common.groupShareTicket,
keyList: ["driver_MaxScore"],
success(res){
console.log(res)
if(res && res.data){
self.tips.active = false;
//按maxScore从大到小排列
self.sortList(res.data, false); 
for(var i = 0; i < res.data.length; i++){ 
var item = cc.instantiate(self.RankItem, i); //生成node节点
item.parent = self.content;
item.getComponent("RankItem").initView(res.data[i], i);  

self.content.height = self.RankItem.data.height * res.data.length;
//获得自己对应的data索引
var selfDataIndex = null;
//先比较昵称
var sameNameList = [];
for(var i = 0; i < res.data.length; i++){
if(res.data[i].nickname == self.selfName){
sameNameList.push(i);
}
}
if(sameNameList.length < 1){
console.log("Rank:好友的信息1:未找到同名自己");
}else if(sameNameList.length == 1){
console.log("Rank:好友的信息2:找到1个同名自己");
selfDataIndex = sameNameList[0];
}else{
//再比较头像
var sameHeadList = [];
for(var i = 0; i < sameNameList.length; i++){
if(res.data[i].avatarUrl == self.selfHead){
sameHeadList.push(i);
}
}
if(sameHeadList.length < 1){
console.log("Rank:好友的信息3:未找到同头像自己");
}else if(sameHeadList.length == 1){
selfDataIndex = sameHeadList[0];
}else{
//再比较最高积分
var sameMaxScoreList = [];
for(var i = 0; i < sameNameList.length; i++){
var dList = res.data[sameNameList[i]].KVDataList;
for(var j = 0; j < dList.length; j++){
if(dList[j].key == "driver_MaxScore" && dList[j].value == self.selfScore){
sameMaxScoreList.push(i);
}
}
}
if(sameMaxScoreList.length < 1){
console.log("Rank:好友的信息3:未找到同周最高积分自己");
}else if(sameMaxScoreList.length == 1){
selfDataIndex = sameMaxScoreList[0];
}else{ //到这里,发现多个同昵称、同头像、同最高积分的玩家,只能随机了
var value = Math.floor(Math.random() * (sameMaxScoreList.length - 1 + 1) + 1) - 1;
selfDataIndex = sameMaxScoreList[value - 1];
}
}
}
console.log("Rank:selfDataIndex=" + selfDataIndex);
//设置自己的信息
self.setSelfInfo(selfDataIndex); 
}else{
self.tips.active = true;
}                
},
fail(){
//console.log(res)
console.log("Rank:获取群的信息失败");
self.tips.active = true;
}
})
注意:common.groupShareTicket是从主域传过来的群分享成功后获得的ShareTicket,
这里我用一个全局变量将其保存,以在以上使用。


2.8.排序函数
sortList: function(ListData, order){ //排序(ListData:res.data;order:false降序,true升序)
ListData.sort(function(a,b){
var AMaxScore = 0;
var KVDataList = a.KVDataList;
for(var?i = 0;?i < KVDataList.length;?i++){
if(KVDataList[i].key?==?"driver_MaxScore"){
AMaxScore?=?KVDataList[i].value;
}
}


var BMaxScore = 0;
KVDataList = b.KVDataList;
for(var i = 0; i<KVDataList.length; i++){
if(KVDataList[i].key == "driver_MaxScore"){
BMaxScore = KVDataList[i].value;
}
}


if(order){
return parseInt(AMaxScore) - parseInt(BMaxScore);
}else{
return parseInt(BMaxScore) - parseInt(AMaxScore);
}
});
return ListData;
}
注意:请以以上作为排序的方法,不要使用网上的js的通用排序比较函数。否则,
   会出现不同手机上显示的排行榜不同的问题。


3.问题总结
3.1.关于挂在主域项目下的用于显示子域的精灵对象
官方例子中命名为:
subDomainCanvas
其大小为占整个屏幕,SpriteFrame属性为空,坐标位于主域的中心。
这里容易犯的错误就是,直接创建了一个精灵,而没有设置其大小。


3.2.莫名其妙的子域内容会缩小
问题的根源是显示子域的精灵对象的Size Mode未设置对。
默认精灵对象的Size Mode是TRIMMED,即裁剪模式。
将其设置为CUSTOM即可。


3.3.滚动区的子项的设置
首先,子项是要挂接在滚动区的content下的。
其预制文件宽度要设置的比content的宽度小一点。
子项预制文件的坐标是(375,1334),为啥是这个值,你可以将其预制文件拖
到滚动区的content下,看看其效果。
子项预制文件使用了Widget组件,其勾选了上、左、右,对应的挂接在其上
的脚本中控制其Y坐标的代码也使用的是Widget组件的Top位置。


3.4.关于保存到微信服务器的字段
我是按以下
uploadWXData: function(bestHeight){ //上报到微信服务器:历史最高分
var kvDataList = new Array();
kvDataList.push({key:"driver_MaxScore", value: "" + bestHeight});
wx.setUserCloudStorage({ KVDataList: kvDataList })
},
由上,我用的字段名字是"driver_MaxScore",其中driver是我的项目名字,每个
人根据开发项目不同请取不同的名字。因为,不排除微信服务器只是给用户在数据
库中用json格式保存了一个字符串,若是遇到其他游戏的同名字段,你的数据必然
会被覆盖。
另外,要注意以上字段名字的统一性,我的项目中在排行榜脚本、子项脚本中都
使用了"driver_MaxScore"。若是你想避免以后遇到要修改此字段名字时要多处修
改,可以创建一个全局字符串保存其值。
最后,我一般会在玩家进入游戏界面时,上传一次字段的值,在字段对应的值(这里
是历史最高分)有更高的值时,再上传一次。这样,就保证了之前版本的玩家的记录
会在第1时间显示在排行榜。


3.5.关于头像
根据creator的提示,mask在canvas模式下会失效,即只能使用方形头像。
微信的头像链接的图片一般图片大小为507*507,要控制头像大小,只需要将Sprite
对象挂接到一个固定大小的节点下。
若是你想查看微信的头像,链接后面加上 ?aaa=aa.jpg 这几个字符,就能够访问到
图片了。


3.6.关于子域的滚动区
在开发中遇到一个奇怪的问题,就是触摸子域的滚动区不滚动,后来发现是因为在

模块设置时没有勾选ScrollView。


3.7.关于子域效率的优化
由上面的代码可以发现,子域的东西是在主域中每帧刷新的,这里就可以自己在
update中创建一个计时器,控制刷新的频率。如下:
this.timer += dt;
if(this.timer > 0.2){
...
}
以上从每帧刷改为0.2秒刷一次,至少可以提升10帧的fps。

猜你喜欢

转载自blog.csdn.net/haibo19981/article/details/80435962