前言
对于一个微信小游戏来说,好友排行榜绝对是必不可少的功能,能一定程度上增加玩家的战斗力和活跃度,实实在在地增加小游戏的曝光量。
这篇文章皮皮将讲解如何给小游戏项目加入微信好友排行榜功能~
不吹不黑,这绝对是新手开发者的福音!不接受任何反驳!
前排提示:文章中的排行榜子域项目已经上传至我的开源主页,甚至改都不用改,接上项目就能用,点击文章底部阅读原文即可获取完整项目~
正文
微信开放数据域
1. 要让小游戏接入微信好友排行榜功能,我们必须先了解下什么是开放数据域,来看看 Cocos 官方文档中的解释:
2. 也就是说,我们的小游戏项目想要加入好友排行榜功能,就需要单独再创建一个子项目专门用来展示好友排行榜,并且只有在子项目中才可以调用微信提供的数据操作 API 。
主域(主项目)
const { ccclass, property } = cc._decorator;
@ccclass
export default class RankPanel extends cc.Component {
@property(cc.Node)
private main: cc.Node = null;
@property(cc.Node)
private closeBtnNode: cc.Node = null;
private static instance: RankPanel = null;
protected onLoad() {
RankPanel.instance = this;
this.closeBtnNode.on('touchend', RankPanel.hide, this);
}
protected onDestroy() {
this.closeBtnNode.off('touchend', RankPanel.hide, this);
}
public static show() {
this.instance.main.active = true;
this.getRank();
}
public static hide() {
this.instance.main.active = false;
}
/**
* 设置用户的分数
* @param value
*/
public static setScore(value: number) {
wx.postMessage({
event: 'setScore',
score: value
});
}
/**
* 获取排行榜
*/
public static getRank() {
wx.postMessage({
event: 'getRank'
});
}
}
子域(子项目)
const { ccclass, property } = cc._decorator;
@ccclass
export default class RankItem extends cc.Component {
@property(cc.Label)
private rankingLabel: cc.Label = null;
@property(cc.Sprite)
private avatarSprite: cc.Sprite = null;
@property(cc.Label)
private nicknameLabel: cc.Label = null;
@property(cc.Label)
private scoreLabel: cc.Label = null;
/**
* 设置展示的信息
* @param ranking 排名
* @param user 用户数据
*/
public set(ranking: number, user: UserGameData) {
this.rankingLabel.string = ranking.toString();
this.nicknameLabel.string = user.nickname;
this.scoreLabel.string = user.KVDataList[0].value.toString();
this.updateAvatar(user.avatarUrl);
}
/**
* 更新头像
* @param url 头像链接
*/
private updateAvatar(url: string) {
let image = wx.createImage();
image.onload = () => {
let texture = new cc.Texture2D();
texture.initWithElement(image);
texture.handleLoadedTexture();
this.avatarSprite.spriteFrame = new cc.SpriteFrame(texture);
};
image.src = url;
}
}
import RankItem from "./RankItem";
const { ccclass, property } = cc._decorator;
@ccclass
export default class Rank extends cc.Component {
@property(cc.Node)
private content: cc.Node = null;
@property(cc.Prefab)
private itemPrefab: cc.Prefab = null;
@property(cc.Node)
private loading: cc.Node = null;
protected onLoad() {
if (cc.sys.platform !== cc.sys.WECHAT_GAME_SUB) return;
// 监听来自主域的消息
wx.onMessage((msg: any) => this.onMessage(msg));
}
/**
* 消息回调
* @param msg 消息
*/
private onMessage(msg: any) {
switch (msg.event) {
case 'setScore':
this.setScore(msg.score);
break;
case 'getRank':
this.getRank();
break;
}
}
/**
* 获取玩家分数
*/
private getScore(): Promise<number> {
return new Promise(resolve => {
console.log('[getScore]');
wx.getUserCloudStorage({
keyList: ['score'],
success: (res: UserGameData) => {
console.log('[getScore]', 'success', res);
resolve(res.KVDataList[0] ? parseInt(res.KVDataList[0].value) : 0);
},
fail: () => {
console.log('[getScore]', 'fail');
resolve(-1);
}
});
});
}
/**
* 设置玩家分数
* @param value 分数
*/
private async setScore(value: number) {
console.log('[setScore]', value);
let oldScore = await this.getScore();
if (oldScore === -1) return;
if (value > oldScore) {
wx.setUserCloudStorage({
KVDataList: [{
key: 'score',
value: value.toString()
}],
success: () => {
console.log('[setScore]', 'success');
},
fail: () => {
console.log('[setScore]', 'fail');
}
});
}
}
/**
* 获取排行榜
*/
private async getRank() {
console.log('[getRank]');
// 显示加载动画
this.showLoading();
// 调用微信的函数
await new Promise(resolve => {
wx.getFriendCloudStorage({
keyList: ['score'],
success: (res: any) => {
console.log('[getRank]', 'success', res);
// 对数据进行排序
res.data.sort((a: UserGameData, b: UserGameData) => {
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;
return parseInt(b.KVDataList[0].value) - parseInt(a.KVDataList[0].value);
});
// 排序之后进行展示
this.updateRankList(res.data);
resolve();
},
fail: (res: any) => {
console.log('[getRank]', 'fail');
resolve();
}
});
});
// 关闭加载动画
this.hideLoading();
}
/**
* 更新好友排行
* @param data 数据
*/
private updateRankList(data: UserGameData[]) {
let count = Math.max(data.length, this.content.childrenCount);
for (let i = 0; i < count; i++) {
if (data[i] && this.content.children[i]) {
// 已存在节点,更新并展示
this.content.children[i].active = true;
this.content.children[i].getComponent(RankItem).set(i + 1, data[i]);
} else if (data[i] && !this.content.children[i]) {
// 节点不足,再实例化一个,更新信息
let node = cc.instantiate(this.itemPrefab);
node.setParent(this.content);
node.getComponent(RankItem).set(i + 1, data[i]);
} else {
// 节点多了,关掉吧
this.content.children[i].active = false;
}
}
}
/**
* 显示加载动画
*/
private showLoading() {
this.loading.active = true;
}
/**
* 关闭加载动画
*/
private hideLoading() {
this.loading.active = false;
}
}
打包运行
★ 梅开二度:文章的排行榜子域项目已经上传至我的开源主页,甚至改都不用改,接上项目就能用。https://gitee.com/ifaswind/wxsubcontext
补充
// 以下为 wx.d.ts 文件的内容
/**
* 微信的命名空间
*/
declare namespace wx {
/**
* 打开另一个小程序。
*/
export function navigateToMiniProgram(object: object): void;
/**
* 提前向用户发起授权请求。调用后会立刻弹窗询问用户是否同意授权小程序使用某项功能或获取用户的某些数据,但不会实际调用对应接口。如果用户之前已经同意授权,则不会出现弹窗,直接返回成功。
*/
export function authorize(object: object): void;
/**
* 获取用户信息。
*/
export function getUserInfo(object: object): void;
/**
* 向开放数据域发送消息。
*/
export function postMessage(object: object): void;
/**
* 监听主域发送的消息。
*/
export function onMessage(callback: Function): void;
/**
* 对用户托管数据进行写数据操作。允许同时写多组 KV 数据。
*/
export function setUserCloudStorage(object: object): void;
/**
* 获取当前用户托管数据当中对应 key 的数据。该接口只可在开放数据域下使用。
*/
export function getUserCloudStorage(object: object): void;
/**
* 删除用户托管数据当中对应 key 的数据。
*/
export function removeUserCloudStorage(object: object): void;
/**
* 监听成功修改好友的互动型托管数据事件,该接口在游戏主域使用。
*/
export function onInteractiveStorageModified(callback: Function): void;
/**
* 修改好友的互动型托管数据,该接口只可在开放数据域下使用。
*/
export function modifyFriendInteractiveStorage(object: object): void;
/**
* 获取当前用户互动型托管数据对应 key 的数据。
*/
export function getUserInteractiveStorage(object: object): void;
/**
* 获取可能对游戏感兴趣的未注册的好友名单。每次调用最多可获得 5 个好友,此接口只能在开放数据域中使用。
*/
export function getPotentialFriendList(object: object): void;
/**
* 获取群信息。小游戏通过群分享卡片打开的情况下才可以调用。该接口只可在开放数据域下使用。
*/
export function getGroupInfo(object: object): void;
/**
* 获取群同玩成员的游戏数据。小游戏通过群分享卡片打开的情况下才可以调用。该接口只可在开放数据域下使用。
*/
export function getGroupCloudStorage(object: object): void;
/**
* 拉取当前用户所有同玩好友的托管数据。该接口只可在开放数据域下使用。
*/
export function getFriendCloudStorage(object: object): void;
/**
* 给指定的好友分享游戏信息,该接口只可在开放数据域下使用。接收者打开之后,可以用 wx.modifyFriendInteractiveStorage 传入参数 quiet=true 发起一次无需弹框确认的好友互动。
*/
export function shareMessageToFriend(object: object): void;
/**
* 获取主域和开放数据域共享的 sharedCanvas。只有开放数据域能调用。
*/
export function getSharedCanvas(): any;
/**
* 获取开放数据域。
*/
export function getOpenDataContext(): any;
/**
* 创建一个图片对象。
*/
export function createImage(): any;
}
/**
* 托管数据
*/
declare type UserGameData = {
avatarUrl: string;
nickname: string;
openid: string;
KVDataList: KVData[];
}
/**
* 托管的 KV 数据
*/
declare type KVData = {
key: string;
value: string;
}
/**
* 用户信息
*/
declare type FriendInfo = {
avatarUrl: string;
nickname: string;
openid: string;
}
结束语
以上皆为陈皮皮的个人观点,小生不才,文采不佳,如果写得不好还请各位多多包涵。如果有哪些地方说的不对,还请各位指出,希望与大家共同进步。