排行榜
# 我们设置了比赛、好友、部落和存储数据的方法。我们来将其整合到一起,显示顶尖玩家的排行榜 ,促进竞争。
排行榜
设置排行榜
# 对于想要创建的每个排行榜,我们运行 leaderboardCreate
。此函数有多个参数:
ID/名称 排行榜是否为权威的布尔值(如为是,则仅有服务器可以更新排行榜) 排序(SortOrder.ASCENDING
或 SortOrder.DESCENDING
) 对分数求和的运算符Operator.BEST
:始终取提交的最好分数Operator.SET
:始终取提交的最新分数Operator.INCR
:将提交的分数添加到总分 重置时间表,其为 CRON 表达式 或从不重置的排行榜的 null
要存储到排行榜中的元数据 对于 Pirate Panic,我们设置一个全局排行榜,显示所有玩家所有时候的最高分数:
main.ts
1
2
3
4
5
6
7
const id = "global_leaderboard" ;
const authoritative = false ;
const metadata = {};
const scoreOperator = nkruntime . Operator . BEST ;
const sortOrder = nkruntime . SortOrder . DESCENDING ;
const resetSchedule = null ;
nk . leaderboardCreate ( id , authoritative , sortOrder , scoreOperator , resetSchedule , metadata );
选择排行榜可以接受新的记录。
向排行榜添加
# 每场比赛结束后,我们将把玩家分数记录到排行榜上。每当比赛结束时,客户端都会向服务器发送 RPC 请求以处理游戏结束行为:
match.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
interface MatchEndRequest { // Create a structure to align the payload to
matchId : string ;
placement : MatchEndPlacement ;
time : number ;
towersDestroyed : number ;
}
const rpcHandleMatchEnd : nkruntime.RpcFunction = function ( ctx : nkruntime.Context , logger : nkruntime.Logger , nk : nkruntime.Nakama , payload : string ) : string {
... // Add gems to wallet, calculate score, etc. etc.
let request : MatchEndRequest = JSON . parse ( payload );
let score = calculateScore ( request . placement == MatchEndPlacement . Winner , request . towersDestroyed , request . time );
nk . leaderboardRecordWrite ( globalLeaderboard , ctx . userId , ctx . username , score );
...
}
如何计算分数取决于您和游戏机制。您可以考虑谁赢了,花了多长时间才赢了,或者他们像我们在这个例子中一样摧毁了多少座塔。所有这些信息都从客户端传递到有效载荷中。
一旦计算出分数,我们将其作为一个数字与用户 ID 和用户名一起传递到 leaderboardRecordWrite
,然后排行榜引擎将进行后续处理。
此外,还可以使用 WriteLeaderboardRecordAsync 在 Unity 端达到这个目的。
列出排行榜记录
# 现在已为处理新的排行榜记录设置好服务器,让我们为玩家提供一种查看服务器上存储的内容的方式。这在客户端使用 ListLeaderboardRecordsAsync
完成:
LeaderboardsMenuUI.cs
1
2
3
4
5
6
7
8
9
10
[SerializeField] private int _recordsPerPage = 100 ;
...
public async void ShowGlobalLeaderboards ( string cursor = null )
{
// Fetch all records from the leaderboard "global"
IApiLeaderboardRecordList records = await _connection . Client . ListLeaderboardRecordsAsync ( _connection . Session , "global" , ownerIds : null , expiry : null , _recordsPerPage , cursor );
SetLeaderboardsCursor ( records , ShowGlobalLeaderboards );
...
}
对于上述示例,SetLeaderboardsCursor
会形如:
LeaderboardsMenuUI.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private void SetLeaderboardsCursor ( IApiLeaderboardRecordList records , Action < string > caller )
{
if ( records . PrevCursor != null ) {
_prevPageButton . interactable = true ;
_prevPageButton . onClick . RemoveAllListeners ();
_prevPageButton . onClick . AddListener (() => caller ( records . PrevCursor ));
} else {
_prevPageButton . interactable = false ;
}
if ( records . NextCursor != null ) {
_nextPageButton . interactable = true ;
_nextPageButton . onClick . RemoveAllListeners ();
_nextPageButton . onClick . AddListener (() => caller ( records . NextCursor ));
} else {
_nextPageButton . interactable = false ;
}
}
ListLeaderboardRecordsAsync
返回的 records
列表带有两个函数,PrevCursor
和 NextCursor
,每个都抓取上一页或下一页记录(如果存在这一页)。
通过将这些功能绑定到按钮,我们可以让玩家轻松浏览记录。PrevCursor
和 NextCursor
都将遵守在原始 ListLeaderboardRecordsAsync
调用中设置的每页记录数,并将更新 records
对象,以保留下一页记录。
为实际显示这些记录,可以在 records
中的每条记录上使用 foreach
循环:
LeaderboardsMenuUI.cs
1
2
3
4
5
6
7
8
9
foreach ( IApiLeaderboardRecord record in records )
{
string username = record . Username ;
if ( localId == record . OwnerId )
{
username += " (You)" ;
}
...
}
每个 record
保留一个 Username
、OwnerId
、Score
,以及存储在可选数据库中的任何其他自定义字段。
过滤排行榜
# 我们还可以过滤出全局排行榜,看看我们的好友或部落的表现如何。
在前一部分,我们以 null
退出 ownerIds
,因为我们想要获取所有条目。现在,我们可以使用此参数仅获取具有特定所有者的条目。
例如,我们可以使用 ListFriendsAsync
获取所有好友:
1
var friends = await _connection . Client . ListFriendsAsync ( _connection . Session );
然后,我们可以提取他们的所有用户 ID 并将其存储到列表中:
1
List < string > ids = friends . Friends . Select ( x => x . User . Id ). ToList ();
最后,我们将 ids
列表传入过滤器,在 records
中将仅显示此列表中的用户:
1
IApiLeaderboardRecordList records = await _connection . Client . ListLeaderboardRecordsAsync ( _connection . Session , "global" , ids , null , 1 , cursor );
在这里,我们从同一排行榜 (global
) 获取记录,并将 ids
作为 ownerIds
,并将每页记录数设置为 1
。
可以执行一个非常类似的过程,对排行榜进行过滤,以仅显示您的部落的成员的分数:
1
2
3
4
var users = await _connection . Client . ListGroupUsersAsync ( _connection . Session , _userClan . Group . Id , null , 1 , null );
IEnumerable < string > ids = users . GroupUsers . Select ( x => x . User . Id );
IApiLeaderboardRecordList list = await _connection . Client . ListLeaderboardRecordsAsync ( _connection . Session , "global" , ids , null , 1 , cursor );
下一主题
# 通知
Related Pages