为你的游戏添加成就

Epic Games技术客户经理Rajen Kishna |
2022年1月25日
在前两篇博客文章中,我们介绍了统计排行榜,现在我们来看看如何使用成就接口为你的游戏添加成就。成就可以被配置为基于统计进度自动解锁,或使用API手动解锁。在本文中,我们将介绍:
 

Epic在线服务成就与Epic成就

在我们深入探讨Epic在线服务成就的实现之前,我想花点时间解释一下Epic在线服务(EOS)成就与2021年10月公布的Epic成就(在撰写本文时处于抢先体验阶段)之间的关系和区别。
Epic在线服务(EOS)成就
  • 与许多其他Epic在线服务功能一样,Epic在线服务(EOS)成就与平台无关,是一种可以在游戏中实现的成就。
  • 你可以使用EOS成就跟踪进度,并使用你自己的游戏内UI解锁成就。
  • 方便起见,EOS成就将通过覆层呈现,它们无需链接到Epic游戏商城的游戏,因此不会显示在Epic游戏商城的玩家资料或游戏页面中。
  • EOS成就不附带经验值。由于它们具有平台无关性,你可以在游戏中自由实现任何计分机制。
Epic成就
  • Epic成就是一种仅需配置(无需代码)的功能,用于将EOS成就扩展到Epic生态系统(包括Epic游戏商城)。
  • 任何解锁的(或之前解锁过的)EOS成就将为用户解锁相应的Epic成就。
  • Epic成就中的每个成就都附加了经验值。经验值的范围从5到200。本文发布时,一款游戏所有成就的经验值之和必须为1000。
  • 根据分配的经验值,Epic成就划分为3个级别:铜级=5-45经验值,银级=50-95经验值,金级=100-200经验值。
    • 需要注意的是,完成所有其他成就会自动获得额外的铂金级成就(250经验值),因此从每款游戏中总共可以获得1250经验值。
  • Epic成就进度将自动显示在玩家的Epic游戏商城库、玩家资料和Epic游戏商城的游戏页面中(在网页和Epic Games启动程序中都会显示)。
  • 已经配置了Epic成就的游戏将会在覆层中显示Epic成就(包括经验值),取代之前显示的EOS成就。
  • 最后,正如在公告博客中所提到的,Epic成就将在未来扩展,以包括虚拟形象等其他社交功能。

因为Epic成就目前处于抢先体验阶段,并且游戏必须在Epic游戏商城中发布才能配置Epic成就,我们在这篇博客文章中将只关注Epic在线服务成就。

更改我们的客户端策略

要使用成就接口,我们必须在客户端策略中添加操作:
 
  1. 访问https://dev.epicgames.com/portal/登录开发者门户。
  2. 在左侧菜单中导航到你的产品,进入“产品设置”,在“产品设置”界面中点击“客户端”选项卡。
  3. 在你使用的客户端策略旁边点击三点图标,然后点击“更新策略”。
  4. 向下滚动至“功能”并点击“成就”旁的开关按钮。
  5. 勾选以下操作旁的复选框: 
    • findAchievementDefinitions:用于查询成就定义
    • findAchievementsForLocalUser:用于查询玩家成就进度
    • unlockAchievementForLocalUser:用于为已登录的玩家解锁成就
      • 需要注意,在生产环境中应该谨慎使用这一操作,因为它可能被逆向工程,使恶意用户能够在没有获得成就的情况下解锁成就。更可靠的方法是通过统计或你自己的后端服务器解锁成就。
  6. 点击“保存并退出”。
Developer Portal Client Policy Achievements
客户端策略允许的成就功能和操作

在开发者门户中创建成就

成就应在开发者门户中创建,可被设置为基于统计解锁或手动解锁。此外,成就可被设置为可见或隐藏,取决于你是否希望玩家在解锁成就前知道成就内容。让我们在门户中设置一些成就。
 
  1. 在左侧菜单中导航到你的产品,然后依次点击“游戏服务”和“成就”。
  2. 在这里,可以看到在我们产品的每个部署(目前可能只有“Release in Live Sandbox”)中,有哪些成就。
    • 请注意右上方还有“批量导入/导出”按钮,它将帮助你简化成就的备份和创建过程。但在这篇文章中,我们不会涉及这一过程。
  3. 点击右上角的“新建”来添加一个新成就。
  4. 在弹出窗口中,你将看到两个步骤中的第一步,让你定义一个用于自动解锁成就的统计。在下拉菜单中选择“SumStat”统计。我们还需要在统计右边的方框中输入一个阈值。我们在这里输入50。
  5. 我们最多可以在这里定义三个统计,用作解锁成就的依据,但目前我们只使用这一个。点击“下一步”,移动到第二步。
  6. 我们将在这里定义大部分成就设置。输入“50_TOTAL_CLICKS”作为成就ID。
  7. 保留或选择你要用于测试的区域设置。
  8. 在“可见性”设置下,我们让这个成就保持为“已显示”。
  9. 上传成就在解锁和锁定状态下的图标。可以上传任何不高于1024×1024像素,并不超过1.02 MB的图片(JPG、PNG、BMP或非动画GIF)。
    • 请注意图标的文件名必须在所有成就中唯一,否则新上传的同名文件将覆盖旧文件。
  10. 输入锁定和解锁状态下的成就名称和描述:
    • 已锁定显示名称:点击,点击,点击……
    • 已锁定描述:要点击多少次?
    • 已解锁显示名称:点击冠军
    • 已解锁描述:总计点击50次。
    • 注意,你也可以输入可选的风格文本,这是你可能会在游戏中使用的任意本地化字符串。我们暂时跳过这部分。
  11. 现在我们可以点击“创建”完成成就的创建。弹出窗口关闭后,你应该能看到成就出现在列表中。
 
Developer Portal Achievements Click Champion
创建的“点击冠军”成就

我们来创建第二个可以由我们手动解锁的隐藏成就:
 
  1. 点击右上角的“新建”开始添加一个新成就。
  2. 在这两个步骤的第一步中,不指定统计,直接点击弹出窗口中的“下一步”。
  3. 指定成就的细节:
    • 成就ID:TOP_SECRET
    • 可见性:已隐藏
    • 已解锁显示名称:你发现它了
    • 已解锁描述:解锁隐藏成就。
    • 注意,可见性为“已隐藏”的成就没有已锁定显示名称及描述。

查询成就定义

现在我们开始实现查询成就定义的代码:
 
  1. 在Views文件夹中创建一个名为“AchievementView”的新用户控件:
  • 我们的成就UI中将会有两个不同的ListView,一个显示所有定义,另一个显示玩家进度。现在,我们先从显示所有定义的ListView开始,这只会占用部分UI。
 
  1. 打开AchievementsView.xaml.cs,附加ViewModel,并保存占位符选择改变的事件句柄:
  1. 在ViewModels文件夹中添加一个AchievementsViewModel.cs类:
  1. 在ViewModelLocator.cs中添加对AchievementsViewModel的引用:
  1. 在Services文件夹中添加AchievementsService.cs类来保存定义查询逻辑:
 
  1. 在Commands文件夹中添加一个AchievementsQueryDefinitionsCommand.cs类:
  1. 打开AchievementsViewModel.cs,声明和实例化命令:
  1. 在ViewModelLocator.cs中向RaiseConnectCanExecuteChanged()方法添加以下代码行,确保我们只有在通过连接接口成功登录后才能查询成就定义:
  1. 最后,将AchievementsView添加到MainWindow.xaml的TabControl中:
现在,当我们运行应用程序,并通过身份验证接口或连接接口进行身份验证时,我们可以导航到“Achievements”选项卡,使用“Query definitions”按钮查询成就定义。
 
App Achievements QueryDefinitions
查询到的成就定义

查询玩家成就进度

现在我们已经知道如何检索所有成就定义了,我们来看看如何检索玩家的成就进度:
 
  1. 打开AchievementsView.xaml,并在之前的标签下方添加第二个ListView和StackPanel:
  • 我们使用了一点蛮力方法来显示附加到成就的统计(如果有的话)。我们将显示数组中的第一个统计(即使没有)。在生产环境中,必须先验证StatInfo属性中返回的PlayerStatInfo数组,然后才能使用它。
 
  1. 打开AchievementsViewModel.cs,并在SelectedAchievement下方声明以下集合,以保存玩家成就进度:
  1. 打开AchievementsService.cs并添加以下方法来保存我们的玩家成就进度查询逻辑:
 
  1. 在Commands文件夹中添加一个AchievementsQueryPlayerAchievementsCommand.cs类:
  1. 打开AchievementsViewModel.cs,声明和实例化命令:
  1. 打开ViewModelLocator.cs,并在RaiseConnectCanExecuteChanged()方法中添加以下代码行,确保我们只有在通过连接接口成功登录后才能查询玩家成就进度:
现在,我们可以再次启动应用程序,并使用“Query progress”按钮检索玩家成就进度。
 
App Achievements QueryPlayerAchievementsInitial
查询到的玩家成就进度

这里有几点需要注意:
 
  • 从QueryPlayerAchievements调用返回的DisplayName属性是“null”,Description、IconURL和FlavorText属性(我们不在UI中显示它们)也一样。这些属性通过QueryDefinitions调用被检索并存储到SDK缓存中,因此我们需要先点击“Query definitions”按钮,以将这些属性填充到缓存中。
  • StatInfo属性将为“null”,除非玩家拥有采集的统计值。在上面的截图中,我重置了已登录玩家的统计,所以这里没有显示任何值。
  • 玩家进度被报告为0和1之间的双精度值,代表着0到100%之间的一个数值。在截图中,因为已登录的玩家没有已采集的统计,所以进度是0。

在我们的示例应用程序中,导航到“Stats”标签页,采集点击数之后,我们可以返回到“Achievements”标签页,先后点击“Query definitions”和“Query progress”,以显示玩家的进度:
 
App Achievements QueryPlayerAchievementsFinal
查询到的玩家成就进度

解锁成就

我们已经设置了一个手动解锁的成就,还有一个使用统计自动解锁的成就。我们来看看手动解锁成就的代码,并了解如何在成就自动解锁时得到通知。

请注意,如前文所述,在游戏代码中手动解锁成就可能会暴露出一条攻击途径,让恶意用户能够解锁他们未获得的成就。
 
  1. 打开AchievementService.cs并添加以下方法来保存我们手动解锁成就的逻辑:
 
  1. 在Commands文件夹中添加一个AchievementsUnlockAchievementCommand.cs类:
  1. 打开AchievementsViewModel.cs,声明和实例化命令:
  1. 最后,打开AchievementsView.xaml.cs,并在AchievementsListView_SelectionChanged方法中添加以下代码行,确保我们只有在选中一个成就后才能点击解锁按钮:
当你运行应用程序并进行身份验证时,导航到“Achievements”标签页,并点击“Query definitions”。然后点击TOP_SECRET成就,再点击“Unlock”按钮。UI不会发生改变,但你应该能在Visual Studio的调试输出中看到“UnlockAchievements Success”消息。注意,这段代码适用于可见成就和隐藏成就。

现在我们可以点击“Query progress”,随后我们的成就将显示在列表中。就像之前看到的那样,隐藏的成就在被解锁之前,不会被QueryPlayerAchievements调用返回。
 
App Achievements UnlockAchievement
手动解锁的隐藏成就

最后,我们来订阅成就解锁通知,如此一来,当成就通过统计进度解锁时,我们就能运行自己的代码:
 
  1. 打开AchievementsService.cs,添加以下用于订阅和取消订阅成就通知的方法:
  • 我们调用Achievements.AddNotifyAchievementsUnlockedV2来设置通知,传入一个回调方法,当通过采集与某个成就相关的统计数据解锁该成就时,将调用该方法。注意,当你手动解锁成就时,也会调用这个方法。
  • 在这种情况下,AchievementsUnlockedCallback只会将一行信息写入调试输出,但你应该据此处理所有UI,通知玩家他们解锁了一个成就。
  • AddNotifyAchievementsUnlockedV2将返回notificationId,你可以用它来停止接收成就解锁通知。我们不会在这个示例中实现它,但它是RemoveNotification方法的功能。
 
  1. 为了简单起见,在AchievementsService.cs的QueryDefinitions方法中添加以下调用,就在ViewModelLocator.Main.StatusBarText = string.Empty上面,以便在调用QueryDefinitions后开始获得通知。
再次运行应用程序并进行身份验证,然后导航到成就标签页,并点击“Query definitions”按钮。要查看总计50次点击的成就进度,请点击“Query progress”按钮。如果成就尚未解锁,请记下进度并导航到“Stats”标签页,采集更多的点击数,直到解锁成就。

你应该会看到Visual Studio的调试输出中弹出了一条消息,表明成就解锁了。如果你已经解锁了成就,请按照下一部分的步骤重置成就,并在必要时重置玩家的统计。

查找和修改玩家成就

任何时候,如果你需要手动调整玩家的成就,解锁或重置/锁定它们,可以在开发者门户中这样操作:
 
  1. 访问https://dev.epicgames.com/portal/登录开发者门户。
  2. 在左侧菜单中导航到你的产品,然后依次点击“游戏服务”和“成就”。
  3. 点击右上方的“玩家查找”按钮。
  4. 在弹出窗口中,输入玩家的产品用户ID(PUID)或特定账户ID(例如Epic账户ID),然后点击“搜索”。
  5. 将出现玩家的成就列表,显示它们的当前进度和解锁状态。在这个列表中,你可以点击省略号按钮解锁或重置成就。

注意,你也可以使用“重置全部”或“解锁全部”按钮来快速切换所有成就的解锁状态,但在生产环境中这么做时需谨慎。这在开发过程中非常有用。另一种良好的做法是在开发过程中创建一个单独的部署,用来测试成就,因为所有玩家数据都针对于一个特定的部署。

Developer Portal Achievements Player Lookup
在开发者门户中解锁或重置成就

使用限制和要求

和之前介绍的服务相同,成就存在一些使用限制,旨在为所有玩家确保可靠性和可用性。撰写本文时,存在下列限制(请务必参阅这篇文档了解最新信息):
 
  • 每个部署的成就总数不能超过1000
  • 成就最多可以基于3项统计自动解锁

成就还必须符合以下要求:
 
  • 成就ID不能超过256个字符
  • 成就ID不能包含以下字符:, { ^ } % ` ] > [ ~ < # | & $ @ = ; ?\ ( ) * /
  • 图标文件名不能包含以下字符: , { ^ } % ` ] > [ ~ < # | & $ @ = ; :+ ?!\ ( ) * /
  • 每个成就最多可以有22个本地化文本变体
  • 成就图标文件大小不能超过1.02 MB
  • 成就图标的分辨率不能超过1024×1024像素
  • 成就图标必须为PNG、JPG、BMP或非动画GIF格式

最后,对于客户端API调用或服务器调用,也分别存在针对每个用户或每个部署的速率限制,你可以在这篇文档中了解详情。

获取代码

在下方可以获取本文的代码。请按照GitHub仓库中的使用说明设置下载的代码。
 
你可以在系列目录中找到包含本系列所有文章的完整列表,如果你对本文有任何疑问或反馈,请前往社区论坛告知我们。

    你的成功就是我们的成功

    Epic秉承开放、整合的游戏社区理念。
    通过免费向所有人提供在线服务,我们致力于帮助更多开发者服务好他们自己的玩家社区。