开发

Meta Quest 应用排行榜

更新时间: 2024年10月23日
Notice of feature support change
玩家成绩应用自 2024 年 12 月 20 日起已正式停用。此更改不会破坏使用排行榜 API 的现有应用。
This is a Platform SDK feature requiring Data Use Checkup
使用此功能或任何其他平台 SDK 功能之前,您需要完成数据使用情况检查 (DUC)。DUC 可确保您遵守开发者政策。这需要您团队的管理员证明您对用户数据的使用符合平台守则。在应用审核团队审核并批准您的 DUC 之前,平台功能仅供测试用户使用。
Apps for children can't use Platform SDK features
如果您自我证明您的应用主要用于未满 13 岁的儿童,则必须避免使用平台 SDK 功能。这一限制确保遵守特定于年龄的守则。为确保合规性,已为您的应用禁用数据使用情况检查。
排行榜为游戏提供了一种追踪玩家及其相对于其他玩家的分数的方法。排行榜有助于营造竞争氛围,增加用户之间的互动。
例如,在赛车游戏中,对于特定赛道,您可能有一个最快单圈时间的排行榜(按最短时间排序)和一个获胜次数最多的排行榜(按最大值排序)。一个游戏可能有多个排行榜。
Meta Horizon 平台会管理排行榜数据,然而,您要负责在应用中展示、报告和验证排行榜数据。有关在您的应用中添加排行榜的步骤,请参阅“实现”部分
User Data Warning
避免使用任何个人身份识别信息。
注意:任何人都可以检索排行榜元数据。在创建或更新排行榜时,避免存储敏感信息。
您可以选择向用户开放排行榜,这意味着用户可以在 Meta Quest 应用中看到他们相对于好友和其他用户的排名。您还可以选择在用户超过好友的排行榜分数时自动生成通知。
下图显示的是面向用户的排行榜。
user facing leaderboard

在开发者面板上创建排行榜

将排行榜添加到您的游戏中的第一步是在开发者面板中定义排行榜。为此,请按照以下步骤操作。
  1. 前往 Meta Horizon 开发者面板
  2. 选择您的应用。
  3. 在左侧导航中,点击互动 > 排行榜
  4. 选择创建排行榜并输入以下信息:
    • API 名称 - 用于在应用代码中引用该排行榜的唯一标识符字符串。API 名称区分大小写,您在开发者面板中定义的名称必须与代码中的引用名称完全一致。
    • 使用语言下拉菜单对您的标题进行本地化。您必须为所选的每种语言输入本地化字符串。
    • 为您的排行榜输入一个标题,该标题将公开显示。
    • 排序顺序 - 根据您的用例,排序顺序有两个选项:
      • 由高到低将按得分从最高到最低的降序对用户进行排名。
      • 由低到高将按得分从最低到最高的升序对用户进行排名。
    • 选择条目写入策略来确定如何提交条目。
      • 客户端权威 - 可以从客户端或服务器提交条目。这允许在客户端使用访问口令进行更新,并且可以通过 POST 请求进行更新。
      • 服务器权威 - 只能从服务器提交条目。这是更安全的方法,因为它使用应用访问口令来更新条目。
    • 选择一个分数类型来确定分数在排行榜上的显示方式。这需要一个原始分数,并将其整理为以下的格式,以 1000 为例。
      • 距离(单位:英尺)- 1000 英尺
      • 距离(单位:米)- 1000 米
      • 百分比 - 1000%
      • 积分 - 1000
      • 时间(单位:毫秒)- 00:00:01.000
      • 时间(单位:秒)- 00:16:40 秒
    • 最后,要启用排行榜的社交功能,请使用滑块进行选择。您可以:
    • 添加一个深度链接目标位置,这意味着当用户点击排行榜时,他们将被带到您指定的应用内部目标位置。有关目标位置的更多信息,参阅目标位置小组状态
    • 选择让排行榜面向用户,这意味着拥有您的应用的用户可以在 Meta Quest 应用的排行榜上看到他们的排名。
    • 如果排行榜是面向用户的,您还可以选择使用好友超过通知。这意味着当好友超过他们的分数时,Meta Quest 会向用户发送通知。
  5. 完成后,选择提交来保存排行榜。
    您可以在开发者面板中随时更新排行榜设置。您还可以清除排行榜中的结果并重置分数。

排行榜最佳实践

为了增加与您的排行榜的互动,请遵循以下最佳实践:
  • 除了 API 名称之外,还为排行榜设置一个方便用户的显示标题。
  • 为了开拓更广阔的市场,请为您的显示标题提供翻译。
  • 如果您想让 Meta Quest 为这个排行榜提供通知和社交故事,请通过检查排行榜页面上的切换开关,确保您的排行榜是公开的。
  • 为排行榜创建一个目标位置,并将其与您的排行榜相关联。如果您提供了一个目标位置,您可以将用户直接深度链接到您的应用的正确级别,跳到行动中并挑战他们刚刚在平台级别看到的好友的排行榜分数。

编辑排行榜

除 API 名称外,您可以编辑排行榜的所有其他属性。这意味着您可以在创建排行榜后添加翻译和社交功能。如要编辑排行榜,请执行以下操作:
  • 前往 Meta Horizon 开发者面板> 选择 [您的应用] > 选择左侧面板中的“开发”> “所有平台服务”> “排行榜”
  • 点击您想要编辑的排行榜右侧的省略号 (…) 按钮,并选择查看/编辑提交信息
  • 进行所需的更改,例如添加语言和本地化标题或启用社交功能。
  • 点击提交以保存更改。

排行榜客户端 API

在面板中成功创建排行榜后,您就可以开始将它们集成到您的游戏或应用中。调用本节中的函数时,请使用您在开发者面板中定义的排行榜 API 名称
排行榜由多条排行榜条目组成,每个条目代表单个用户在该排行榜中的分数与排名。
有关以下每个功能的详细信息,请参阅排行榜请求参考

检索排行榜

此方法检索指定的排行榜。
Platform.Leaderboards.Get()
如果没有产生错误,结果将包含一个带有排行榜的数组。

检索排行榜条目列表

这种方法检索指定排行榜的排行榜条目数组。
Platform.Leaderboards.GetEntries()
如果没有产生错误,返回结果将包含排行榜条目数组。

检索排名后的排行榜条目列表

这种方法检索从您定义的排名后开始的条目列表。例如,如果您指定一个 "afterRank" 为 10 的列表,您会得到一个从第 11 位开始的列表。
Platform.Leaderboards.GetEntriesAfterRank()
如果没有产生错误,结果将包含您指定的排名之后的排行榜条目数组。

检索下一个条目列表

这个方法检索下一组排行榜条目。此方法可以用于对排行榜数据进行分页。
Platform.Leaderboards.GetNextEntries()
如果没有产生错误,消息将包含一个排行榜条目数组。

检索上一个条目列表

这个方法检索上一组排行榜条目。此方法可以用于对排行榜数据进行分页。
Platform.Leaderboards.GetPreviousEntries()
如果没有产生错误,返回结果将包含排行榜条目数组。

编写一个排行榜条目

这个方法将向当前用户的指定排行榜写入一个新的排行榜条目。它不是增量更新,而是将覆盖现有条目。
Platform.Leaderboards.WriteEntry()
如果没有产生错误,结果将包含一个排行榜状态。

获取排行榜条目的总数

调用此方法可获取排行榜的总条目数,从而显示用户在榜单中的整体排名。例如,使用这个方法显示用户是 200 个条目中的第 50 个。
Platform.Models.LeaderboardEntryList.TotalCount()
返回一个无符号长整型值,用来指定排行榜条目的总数。

获取指定用户的排行榜条目块

请求指定用户 ID 的排行榜条目块以供此客户端查看。使用这个方法获取相互竞争的用户的排名。您可以指定排行榜名称以及是否从顶部开始,或者以(客户端)用户为中心显示结果。请注意,如果您将结果指定为以客户端用户为中心,则无论其 ID 是否在 ID 列表中明确指定,其排行榜条目都将包含在返回的数组中。
Platform.Leaderboards.GetEntriesByIds()
如果没有产生错误,返回结果将包含排行榜条目数组。

实施排行榜

要实施排行榜,有两个不同的流程。
  • 检索和显示排行榜 - 在游戏开始前显示当前的排行榜状态。在 Unity 中使用 Platform.Leaderboards.GetEntries()。您还可以使用其他方法根据输入条件获得排行榜条目的子集。
  • 更新排行榜条目 - 将当前游戏的结果写入您的排行榜。在 Unity 应用中使用 Platform.Leaderboards.WriteEntry()。一个用户在每个排行榜上只能有一个条目,后续条目将覆盖指定排行榜上的现有条目。

实施技巧

在实施排行榜时,您需要注意两种常见情况。这两种情况是:
  • 要检索以当前用户为中心的排行榜条目,请使用 LeaderboardStartAt 枚举来定义返回值的开始位置或中心位置。要仅检索当前用户,请以查看者为中心,并将返回的结果限制为 1。
  • 要仅返回用户的好友,您可以使用 LeaderboardFilterType 枚举来定义返回的结果。
示例实施 - Unity
以下 Unity 示例演示了如何从名为 'MOST_MATCHES_WON' 的排行榜中检索信息,并在当前用户获胜后编写一个新的排行榜条目。以下示例取自 VRHoops 应用示例。请参阅 NPM 注册表中的平台示例包中的完整示例。有关示例的更多信息,请参阅示例应用页面。
using UnityEngine;
using Oculus.Platform;
using Oculus.Platform.Models;

// Coordinates updating leaderboard scores and polling for leaderboard updates.
public class LeaderboardManager : MonoBehaviour
{
    // API NAME for the leaderboard where we store how many matches the user has won
    private const string MOST_MATCHES_WON = "MOST_MATCHES_WON";

    // the top number of entries to query
    private const int TOP_N_COUNT = 5;

    // how often to poll the service for leaderboard updates
    private const float LEADERBOARD_POLL_FREQ = 30.0f;

    // the next time to check for leaderboard updates
    private float m_nextCheckTime;

    // whether we've found the local user's entry yet
    private bool m_foundLocalUserMostWinsEntry;

    // number of times the local user has won
    private long m_numWins;

    public void Update()
    {
        if (Time.time >= m_nextCheckTime)
        {
            m_nextCheckTime = Time.time + LEADERBOARD_POLL_FREQ;
            QueryMostWinsLeaderboard();
        }
    }

    void QueryMostWinsLeaderboard()
    {
        Leaderboards.GetEntries(MOST_MATCHES_WON, TOP_N_COUNT, LeaderboardFilterType.None,
            LeaderboardStartAt.Top).OnComplete(MostWinsGetEntriesCallback);
    }

    void MostWinsGetEntriesCallback(Message<LeaderboardEntryList> msg)
    {
        if (!msg.IsError)
        {
            foreach (LeaderboardEntry entry in msg.Data)
            {
                string currentUserId;
                Users.GetLoggedInUser().OnComplete(
                  (Message<User> msg) =>
                  {
                      currentUserId = msg.Data.OculusID;
                      if (entry.User.OculusID == currentUserId)
                      {
                          m_foundLocalUserMostWinsEntry = true;
                          m_numWins = entry.Score;
                      }
                  }
                );
            }

            // results might be paged for large requests
            if (msg.Data.HasNextPage)
            {
                Leaderboards.GetNextEntries(msg.Data).OnComplete(MostWinsGetEntriesCallback);
                return;
            }

            // if local user not in the top, get their position specifically
            if (!m_foundLocalUserMostWinsEntry)
            {
                Leaderboards.GetEntries(MOST_MATCHES_WON, 1, LeaderboardFilterType.None,
                    LeaderboardStartAt.CenteredOnViewer).OnComplete(MostWinsGetEntriesCallback);
                return;
            }
        }
        else
        {
            Debug.LogError(msg.GetError());
        }
    }

    // submit the local player's match score to the leaderboard service
    public void SubmitMatchScores(bool wonMatch)
    {
        if (wonMatch)
        {
            m_numWins += 1;
            Leaderboards.WriteEntry(MOST_MATCHES_WON, m_numWins);
        }
    }
}

服务器到服务器 API

您可能需要从您信任的服务器操作排行榜。有关排行榜服务器到服务器 API 的详细信息,请参阅排行榜服务器到服务器 API