cocos creator 实现原生微信小游戏排行榜

本文以玩家身上钱为例,主要讲述在cocos中,如何使用原生的排行榜,显示好友排行
效果如图:

排行1
排行2

一、准备工作:
1、在打包出的目录里,创建src/myOpenDataContext文件夹,在文件夹myOpenDataContext中新建空js文件index.js,稍等我们再来完善index.js里的内容;
2、在打包出的目录里,在gmae.json中加上"openDataContext": "src/myOpenDataContext"

二、上传玩家数据:
本文以玩家身上金钱为例,注意上传的key

 // 上传玩家数据
        wx.setUserCloudStorage({
            KVDataList: [{
                key: "person_total_money",
                value: money
            }, {
                key: "username",
                value: username
            }],

            success: function (res) {
                console.log("upload success");
            },

            fail: function (res) {
                console.log("upload fail");
            },
        });

三、向子域发送消息

        // 向子域发送消息 请注意此处key的值,和之前上传的key一致
        // 若实现的是群排行,则需要传shareTicket(可从onShow中获得)
        wx.getOpenDataContext().postMessage({
            keyName: "person_total_money",
            shareTicket: this.shareTicket,
            keyUsername: "username",
            keyUnit: "金蛋",
        });

四、完善子域中的代码(index.js),添加以下代码

        let sharedCanvas = null;
        let context = null;
        let heightPerUser = 146; // 单个玩家排行的高度
        let widthPerUser = 808; // 单个玩家排行的宽度

        wx.onMessage(function (data) {
            if (sharedCanvas == null) {
                sharedCanvas = wx.getSharedCanvas();
            }
            if (context == null) {
                // 获取画布对象的绘图上下文
                context = sharedCanvas.getContext('2d');
            }

            // 清除画布上在该矩形区域内的内容
            context.clearRect(0, 0, widthPerUser, heightPerUser * 10);

            wx.getUserCloudStorage({
                keyList: ["username"],

                success: function (res) {
                    // 先获得自己的数据,这样在排行榜中可以突显自己的位置
                    // (若没有这个需求,可以不要这一步)
                    let kvData = res.KVDataList;
                    let myKvData = kvData[0];
                    let myUsername = "";
                    if (myKvData != null) {
                        myUsername = res.KVDataList[0].value;
                    }

                    if (data.shareTicket) {
                        // 获取群同玩成员的游戏托管数据
                        wx.getGroupCloudStorage({
                            shareTicket: data.shareTicket,
                            keyList: [data.keyName, data.keyUsername],

                            success: function (res) {
                                // res.data有所有在玩好友的数据
                                // 包含 头像:avatarUrl, 昵称:nickname, 用户的托管KV数据列表:KVDataList, 
                                drawRankList(res, myUsername, data.keyName, data.keyUsername, data.keyUnit);
                            },

                            fail: function (res) {
                                drawFail();
                            },
                        });
                    } else {
                        // 当前用户所有同玩好友的托管数据
                        wx.getFriendCloudStorage({
                            keyList: [data.keyName, data.keyUsername],

                            success: function (res) {
                                // res.data有所有在玩好友的数据
                                // 包含 头像:avatarUrl, 昵称:nickname, 用户的托管KV数据列表:KVDataList, 
                                drawRankList(res, myUsername, data.keyName, data.keyUsername, data.keyUnit);
                            },

                            fail: function (res) {
                                drawFail();
                            },
                        });
                    }
                },

                fail: function (res) {
                    console.log("getUserCloudStorage 失败");
                    drawFail();
                }
            });
        });
    },

    function drawRankList(res, myUsername, keyName, keyUsername, unitName = "") {
        if (res == null || res.data == null || res.data.length == null || res.data.length < 1) {
            drawFail();
            return;
        }

        //初始化信息
        let data = res.data;
        let rankInfo = [];
        for (let i in data) {

            let personData = data[i];
            let usernameKeyIndex = -1;
            let keyNameIndex = -1;

            let KVDataLen = personData.KVDataList.length; // KVDataList是用户的托管 KV 数据列表
            for (let i = 0; i < KVDataLen; i++) {
                if (personData.KVDataList[i].key === keyUsername) {
                    usernameKeyIndex = i;
                } else if (personData.KVDataList[i].key === keyName) {
                    keyNameIndex = i;
                }
            }

            let obj = {};
            if (personData.KVDataList[keyNameIndex] != null) {
                obj.score = personData.KVDataList[keyNameIndex].value;
            } else {
                obj.score = "-1";
            }
            if (personData.nickname) {
                obj.nickname = personData.nickname;
            }
            if (personData.avatarUrl) {
                obj.headimgurl = personData.avatarUrl;
            }
            if (personData.KVDataList[usernameKeyIndex] != null) {
                obj.username = personData.KVDataList[usernameKeyIndex].value;
            }
            obj.rank = 0;
            obj.isSelf = false;
            rankInfo.push(obj);
        }

        console.log("共获取到了排行数据数量:" + rankInfo.length);

        //对排行数据排序
        rankInfo.sort(function (m, n) {
            let intM = parseInt(m.score);
            let intN = parseInt(n.score);

            if (typeof intM !== "number" || intM == NaN || intM < 0) {
                intM = -1;
            }
            if (typeof intN !== "number" || intN == NaN || intN < 0) {
                intN = -1;
            }

            m.score = intM;
            n.score = intN;

            if (intM > intN) {
                return -1;
            } else if (intM < intN) {
                return 1;
            } else {
                // 名次相等,按固定规则排序
                if (m.nickname > n.nickname) {
                    return 1;
                }
                if (m.nickname < n.nickname) {
                    return -1;
                }
                return 0;
            }
        });

        let rank = 0;
        for (let i = 0; i < rankInfo.length; i++) {
            rank++;
            rankInfo[i].rank = rank;
        }

        for (let i = 0; i < rankInfo.length; i++) {
            let st = rankInfo[i].score;
            if (st == -1) {
                st = "暂无数据";
            } else {
                st = st + unitName;
            }
            rankInfo[i].score = st;

            if (rankInfo[i].username === myUsername) {
                // 找到自己 方便后面排名时,突显自己
                rankInfo[i].isSelf = true;
            }
        }

        draw(rankInfo);
    }

    function draw(rankInfo) {
        for (let i = 0; i < rankInfo.length; i++) {
            let rankItem = rankInfo[i];
            let y = i * heightPerUser;

            context.textAlign = 'left';
            if (rankItem == null || rankItem == {}) {
                context.fillStyle = "#FFDEC0";
                context.font = "bold 56px SimHei";
                context.fillText("无法获得玩家数据", 110, y + 90);
                continue;
            }


            if (rankItem.isSelf) {
                context.fillStyle = "#a37d56";
                context.fillRect(0, y, widthPerUser, heightPerUser);
            }

            let nickname = rankItem.nickname;
            let score = rankItem.score;
            let headimgurl = rankItem.headimgurl;
            let rank = "" + rankItem.rank;
            
            // 绘制分数
            let scoreTextLen = renderLengthOf(score);
            let fontReduce = Math.floor(scoreTextLen - 11);
            if (fontReduce < 0) {
                fontReduce = 0;
            }
            context.font = (48 - fontReduce) + "px SimHei";
            context.fillStyle = '#FFDEC0';
            context.fillText(score, 344, y + 126);

            // 绘制昵称
            context.fillStyle = "#FFFFFF";
            nickname = trimString(nickname, 13);
            context.font = "48px SimHei";
            context.fillText(nickname, 344, y + 58);

            // 绘制头像
            let img = wx.createImage();
            img.src = headimgurl;
            img.onload = function (res) {
                let heightImg = res.target.height;
                let widthImg = res.target.width;
                context.drawImage(img, 0, 0, widthImg, heightImg, 160, y + 10, 124, 124);
            }
            
            // 绘制排名
            context.textAlign = 'center';
            drawRankNum(rank, y);

            if (i >= 10) {
                // 仅绘制前10个玩家
                break;
            }
        }

        for (let j = 0; j < 10; j++) {
            let y = j * heightPerUser;
            context.fillStyle = "#a5805a";
            context.fillRect(0, y + heightPerUser - 4, widthPerUser, 2);
            context.fillStyle = "#d5ad88";
            context.fillRect(0, y + heightPerUser - 2, widthPerUser, 2);
        }
    }

    // 渲染长度
    function renderLengthOf(str) {
        var len = 0;
        for (var i = 0; i < str.length; i++) {
            if (isChinese(str.charAt(i))) {
                len += 2;
            } else {
                len += 1;
            }
        }

        return len;
    },
    //判断是不是中文  
    function isChinese(char) { 
        var reCh = /[u00-uff]/;
        return !reCh.test(char);
    }

    //截断过长的文字,用...代替过长的部分,注意这里判断是基于文字的渲染长度
    function trimString(string, renderLengthMax) {
        let len = string.length;
        let renderLen = renderLengthOf(string);
        let l = 0;

        if (renderLen > renderLengthMax) {
            let lenToSubstr = 0;
            for (let i = 0; i < len; i++) {
                if (isChinese(string[i])) {
                    l += 2;
                } else {
                    l += 1;
                }
                lenToSubstr++;

                if (l >= renderLengthMax) {
                    string = string.substr(0, lenToSubstr);
                    string = string + "..";
                    break;
                }
            }
        }

        return string;
    }

    function drawRankNum(rank, y) {
        if (rank <= 3) {
            // 绘制排名的名次图片 此处仅绘制前3名
            let img = wx.createImage();
            img.src = "customRes/rank" + rank + ".png";
            img.onload = function (res) {
                let heightImg = res.target.height;
                let widthImg = res.target.width;
                context.drawImage(img, 0, 0, widthImg, heightImg, 10, y + 14, 114, 112)
            }
        } else if (rank < 10) {
            context.font = "bold 64px Calibri";
            context.fillText(rank, 68, y + 94);
        } else if (rank < 100) {
            context.font = "bold 60px Calibri";
            context.fillText(rank, 68, y + 94);
        } else {
            context.font = "bold 60px Calibri";
            context.fillText("99+", 64, y + 94);
        }
    }

    function drawFail() {
        context.textAlign = 'left';
        context.font = "bold 56px SimHei";
        context.fillStyle = '#FFFFFF';

        context.fillText("无法获取排行数据", 110, 90);
        context.fillStyle = '#FFDEC0';
        context.fillText("请过段时间再来", 110, heightPerUser + 90);
    }

    function drawEmpty() {
        context.textAlign = 'left';
        context.font = "bold 56px SimHei";
        context.fillStyle = '#FFFFFF';

        context.fillText("无人占据排行榜哦", 110, 90);
        context.fillStyle = '#FFDEC0';
        context.fillText("排行榜数据定期重置", 110, heightPerUser + 90);
    }

五、在游戏中将子域中的排行榜绘制出来

    init: function () {
        let openDataContext = wx.getOpenDataContext();
        this.sharedCanvas = openDataContext.canvas;
        this.sharedCanvas.width = 808;
        this.sharedCanvas.height = 1460;
    },

    startRefesh: function () {
        if (!this.sharedCanvas) {
            this.init();
        }

        this.refreshStart = true;

        // 防止子域响应慢,或者头像加载慢
        // 每隔0.7s 绘制1次 总共绘制6次
        this.refreshTimeRest = 6;
        this.refreshTimer = 0.4
        this.refreshInterval = 0.7;
    },

    update: function (dt) {
        if (this.texture == null) {
            this.texture = new cc.Texture2D();
        }
        if (this.refreshStart && this.refreshTimeRest > 0) {
        // 每隔0.7s 绘制1次 总共绘制6次
            this.refreshTimer += dt;
            if (this.refreshTimer > this.refreshInterval) {
                this.refreshTimer -= this.refreshInterval;
                this.refreshTimeRest--;
                this.show();
            }
        }
    },

    show: function () {
        if (this.spriteFrame) {
            this.spriteFrame.clearTexture();
        }

        if (this.texture) {
            if (!this.sharedCanvas) {
                this.init()
            }

            this.texture.initWithElement(this.sharedCanvas);
            this.texture.handleLoadedTexture();
            this.spriteFrame = new cc.SpriteFrame(this.texture);

            // 此处已经拿到了spriteFrame,可以随便放在需要的sprite上了
            this.rankSprite.spriteFrame = this.spriteFrame;
        }
    },

    hide: function () {
        if (this.spriteFrame) {
            this.spriteFrame.clearTexture();
            this.spriteFrame = null;
        }

        if (this.texture) {
            this.texture.destroy();
        }
    },

OK,至此,绘制排行榜全部完成。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容