[转载] 原文链接:https://partner.steamgames.com/doc/features/achievements
概览
Steam 统计和成就为您的游戏提供了一种简便的方式,持续并动态追踪用户的成就与统计数据。 用户的数据将与 Steam 帐户相关联,而每项成就与统计数据皆可依固定的格式显示于用户的 Steam 社区个人资料之中。
有什么好处
除了向您的游戏玩家提供高价值的奖励之外,成就也很适合用于鼓励和奖励团队合作或玩家互动、加深游戏目标的层次,并且玩家会因在游戏上花更多时间得到奖励。
统计数据则记录了许多精细的信息,像是游戏时间、使用的能量增强物品的数量等等。 您可将它们仅用于记录内部游戏数据,以便从多台电脑收集多重会话的游戏统计数据,为用户授予成就。
实现概览
定义游戏的统计与成就
成就专属于各个应用程序,必须使用 Steamworks 合作伙伴站点的应用管理页面进行设置。
您可直接从 此处 前往统计配置页面,或从 此处 前往成就配置页面。
可储存的统计类型有三种:
INT - 32 位(带正负号的)整数(例如游戏次数)
FLOAT - 32 位的浮点值(例如驾驶里程数)
AVGRATE - 移动平均数。 详见:AVGRATE 统计类型
Steamworks 合作伙伴站点的接口可供您定义和更新游戏统计和成就,具体用途为:
定义初始统计与成就
增加额外统计与成就
更新成就名称、描述,和图标
更新统计的参数与限制(最大 / 最小值、移动平均窗口大小等等)
统计具有下列属性:
ID - 每项统计自动产生的数字 ID
类型 此项统计的类型 - INT 、 FLOAT ,或 AVGRATE
API 名称 - 用来访问此项成就的 API 字符串
设置人- 设定谁能修改这项统计,默认为客户端。 更多信息请见 游戏服务器统计数据 文档。
仅限增量– 设置后,此统计数值便只能随着时间增加
最大变更- 设置后,每次调用一个 SetStat 到下一个 Setstat 时,此项统计的数值能改变的最大值
最小值- 设置后,此项成就能接受的最小数值,默认最小值是基本数值类型的最小值( INT_MIN 或 -FLT_MAX )。
最大值- 设置后,此项成就能接受的最大数值,默认最大值是基本数值类型的最大值( INT_MAX 或 FLT_MAX )。
默认值- 设置后,新用户初始设置的默认统计数值。 如果没有设置,默认值则为零。
合计– 设置后, Steam 将记录此项统计的全球统计。 更多信息,请见下方的全球统计。
显示名称- 显示于 Steam 社区的统计名称。 可本地化。
AVGRATE 具有以下额外的属性:
- 窗口 - 用来计算平均值的”滑动窗口”的大小
AVGRATE 统计由 Steam 自动平均得出。 请参见下文的的 AVGRATE 一节,了解更多信息。
成就具有下列属性:
ID - 每项统计自动产生的数字 ID
API 名称- 用来访问此项成就的 API 字符串
进度状态- 指定一项统计数据,作为此项成就在社区中的显示进度指示器。 当统计数值达到解锁值时,成就将自动解锁
显示名称- 出现于客户端弹出通知和社区的显示名称。 可本地化
**描述 **- 社区中关于此项成就的描述。 可本地化
设置人- 设定谁能解锁此项成就。 默认是客户。 请参见 游戏服务器统计数据 ,了解更多信息。
隐藏- 如勾选,”隐藏”成就在达成之前则完全不会显示于用户的社区页面中
已达成图标- 达成成就后显示的图标
未达成图标- 未达成成就时显示的图标
以下是 Steamworks API 示例应用程序(SpaceWar) 的成就列表:
使用方法
在游戏中访问统计和成就:
初始化 Steamworks API 后,您便可开始使用 ISteamUserStats 中的统计与成就 API 。
游戏会话开始时,调用 ISteamUserStats::RequestCurrentStats 从 Steam 后端调出用户的统计与成就数据。 数据准备完成后,将会收到 ISteamUserStats::UserStatsReceived_t 的回调。
使用 ISteamUserStats::GetStat 和 ISteamUserStats::GetAchievement 迭代每项数据并初始化游戏状态
如想在游戏中显示成就,可使用 ISteamUserStats::GetAchievementDisplayAttribute 来获取一般可读的成就属性,包括名称(” name ”)和描述(” desc ”)。 这些属性可从 Steamworks 合作伙伴站点的此处进行本地化, 系统将根据用户在游戏中使用的语言返回不同的数据。 您可使用 ISteamUserStats::GetAchievementIcon 取得每项成就的图标,或用ISteamUserStats::GetAchievementAndUnlockTime 取得每项成就的解锁时间
每当统计数值的变更呈现给用户之前,调用 ISteamUserStats::SetStat 或 ISteamUserStats::UpdateAvgRateStat 。 此调用只会改变 Steam 的内存状态,消耗的资源很少。即便在发生游戏崩溃的状况下,这样做也可以让 Steam 保持会话之间的变更一致。
在游戏中适当的时候(例如检查点或等级转换),调用 ISteamUserStats::StoreStats 上传变更。 完成后,即会收到一个 ISteamUserStats::UserStatsStored_t 回调
如果成就有进度指示器,在重要时点可使用 ISteamUserStats::IndicateAchievementProgress 弹出进度状态的通知信息。 例如,如果需要20 场胜利即可达成成就,您可能需要在完成 10 场时调用此 API,提示用户已经完成一半了
每当解锁一项或几项成就时,针对每项未解锁成就,调用 ISteamUserStats::SetAchievement 然后使用 ISteamUserStats::StoreStats 立刻上传。 您的游戏将收到 ISteamUserStats::UserStatsStored_t 回调,并对每项未解锁成就外加一个 ISteamUserStats::UserAchievementStored_t回调。 Steam 游戏界面则会向用户显示一个通知面板
AVGRATE 统计类型
此统计类型提供了独特且非常有用的功能,但需要一些详细说明。
假如您想追踪某项平均统计数据,例如”每小时平均得分”。 一种办法是设置两项统计数据,一个 INT 的”总得分”,和 FLOAT 的”总游玩时数”,然后将得分除以游玩时数,得到每小时平均得分。
这个方法这的缺点是,一但玩家的游戏时数达到某个程度,计算出的平均值将变动得非常缓慢。 实际上,玩家玩得越多,平均值的反应就越不明显。 如果玩家花了 100 个小时在游戏上,得出的平均将会”延迟”大概 50 个小时。 即便他们提高了技术水平,也不会如期看到每小时平均得分的增加。
AVGRATE 统计类型则能让您设置一个可影响平均值的”滑动窗口”。 举例来说,您可使用几小时前的游戏时间数据,让统计数值更精确地反应玩家目前的技术水平。
现在来设置一个 AVGRATE 统计来实现”每小时平均得分”,而且只有过去 20 个小时的游戏才能影响数值。 方法是:
由于平均值以”每小时”计算,与此统计相关的时间参数的单位都是”小时”,例如统计本身的窗口属性,和传给
UpdateAvgRateStat
的 dSessionLength 参数创建一个名为” AvgPointsPerHour ”的 AVGRATE 统计,并将窗口属性设置为 20.0 (谨记:以”小时”为单位)
-
在游戏中适当的时候,调用 ISteamUserStats::UpdateAvgRateStat 并传入下列参数:
pchName – ” AvgPointsPerHour ”
flCountThisSession - 自从上次调用 UpdateAvgRateStat 后,玩家所获得的分数
dSessionLength - 自从上次调用 UpdateAvgRateStat 后,玩家的游玩时数必须使用与窗口属性相同的单位,在此例中,以”小时”为单位。
例如,玩家在过去 0.225 小时( 13.5 分钟)获得了 77 分,就会变成
SteamUserStats()-> UpdateAvgRateStat( " AvgPointsPerHour", 77, 0.225 )
在上述实例中, Steam 会将这回合的平均每小时 342.2 分( 77 除以 0.225 )与先前的数值一起计算,结果便是玩家过去 20 个小时游戏时间的平均得分。 如果这是第一次为此玩家更新数据,那么目前的值就是 342.2。
此实例用”小时”作为单位,但您也可使用任何其他的时间单位。请记住,您必须始终使用该单位作为”dSessionLength”的基础,以及窗口属性。
取得其他玩家的统计数据
您可使用 ISteamUserStats::RequestUserStats 取得其他玩家的统计数据,然后使用 ISteamUserStats::GetUserStat 、 ISteamUserStats::GetUserAchievement ,和ISteamUserStats::GetUserAchievementAndUnlockTime 取得用户的其他数据。 由于其他玩家会不断上传新的统计数据,您取得的数据并不会自动更新。 再次调用 ISteamUserStats::RequestUserStats 即可刷新数据。
为避免使用过多的内存,系统会维持一个近来最少使用( LRU )缓存,并会偶尔加载其他用户的统计。 这种状况发生时将自动发送一个 ISteamUserStats::UserStatsUnloaded_t 回调。 发出回调后,再次调用ISteamUserStats::RequestUserStats 之前,都无法使用该用户的统计数据。
离线模式
Steam 会将统计与成就数据保存于本机缓存之中,以便在离线模式中也能正常使用 API 。 这段时间无法上传的统计皆会被保存至下次联机至网络。 如在多台机器上都有过修改,Steam 会自动合并成就,并选择进度最多的一组统计数据。 由于 Steam 已经在本机缓存上保存了统计数据,游戏便没有必要再将数据缓存于磁盘上。 这两种缓存常常互相冲突,当他们这样做时,用户就会认为他们的进度已经复原了。
游戏服务器统计数据
与 ISteamUserStats 性质相近的便是游戏服务器的 ISteamGameServerStats 了,可以使用与客户端相同的方式取得用户的统计数据。 但只有在”设定人”是 GS(游戏服务器)或Official GS (官方游戏服务器)的情况下,才可以用它来设置统计和成就。 游戏服务器和官方游戏服务器的差别在于,官方服务器是您自己主持并控制的。 使用官方服务器设定统计数据能够杜绝作弊行为,因为如此一来玩家便无法变更自己的游戏服务器,或假扮游戏服务器。 如要设置官方服务器,可从此处输入服务器的 IP 范围。
游戏服务器可设定的统计与成就不能由客户端更改。 游戏服务器只能为正在服务器上游玩的玩家设定统计与成就。 当用户离开了服务器,会有一小段宽限期可设置最终的统计,之后所有上传都会被拒绝。 这是为了保持数据的一致性,以及避免恶意的服务器随时随意更改任何人的统计。 鉴于这项限制,尽量不要等到回合结束时才设置统计。 要持续地设置统计,当用户退出游戏时便能顺利储存。
游戏服务器变更统计时,客户端便会自动获得更新。 但是,像客户端一样,加载其他用户的数据后不会自动更新,有可能不正确。
重设统计数据
开发过程中,常常会有为了测试希望清除某个帐户所有统计与成就的状况。 要清除帐户所有统计,调用 ISteamUserStats::ResetAllStats,而将 bAchievementsToo
设置为 **true[/ b] 即可一同清除成就。 调用后,记得要重新逐一查看统计与成就,并重设内存中游戏状态。 无法统一清除所有用户的统计与成就。 这是因为就算统一清除了数据,运行中的游戏可能也不会注意到这次清除,而写入内存中的值。 所幸有一个简单的办法,可以在您的游戏中建立一个统一清除系统。 具体方法是:
定义一项成就,名称可以用” Versoin ”
在游戏中放入一个硬编码统计版本编号
加载统计后,对比” Version ”和硬编码的版本编号
如不相符,调用 ISteamUserStats::ResetAllStats 然后将”Version”设为硬编码号码
这样一来,无论何时您想要统一清除,只需改变硬编码的统计版本号码就可以了。 其他人拿到新生成版本时,便会统一清除数据。只需确保统一清除代码不会在最终生成版本中出现。
统计一致性
最好的做法是考虑相关的统计数据会如何变得不一致。 举例来说,您有三项统计”GamesWon”、”GamesLost”,和“GamesPlayed”。 即使考虑得再周到,统计数据之间也会确实出现无法同步的情况。此种情况下,胜场和败场数加起来有可能不到总游戏场数。 假如您将“GamesLost”去掉,而使用“GamesPlayed”-“GamesWon”来计算败场的话,数据不一致时便会导致”GamesLost”变成负数。 这种状况下,最好的办法是不要使用“GamesPlays”而使用 “GamesWon”+ “GamesLost”进行计算。
全球统计数据
可在管理页面中标出统计的合计, Steam 便会保存所有用户的该项统计的总值。 这可以用来记录经济体中所有的金钱、总击杀数、最受欢迎的武器或地图,或哪个队伍的表现更佳。 另一方面,此方法不能用在像是“MostKills”的统计中,因为将多个用户的最高击杀数加起来没有任何意义。 由于统计是掌握在玩家手上,这些数据便有遭到操纵的可能。 因此,使用合计时,设置最小值、最大值、仅限增量(如有需要)与最大变更便至关重要。 最大变更对合计统计来说意义特殊。 每当上传了新的值,合计值的改变不会超过最大变更值。 如此便能限制一个作弊者影响全球总数的快慢。
要访问全球统计,先调用 ISteamUserStats::RequestGlobalStats 然后再调用 ISteamUserStats::GetGlobalStat 取得每项统计。 也可向 ISteamUserStats::RequestGlobalStats 要求一段特定时间内的历史记录,这些历史记录了这项统计每天的变更量。 使用 ISteamUserStats::GetGlobalStatHistory 便可访问历史纪录。
您也可从客户端要求全球成就完成百分比。 首先调用 ISteamUserStats::RequestGlobalAchievementPercentages。 然后调用 ISteamUserStats::GetMostAchievedAchievementInfo 和ISteamUserStats::GetNextMostAchievedAchievementInfo 以最多完成到最少完成的顺序逐一查看每项成就。 您也可调用 ISteamUserStats::GetAchievementAchievedPercent 取得某项成就的完成百分比。
Steam 社区
游戏发行之后,有关个人与全球的成就进度便会显示于 Steam 社区中。每个玩家都将从他们的社区资料中获得一个链接,此链接会显示他们已经取得的成就,以及他们还未解锁的内容。
备注:在您的应用在社区曝光以前,您的成就不会显示出来。
每项成就都会与在 Steamworks 控制面板中设置的图标、名称和描述一起列出。 如果成就的名称和内容已被本地化为用户所选语言,便会以该语言显示。
此页面和游戏的 Steam 主页面皆会有一个链接连至全球成就统计数据的页面,显示每一项成就的 Steam 玩家全球达标率,按最常见到最罕见的顺序排列。 这对于玩家来说很有趣,对开发者来说也是项很有用的资源;特别挑战够不够难? 或是难度太高了? (这些信息也可在 Steamworks 合作伙伴站点上找到)。**