> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 排行榜的更多用法

> PlayFab 排行榜高级功能：构建多列排行榜、增强的打破平局、外部实体，以及查询玩家周围的排名。

在本教程中，我们将介绍该服务提供的高级功能，例如创建多列排行榜、增强的打破平局，以及多种查询排行榜的方式。

对于此示例，我们假设您对 [创建基础排行榜](/services/playfab/community/leaderboards/create-basic-leaderboard) 中介绍的所有内容都已熟悉。我们将以一款高度竞技的射击游戏为例，来演示这些新功能如何帮助我们解决一些问题。在此游戏中，有一种称为团队死斗的模式，由两个队伍相互对抗组成。谁先获得 75 次淘汰，谁就是获胜者。现在，此游戏不基于单一分数为玩家进行排名；而是基于淘汰、助攻和死亡数来定义谁是最优秀的。

## 创建多列排行榜定义

要开始此示例，我们需要创建一个比之前更复杂的排行榜定义。我们将定义多列，以映射游戏的关键方面：淘汰、助攻和死亡。以下示例演示了如何使用 C# SDK 创建排行榜定义。

```C# theme={null}
public static async Task CreateLeaderboardDefinitionAsync(PlayFabAuthenticationContext context, string leaderboardName)
{
    PlayFabProgressionInstanceAPI leaderboardsAPI = new PlayFabProgressionInstanceAPI(context);
    CreateLeaderboardDefinitionRequest leaderboardDefinitionRequest = new CreateLeaderboardDefinitionRequest()
    {
        AuthenticationContext = context,
        Name = leaderboardName,
        SizeLimit = 1000,
        EntityType = "title_player_account",
        VersionConfiguration = new VersionConfiguration()
        {
            MaxQueryableVersions = 1,
            ResetInterval = ResetInterval.Manual,
        },
        Columns = new List<LeaderboardColumn>()
        {
            new LeaderboardColumn()
            {
                Name = "Eliminations",
                SortDirection = LeaderboardSortDirection.Descending,
            },
            new LeaderboardColumn()
            {
                Name = "Assists",
                SortDirection = LeaderboardSortDirection.Descending,
            }
            new LeaderboardColumn()
            {
                Name = "Deaths",
                SortDirection = LeaderboardSortDirection.Ascending,
            }         
        }
    };

    PlayFabResult<PlayFab.LeaderboardsModels.EmptyResponse> createLbDefinitionResult = await leaderboardsAPI.CreateLeaderboardDefinitionAsync(leaderboardDefinitionRequest);
}
```

现在，让我们解释此示例中的一些关键元素：

* `SizeLimit`：此参数用于限制排行榜可以包含的行数。此处的值只是一个示例。
* `VersionConfiguration`：此参数允许我们对排行榜进行版本控制。有关更多信息，请参见此页面：[赛季排行榜](/services/playfab/community/leaderboards/seasonal-leaderboards)
* `Columns`：此参数允许我们定义多个列，每个定义最多 5 列。如您所见，我们设置了 Eliminations、Assists 和 Deaths。此处的一个重要元素是 `SortDirection` 参数，它允许我们确定排行榜的排序方式。在此示例中，玩家如果有更多的淘汰和助攻（SortDirection = Descending）并且死亡次数较少（SortDirection = Ascending），则排名更高。

有关其他参数或如何管理排行榜定义的更多信息，请参见 [创建基础排行榜](/services/playfab/community/leaderboards/create-basic-leaderboard)。

## 引入外部实体

排行榜服务可以作为独立组件使用，支持引入仅在游戏上下文中才有意义的外部实体。如果您的玩家身份与 PlayFab 登录未绑定，您仍然可以使用排行榜服务。PlayFab 系统之外的排行榜条目实体类型必须为 *external*。此时 entityId 就是您系统中玩家的身份。在这些情况下，排行榜上的*所有*条目都必须是 *external* 实体。

## 向排行榜添加数据

现在排行榜已经创建，我们将添加数据。与本主题之前的教程的主要区别在于，现在我们需要在同一行中添加三个不同的分数。以下示例演示了如何使用 C# SDK 向我们的排行榜添加数据。

```C# theme={null}
public static async Task UpdateLeaderboardForPlayer(PlayFabAuthenticationContext context, string leaderboardName, string entityId, int score)
{
    PlayFabProgressionInstanceAPI leaderboardsAPI = new PlayFabProgressionInstanceAPI(context);
    UpdateLeaderboardEntriesRequest updateLeaderboardRequest = new UpdateLeaderboardEntriesRequest()
    {
        Entries = new List<LeaderboardEntryUpdate>()
        {
            new LeaderboardEntryUpdate()
            {
                EntityId = entityId,
                Scores = new List<string> { score.ToString(), (score + 1).ToString(), (score + 2).ToString() },
                Metadata = "metadata",
            }
        },
        AuthenticationContext = context,
        LeaderboardName = leaderboardName,
    };

    PlayFabResult<PlayFab.LeaderboardsModels.EmptyResponse> updateResult = await leaderboardsAPI.UpdateLeaderboardEntriesAsync(updateLeaderboardRequest);
}
```

需要注意的一件重要事情是 Scores 参数提供了三个值。为任何条目指定的分数列表长度必须与排行榜定义的列数相匹配。每个值必须是有效的 64 位整数（字符串表示形式只是为了确保所有客户端都可以处理 64 位值）。

## 从排行榜检索数据

现在我们将学习查询排行榜的不同方式。它们都有特定的目的，旨在帮助开发者获取所需的玩家，以便在游戏中显示。

### 获取实体周围排行榜

这种特定的排行榜查询方式让我们能够获取靠近特定实体的一段排行榜。此场景的一个实用示例是，当我们有一个巨大的排行榜，而我们只想向当前游戏中活跃的玩家显示相关信息时。如果玩家排名第 1000 位，我们可以显示附近的邻居，而不是排名靠前的玩家。以下示例演示了如何使用 C# SDK 查询实体周围的排行榜。

```C# theme={null}
public static async Task<List<EntityLeaderboardEntry>> GetLeaderboardAroundEntity(PlayFabAuthenticationContext context, string leaderboardName, string entityId)
{
    PlayFabProgressionInstanceAPI leaderboardsAPI = new PlayFabProgressionInstanceAPI(context);
    GetLeaderboardAroundEntityRequest getLbRequest = new GetLeaderboardAroundEntityRequest()
    {
        LeaderboardName = leaderboardName,
        AuthenticationContext = context,
        Entity = new PlayFab.LeaderboardsModels.EntityKey()
        {
            Id = entityId,
            Type = EntityType
        },
        MaxSurroundingEntries = 20,
    };

    PlayFabResult<GetEntityLeaderboardResponse> lbResponse = await leaderboardsAPI.GetLeaderboardAroundEntityAsync(getLbRequest);
    
    return lbResponse.Result.Rankings;

}
```

此处最重要的元素是 `MaxSurroundingEntries`，它允许我们从排行榜中提取排名在特定实体周围的实体。例如，如果我们有一个位于第 100 位的玩家，并使用 `MaxSurroundingEntries` = 20，那么它将检索从第 90 位到第 110 位的玩家。如果玩家位于排行榜顶部，它将检索排名靠前的 20 个结果。如果玩家位于底部，它将检索最后 20 个结果。除排行榜的顶部和底部的位置外，API 会尽量确保请求排名的实体位于所检索位置的中心。

### 获取实体的排行榜

此 API 为我们提供了另一种查询排行榜的方式。当我们希望在排行榜中搜索多个实体并对它们进行排序时，它会起作用。以下示例演示了如何使用 C# SDK 为实体列表查询排行榜。

```C# theme={null}
public static async Task<List<EntityLeaderboardEntry>> GetLeaderboardForEntities(PlayFabAuthenticationContext context, string leaderboardName, List<string> entityIds)
{
    PlayFabProgressionInstanceAPI leaderboardsAPI = new PlayFabProgressionInstanceAPI(context);
    GetLeaderboardForEntitiesRequest getLbRequest = new GetLeaderboardForEntitiesRequest()
    {
        LeaderboardName = leaderboardName,
        AuthenticationContext = context,
        EntityIds = entityIds,
    };

    PlayFabResult<GetEntityLeaderboardResponse> lbResponse = await leaderboardsAPI.GetLeaderboardForEntitiesAsync(getLbRequest);

    return lbResponse.Result.Rankings;
}
```

### 获取好友排行榜

在某些情况下，一些休闲玩家来体验游戏。他们可能远离排行榜的顶部，但在他们的朋友之间，他们正在进行一场比赛。有了此 API，我们可以查询排行榜并找到该玩家的好友。

```C# theme={null}
public static async Task<List<EntityLeaderboardEntry>> GetFriendLeaderboardForEntity(PlayFabAuthenticationContext context, string leaderboardName, string entityId)
{
    PlayFabProgressionInstanceAPI leaderboardsAPI = new PlayFabProgressionInstanceAPI(context);
    GetFriendLeaderboardForEntityRequest getLbRequest = new GetFriendLeaderboardForEntityRequest()
    {
       LeaderboardName = leaderboardName,
       Entity = new PlayFab.LeaderboardsModels.EntityKey()
       {
           Id = entityId,
           Type = EntityType
       },
    };

    PlayFabResult<GetEntityLeaderboardResponse> lbResponse = await leaderboardsAPI.GetFriendLeaderboardForEntityAsync(getLbRequest);
  
    return lbResponse.Result.Rankings;
}
```

有多种方式可以从 PlayFab 服务获取好友。有关可用参数的更多信息，请参见 [API 参考](/services/playfab/community/leaderboards/api-reference)。

### 增强的打破平局

考虑到我们高度竞技的射击游戏示例，可能会有多个玩家淘汰数相同的情况。对于这些场景，我们需要有一种不同的方式来对这些情况进行打破平局。此场景就是增强的打破平局功能发挥作用的地方。

创建排行榜定义时，可以有多个列。您添加它们的方式决定了我们将如何对某些场景进行排序和打破平局。存在优先级顺序，其中添加的第一列最重要，然后是第二列，依此类推。此场景转换到我们的示例中，就是当淘汰数出现平局时，第二个标准是助攻数，最后一个标准是死亡数。在平局仍然存在的极端情况下，则默认使用时间戳，先达到分数的人排名更高。

\| 排名     | 实体 ID                         | Eliminations|  Assists        | Deaths | LastUpdated\
\|----------------------|------------------------------------|-------------------|--------------------------
|1 | "player 3" | 103               |24 | 15|"2024-08-27T20:24:36.738Z"
|2 | "player 2" | 102               | 30| 20 |"2024-08-27T20:24:29.251Z"
|3 | **"player 1"** | 100               | 25 |18 |"2024-08-27T19:52:26.642Z"\
|4 | **"player 4"** | 100               | 25 | 18 |"2024-08-27T20:24:44.552Z"
|4 | **"player 5"** | 100               | 25 | 19 |"2024-08-27T20:25:47.552Z"

在此示例中，三名玩家出现了平局：

* “player 5”：尽管淘汰数和助攻数相同，但他们的死亡数更多，这意味着他们位于排行榜的底部。
* “player 4”：此玩家的死亡数少于“player 5”，与“player 1”相同，但 player 1 先获得了这些数字。
* “player 1”：尽管数字与“player 4”相同，但此玩家是游戏中首个达到这一分数的人，因此在此打破平局的场景中，他们排名更高。

## 结论

在本教程中，我们学习了如何执行以下操作：

* 创建多列排行榜。
* 检查多种查询方式。
* 了解增强的打破平局机制。

## 另请参阅

* [创建基础排行榜](/services/playfab/community/leaderboards/create-basic-leaderboard)。
* [赛季排行榜](/services/playfab/community/leaderboards/seasonal-leaderboards)。
* [限制](/services/playfab/community/leaderboards/limits-leaderboards)。
* [配额](/services/playfab/community/leaderboards/quota-leaderboards)。
* [根据统计信息为玩家排名](/services/playfab/community/leaderboards/leaderboards-linked-to-stats)。
* [组排行榜](/services/playfab/community/leaderboards/group-leaderboards)。
* [手动等级](/services/playfab/community/leaderboards/manual-tiers)。
* [向排行榜添加额外数据](/services/playfab/community/leaderboards/metadata-leaderboards)。
* [API 参考](/services/playfab/community/leaderboards/api-reference)。
* [排行榜和 Cloudscript](/services/playfab/community/leaderboards/leaderboards-cloudscript)。
* [使用 Playstream 的排行榜](/services/playfab/community/leaderboards/leaderboards-with-playstream-and-telemetry)


## Related topics

- [组排行榜](/zh-CN/services/playfab/community/leaderboards/group-leaderboards.md)
- [排行榜的限制](/zh-CN/services/playfab/community/leaderboards/limits-leaderboards.md)
- [API 排行榜参考](/zh-CN/services/playfab/community/leaderboards/api-reference.md)
- [排行榜配额](/zh-CN/services/playfab/community/leaderboards/quota-leaderboards.md)
- [季节性排行榜](/zh-CN/services/playfab/community/leaderboards/seasonal-leaderboards.md)
