cocos creator 实现原生微信小游戏排行榜
2019-02-20 本文已影响13人
洒一地阳光_217d
本文以玩家身上钱为例,主要讲述在cocos中,如何使用原生的排行榜,显示好友排行
效果如图:
排行1.png 排行2.png
一、准备工作:
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 heightPerUser = 146; // 单个玩家排行的高度
let widthPerUser = 808; // 单个玩家排行的宽度
wx.onMessage(function (data) {
sharedCanvas = wx.getSharedCanvas();
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 > 8) {
// 仅绘制前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,至此,绘制排行榜全部完成。