排行榜指南
环境要求
- Unity
- Android
- iOS
- UE4
- Unity 2019.4 或更高版本
- iOS 11 或更高版本,Xcode 版本 14.1 或更高版本
- Android 5.0(API level 21)或更高版本
Android 5.0(API level 21)或更高版本
iOS 11 或更高版本,Xcode 版本 14.1 或更高版本
- 安装 UE 4.26 及以上版本
- iOS 12 或更高版本
- Android 5.0(API level 21)或更高版本
支持平台:Android / iOS
权限说明
- Unity
- Android
- iOS
- UE4
该模块需要如下权限:
权限 | 使用目的 | 权限申请时机 |
---|---|---|
网络权限 | 用于访问网络数据 | 用户首次使用该功能时会申请权限 |
该模块将在应用中添加如下权限:
<uses-permission android:name="android.permission.INTERNET" />
集成 前准备
- 参考 准备工作 创建应用、开启内建账户、排行榜服务、绑定 API 域名;
SDK 获取
排行榜功能是数据存储 SDK 的一部分,排行榜 SDK 配置与数据存储 SDK 配置一致;
- Unity
- Android
- iOS
- UE4
SDK 可以通过 Unity Package Manager 导入或手动导入,二者任选其一。请根据项目需要选择。
方法一:使用 Unity Package Manager
在项目的 Packages/manifest.json
文件中添加以下依赖:
"dependencies":{
"com.leancloud.realtime": "https://github.com/leancloud/csharp-sdk-upm.git#realtime-2.3.0",
"com.leancloud.storage": "https://github.com/leancloud/csharp-sdk-upm.git#storage-2.3.0",
}
在 Unity 顶部菜单中选择 Window > Package Manager 可查看已经安装在项目中的包。
方法二:手动导入
-
在 下载页 找到 LeanCloud C# SDK 下载地址,下载
LeanCloud-SDK-Realtime-Unity.zip
。 -
解压后的
LeanCloud-SDK-Realtime-Unity.zip
为 Plugins 文件夹,拖拽至 Unity 即可。
- 打开项目的
project/app/build.gradle
文件,添加 gradle 配置如下:
dependencies {
...
implementation 'com.taptap:lc-storage-android:8.2.24'
}
- 下载 TapSDK UE4,TapSDK-UE4-xxx.zip 解压后将
LeanCloud
文件夹 Copy 到项目的Plugins
目录中 - 重启 Unreal Editor
- 打开 编辑 > 插件 > 项目 > LeanCloud,开启
LeanCloud
模块
添加依赖
在 Project.Build.cs 中添加所需模块:
PublicDependencyModuleNames.AddRange(new string[] { "Core",
"CoreUObject",
"Engine",
"Json",
"InputCore",
"JsonUtilities",
"SlateCore",
});
if (Target.Platform == UnrealTargetPlatform.IOS || Target.Platform == UnrealTargetPlatform.Android)
{
PublicDependencyModuleNames.AddRange(
new string[]
{
"LeanCloudMobile"
}
);
}
else
{
PublicDependencyModuleNames.AddRange(
new string[]
{
"LeanCloud"
}
);
}
导入头文件
#include "LCLeaderboard.h"
SDK 初始化
内建账户 SDK 初始化完成后会同步初始化排行榜功能,因此无需重复初始化;
快速入门
创建排行榜
创建排行榜有 3 种方式:
- 在 TapTap 开发者中心的排行榜控制台创建。
- 在服务端等受信任的环境下调用 REST API 创建。
- 在服务端等受信任的环境下调用 SDK 的管理接口创建。
比如,可以在控制台创建 一个名称为 world
,成员类型为「内建账户」,排序为 descending
,更新策略为 better
,重置周期为「每月」的世界排行榜。
提交成绩
假设玩家已登录(currentUser
),通过如下代码即可更新成绩:
- Unity
- Android
- iOS
- UE4
var statistic = new Dictionary<string, double>();
statistic["world"] = 20.0;
await LCLeaderboard.UpdateStatistics(currentUser, statistic);
Map<String, Double> statistic = new HashMap<>();
statistic.put("world", 20.0);
LCLeaderboard.updateStatistic(currentUser, statistic).subscribe(new Observer<LCStatisticResult>() {
@Override
public void onSubscribe(@NotNull Disposable disposable) {}
@Override
public void onNext(@NotNull LCStatisticResult jsonObject) {
// scores saved
}
@Override
public void onError(@NotNull Throwable throwable) {
// handle error
}
@Override
public void onComplete() {}
});
NSDictionary *statistic = @{
@"world" : 20.0,
};
[LCLeaderboard updateCurrentUserStatistics:statistic, callback:^(NSArray *statistics, NSError *error) {
if (statistics) {
// statistics 是更新后你的最好/最新成绩
} else if (error) {
// 处理错误
}
}];
TMap<FString, double> Statistic;
Statistic.Add("world", 20.0);
FLCLeaderboard::FStatisticsDelegate OnSuccess = FLCLeaderboard::FStatisticsDelegate::CreateLambda([=](TArray<FLCLeaderboardStatistic> Statistics) {
// statistics 是更新后你的最好/最新成绩
});
FLCError::FDelegate OnError = FLCError::FDelegate::CreateLambda([=](const FLCError& Error) {
// 处理错误
});
FLCLeaderboard::UpdateCurrentUserStatistics(Statistic, OnSuccess, OnError);
获取名次
接下来我们获取排行榜中的前十,由于之前我们只提交了一个玩家(当前玩家)的成绩,所以结果中只包含一个成绩。
- Unity
- Android
- iOS
- UE4
var leaderboard = LCLeaderboard.CreateWithoutData("world");
var rankings = await leaderboard.GetResults(limit: 10);
LCLeaderboard leaderboard = LCLeaderboard.createWithoutData("world");
leaderboard.getResults(0, 10, null, null).subscribe(new Observer<LCLeaderboardResult>() {
@Override
public void onSubscribe(@NotNull Disposable disposable) {}
@Override
public void onNext(@NotNull LCLeaderboardResult leaderboardResult) {
List<LCRanking> rankings = leaderboardResult.getResults();
// process rankings
}
@Override
public void onError(@NotNull Throwable throwable) {
// handle error
}
@Override
public void onComplete() {}
});
LCLeaderboard *leaderboard = [[LCLeaderboard alloc] initWithStatisticName:@"world"];
leaderboard.limit = 10;
[leaderboard getUserResultsWithOption:nil callback:^(NSArray *rankings, NSInteger count, NSError *error) {
// rankings 是排行榜前十的排名信息
}];
FLCLeaderboard Leaderboard("world", FLCLeaderboard::User);
Leaderboard.Limit = 10;
FLCLeaderboard::FRankingsDelegate OnSuccess = FLCLeaderboard::FRankingsDelegate::CreateLambda([=](TArray<FLCLeaderboardRanking> Rankings, int64 Count) {
// process rankings
});
FLCError::FDelegate OnError = FLCError::FDelegate::CreateLambda([=](const FLCError& Error) {
// handle error
});
Leaderboard.GetResults(OnSuccess, OnError);
看过上面这个最简单的接入排行榜的例子后,下面就详细介绍排行榜的各个接口。
成绩管理
更新用户成绩
当用户完成了一局游戏后,你可以在客户端使用 SDK 的 updateStatistic
方法更新该用户的成绩。
不过,从反作弊的角度出发,我们建议在控制台勾选「只允许使用 Master Key 更新分数」,然后在服务端更新成绩。
- Unity
- Android
- iOS
- UE4
var statistic = new Dictionary<string, double> {
{ "score", 3458.0 },
{ "kills", 28.0 }
};
await LCLeaderboard.UpdateStatistics(currentUser, statistic);
Map<String, Double> statistic = new HashMap<>();
statistic.put("score", 3458.0);
statistic.put("kills", 28.0);
LCLeaderboard.updateStatistic(currentUser, statistic).subscribe(new Observer<LCStatisticResult>() {
@Override
public void onSubscribe(@NotNull Disposable disposable) {}
@Override
public void onNext(@NotNull LCStatisticResult jsonObject) {
// saved
}
@Override
public void onError(@NotNull Throwable throwable) {
// handle error
}
@Override
public void onComplete() {}
});
NSDictionary *statistic = @{
@"score" : 3458.0,
@"kills" : 28.0,
};
[LCLeaderboard updateCurrentUserStatistics:statistic callback:^(NSArray *statistics, NSError *error) {
if (!error) {
// saved
}
}];
TMap<FString, double> Statistic;
Statistic.Add("score", 3458.0);
Statistic.Add("kills", 28.0);
FLCLeaderboard::FStatisticsDelegate OnSuccess = FLCLeaderboard::FStatisticsDelegate::CreateLambda([=](TArray<FLCLeaderboardStatistic> Statistics) {
// saved
});
FLCError::FDelegate OnError = FLCError::FDelegate::CreateLambda([=](const FLCError& Error) {
// handle error
});
FLCLeaderboard::UpdateCurrentUserStatistics(Statistic, OnSuccess, OnError);
更新用户成绩需要玩家登录,玩家只能更新自己的成绩。
你可以一次性更新多个排行榜的成绩,比如上面的示例中同时更新了得分(score
)和击杀(kills
)两个排行榜的成绩。
客户端无法更新 object 和 entity 的成绩。 如需更新其他用户、object、entity 的成绩,需要使用 REST API 或 SDK 提供的管理接口。
删除用户成绩
玩家也可以删除自己的成绩:
- Unity
- Android
- iOS
- UE4
await LCLeaderboard.DeleteStatistics(currentUser, new List<string> { "world" });
// 暂未支持
[LCLeaderboard deleteCurrentUserStatistics:@[@"world"], callback:^(BOOL succeeded, NSError * _Nullable error) {
if (succeeded) {
// 删除成功
} else if (error) {
// 处理错误
}
}];
// 暂未支持
和更新成绩一样,玩家只能删除自己的成绩。 如需删除其他用户、object、entity 的成绩,需要使用 REST API 或 SDK 提供的管理接口。
查询排行榜成员成绩
已登录用户可以通过 GetStatistics
方法查询其他用户在所有排行榜中的成绩:
- Unity
- Android
- iOS
- UE4
var otherUser = LCObject.CreateWithoutData(TDSUser.CLASS_NAME, "5c76107144d90400536fc88b");
var statistics = await LCLeaderboard.GetStatistics(otherUser);
foreach(var statistic in statistics) {
Debug.Log(statistic.Name);
Debug.Log(statistic.Value);
}
// 查询排行榜成员成绩
LCUser otherUser = null;
try {
otherUser = LCUser.createWithoutData(LCUser.class, "5c76107144d90400536fc88b");
} catch (LCException e) {
e.printStackTrace();
}
LCLeaderboard.getUserStatistics(otherUser).subscribe(new Observer<LCStatisticResult>() {
@Override
public void onSubscribe(@NotNull Disposable disposable) {}
@Override
public void onNext(@NotNull LCStatisticResult lcStatisticResult) {
List<LCStatistic> statistics = lcStatisticResult.getResults();
for (LCStatistic statistic : statistics) {
Log.d(TAG, statistic.getName());
Log.d(TAG, String.valueOf(statistic.getValue()));
}
}
@Override
public void onError(@NotNull Throwable throwable) {
// handle error
Toast.makeText(MainActivity.this, "查询失败: " + throwable.getMessage(), Toast.LENGTH_SHORT).show();
}
@Override
public void onComplete() {}
});
NSString *otherUserObjectId = @"5c76107144d90400536fc88b";
[LCLeaderboard getStatisticsWithUserId:otherUserObjectId, statisticNames:nil, callback:^(NSArray<LCLeaderboardStatistic *> * _Nullable *statistics, NSError _Nullable *error) {
if (statistics) {
for (LCLeaderboardStatistic *statistic in statistics) {
NSLog(@"排行榜名称:%@", statistic.name);
NSLog(@"成绩:%f", statistic.value);
}
} else if (error) {
// 处理错误
}
}];
FLCLeaderboard::FStatisticsDelegate OnSuccess = FLCLeaderboard::FStatisticsDelegate::CreateLambda([=](TArray<FLCLeaderboardStatistic> Statistics) {
for (FLCLeaderboardStatistic Statistic : Statistics) {
// 排行榜名称:Statistic.Name;
// 成绩:Statistic.Value;
}
});
FLCError::FDelegate OnError = FLCError::FDelegate::CreateLambda([=](const FLCError& Error) {
// 处理错误
});
FString OtherUserObjectId = "5c76107144d90400536fc88b";
FLCLeaderboard::GetStatistics(OtherUserObjectId, OnSuccess, OnError, {}, FLCLeaderboard::User);
更多的场景下,只关心用户在某个或某几个排行榜中的成绩。 查询时指定相应排行榜的名称即可:
- Unity
- Android
- iOS
- UE4
var statistics = await LCLeaderboard.GetStatistics(otherUser, new List<string> { "world" });