Highlight
Game Center 在 2020 年加入 recurring leaderboards、新的排行榜和成就页面、成就进度上报流程、多人匹配 UI 选项,以及 personalizedCommunicationRestricted 限制标记,让游戏能把周期竞赛、成就收集和实时或回合制匹配接入 GameKit。
核心内容
很多游戏一开始只需要一个最高分榜。等玩家多了,问题就出现了:永久排行榜被早期高手占住,新玩家很难追上;每周活动要单独清榜,开发者还要处理时间窗口;成就进度散落在游戏 UI 里,玩家不知道下一步该做什么;多人邀请又要同时照顾好友、最近一起玩过的人、联系人和自动匹配。
WWDC 2020 的 Game Center 把这些常见游戏服务收进 GameKit。排行榜新增 recurring leaderboards(周期排行榜),可以按小时、天或周重复创建 occurrence(单次周期)。Game Center 的游戏内 UI 也重新设计,排行榜、成就和多人匹配都能用系统页面承载。
这个变化的价值很直接。开发者不用自己维护每周竞赛表、成就页和邀请大厅的全部 UI。游戏只需要在合适的时机提交分数、上报成就、创建匹配请求,再让 Game Center 负责展示、匹配和部分网络流程。
Session 分成三段。第一段讲排行榜,重点是 classic leaderboard 和 recurring leaderboard 的差异。第二段讲成就,重点是成就的四种显示状态、数量限制和 GKAchievement 上报。第三段讲多人游戏,重点是实时、回合制、server-hosted 三种模式,以及 iOS 14 新增的匹配 UI 配置和隐私限制标记。
详细内容
周期排行榜:把限时竞赛交给 Game Center
(01:23)过去的 Game Center 排行榜都是 classic leaderboards。它们永久保留玩家分数和排名,适合记录总经验、历史最高分、关卡最短用时。2020 年新增 recurring leaderboards,用于短时间、重复发生的竞赛,例如每小时 15 分钟挑战、每周日中午一小时赛事、每天一轮新榜。
(02:32)周期排行榜在 App Store Connect 中配置。开发者设置 initial start date、frequency 和 duration。每个 occurrence 有开始和结束时间,新的 occurrence 只会在当前 occurrence 结束后开始。duration 不能大于 frequency,因为 occurrence 不能重叠。
(04:05)提交 classic leaderboard 分数时,使用 GKLeaderboard.submitScore。同一个调用可以把分数提交到一个或多个 leaderboard ID。
// Use the class method to submit score to one or more leaderboards at once
GKLeaderboard.submitScore(self.points, context: 0, player: GKLocalPlayer.local,
leaderboardIDs: ["my.leaderboard.id"]) { error in
}
关键点:
self.points是本次要提交的分数。context: 0是可选上下文值,Game Center 会把它和分数一起保存。player: GKLocalPlayer.local表示当前已认证的本地玩家。leaderboardIDs可以放多个排行榜 ID,适合一次结算写入多个榜。- completion handler 中处理提交错误。
(04:30)对 recurring leaderboard,也可以直接向周期排行榜 ID 提交分数。Game Center 会把分数投递到当前 active occurrence。如果设备离线,Game Center 会延后发送;服务器按收到分数的时间验证,因此离线提交可能在 occurrence 过期后失败。
// Use the class method to submit score to one or more leaderboards at once
GKLeaderboard.submitScore(self.points, context: 0, player: GKLocalPlayer.local,
leaderboardIDs: ["my.recurring.leaderboard.id"]) { error in
}
关键点:
- 代码形态和 classic leaderboard 相同。
"my.recurring.leaderboard.id"指向 App Store Connect 中配置的周期排行榜。- 提交只能落到当前 active occurrence。
- 离线场景要在游戏结算体验中预留错误处理。
(04:48)如果游戏已经加载了某个 occurrence,也可以通过 GKLeaderboard 实例提交。Session 建议用 startDate 和 duration 判断 occurrence 是否仍然 active。
// Submitting to a specific occurrence of a recurring leaderboard
GKLeaderboard.loadLeaderboards(IDs:["my.recurring.leaderboard.id"]) { (fetchedLBs, error) in
if let lb = fetchedLBs?.first {
lb.submitScore(self.points, context: 0, player: GKLocalPlayer.local) { error in
}
}
}
关键点:
loadLeaderboards先按 ID 加载排行榜。fetchedLBs?.first取到当前 occurrence 对应的GKLeaderboard。lb.submitScore把分数提交到这个 occurrence。- 这种写法适合自定义 UI 已经持有 occurrence 对象的场景。
排行榜 UI:系统页面和自定义页面各有入口
(05:25)展示排行榜有两种方式。Apple 推荐使用 GameKit 的游戏内 UI,因为 GKGameCenterViewController 会处理列表、排行榜详情、好友和全局范围、classic leaderboard 的时间范围、recurring leaderboard 的 occurrence 切换。
// Launching in-game UI
// Display a list of leaderboards
let vc = GKGameCenterViewController(
state: .leaderboards)
vc.gameCenterDelegate = self
present(vc, animated: true, completion: nil)
// Or directly display scores for a specific leaderboard
let vc = GKGameCenterViewController(
leaderboardID: "YOUR_ASC_LEADERBOARD_ID",
playerScope: .global,
timeScope: .allTime)
vc.gameCenterDelegate = self
present(vc, animated: true, completion: nil)
关键点:
state: .leaderboards打开排行榜列表。gameCenterDelegate用来接收关闭等 Game Center 页面事件。- 第二个初始化器可以 deep link 到某个排行榜的分数页。
playerScope: .global显示全局范围,也可以按 GameKit 支持的范围切换。timeScope: .allTime用于 classic leaderboard 的时间维度。
(07:14)如果游戏要自绘排行榜 UI,就要自己加载 leaderboard 和 score。recurring leaderboard 还要处理 occurrence。Game Center 只保留过期 occurrence 最多 30 天;已登录玩家通常能看当前 occurrence 和一个 previous occurrence。
// Accessing previous occurrence
// Load current occurrence of a recurring leaderboard
GKLeaderboard.loadLeaderboards(IDs:["my.recurring.leaderboard.id"]) { (fetchedLBs, error) in
if let current = fetchedLBs?.first {
// Load previous occurrence using the current occurrence
current.loadPreviousOccurrence { (prevOccurrence, error) in
// Do something with the previous occurrence
}
}
}
关键点:
loadLeaderboards对 recurring leaderboard 默认加载 current occurrence。current.loadPreviousOccurrence通过当前 occurrence 取上一个可访问 occurrence。prevOccurrence可用于展示上一轮成绩或赛后回顾。- 游戏自绘 UI 时,需要考虑 occurrence 被清理或玩家未参与上一轮的情况。
成就:用进度驱动玩家回到游戏
(10:20)成就是玩家达成目标后的 collectible item。Game Center 的成就有四种呈现状态:locked、in-progress、completed、hidden。hidden 适合不想提前剧透剧情或目标的成就。iOS、macOS 和 tvOS 的 Game Center Dashboard 都会展示成就,因此成就文案、图片和进度要能独立说明玩家目标。
(13:01)数量限制也很明确:一个游戏最多 100 个 achievements,每个最多 100 points,合计最多 1000 points。初版上线时不要把预算用完,后续更新还可能需要新成就。
(14:34)集成成就分三步:先认证本地玩家;再用 GKAchievement 上报进度;最后用 Game Center Dashboard 或成就页面展示。只要 GameKit 里某个成就进度仍是 0,它就会以 locked 状态出现。
if let achievement = GKAchievement(identifier: identifier) {
achievement.percentComplete = percentComplete
GKAchievement.report([achievement]) { error in
if let error = error {
print("Error in reporting achievements: \(error)")
}
}
}
关键点:
identifier必须对应 App Store Connect 中配置的 achievement ID。percentComplete表示完成进度,达到 100 后成就完成。GKAchievement.report可以一次上报一个数组。- completion handler 中要处理上报失败,尤其是网络或认证问题。
(16:05)展示成就时,优先使用 GKGameCenterViewController(state: .achievements)。如果自绘成就页,再使用 GKAchievementDescription 读取本地化标题、未完成描述、完成描述,以及完成和未完成图片。
// Showing the Game Center achievements page
let viewController = GKGameCenterViewController(state: .achievements)
viewController.gameCenterDelegate = self
present(viewController, animated: true)
关键点:
state: .achievements直接打开当前游戏的成就页。gameCenterDelegate负责页面生命周期回调。present让玩家在游戏内查看进度,不需要跳出游戏。- 自绘 UI 时,文字本地化仍应来自 GameKit 返回的数据。
多人游戏:匹配、邀请和隐私限制
(19:22)Game Center 支持三类多人游戏。Real-time 模式负责寻找玩家、建立连接和发送数据。Turn-based 模式负责回合管理和数据存储。Server-hosted 模式把玩家列表交给开发者自己的服务器。
(21:23)实时多人匹配的基本流程是:认证玩家,创建 GKMatchRequest,设置玩家数量和可邀请对象,再选择自动匹配或展示 GKMatchmakerViewController。应用启动时还应采用 GKInviteEventListener,并向本地玩家注册,用来接收其他玩家发来的邀请。
关键点:
GKMatchRequest描述一局游戏需要多少玩家。- Session 明确提到开发者在 request 中设置玩家数量,并可定义要邀请的人。
GKMatchmaker的自动匹配流程会寻找其他玩家,返回的 match object 用于玩家之间发送数据。- 如果需要玩家自己选人,可以展示
GKMatchmakerViewController。 GKInviteEventListener适合在 app 启动时注册,用来接收其他玩家发来的邀请。
(22:52)回合制匹配流程接近实时匹配。差异在于采用 GKTurnBasedEventListener,并使用 GKTurnBasedMatch 或 GKTurnBasedMatchmakerViewController。回合制对局不需要等待所有玩家同时在线,创建后当前玩家可以立即开始自己的回合。
关键点:
GKMatchRequest仍然描述玩家数量和匹配条件。GKTurnBasedEventListener负责接收回合制事件。GKTurnBasedMatch用于程序化匹配,GKTurnBasedMatchmakerViewController用于展示系统匹配界面。- 当前玩家可以先行动,等待其他玩家后续加入或响应。
(23:29)iOS 14 为 matchmaking UI 增加了配置选项。automatch only 适合想让玩家快速随机开局的游戏。nearby only 适合同房间 ARKit 游戏。Session 还提到新的限制会同时影响多人邀请自定义消息和语音聊天。
// Check if personalized communication is restricted
if GKLocalPlayer.local.personalizedCommunicationRestricted {
// Disable UI for Voice chat
}
关键点:
GKLocalPlayer.local代表当前 Game Center 玩家。personalizedCommunicationRestricted为true时,应用应关闭相关个性化通信入口。- Session 给出的示例是禁用 voice chat UI。
- 这个检查应和多人大厅、邀请入口、语音按钮的显示逻辑放在一起。
核心启发
-
做每周挑战榜:把关卡分数接到 recurring leaderboard,每周自动开新 occurrence。值得做,因为新玩家每周都有追排名的机会。可以从 App Store Connect 配置 weekly frequency 和 duration 开始,再用
GKLeaderboard.submitScore在关卡结算页提交。 -
做限时活动入口:在主菜单显示下一轮挑战倒计时,并在活动期间展示当前 occurrence 的排行榜。值得做,因为 Session 明确说明 occurrence 有开始时间、duration 和下一次开始信息。可以先加载 recurring leaderboard,再根据 occurrence 时间决定按钮状态。
-
做分阶段成就路线:为新手、熟练玩家和核心玩家分别设计成就。值得做,因为 Game Center Dashboard 会把 locked、in-progress 和 completed 状态直接展示给玩家。可以用
GKAchievement(identifier:)和percentComplete在每次任务进度变化时上报。 -
做一键成就页:在暂停菜单或关卡结算页放一个“成就”按钮,直接打开 Game Center achievements 页面。值得做,因为系统页已经处理进度、图片和本地化展示。可以用
GKGameCenterViewController(state: .achievements)起步。 -
做快速多人开局:为休闲模式提供 automatch only,为本地同屏或 AR 玩法提供 nearby only。值得做,因为匹配 UI 可以减少玩家选人步骤。可以用
GKMatchRequest定义玩家数量,再根据模式选择自动匹配或GKMatchmakerViewController。
关联 Session
- Tap into Game Center: Dashboard, Access Point, and Profile — 先完成本地玩家认证、Access Point、Dashboard 和玩家资料入口,再接入本篇的排行榜与成就。
- Design for Game Center — 从界面设计角度讲成就卡片、排行榜图像、多人大厅入口和 Game Center 风格统一。
- Advancements in Game Controllers — 游戏服务层接入 Game Center 后,输入层可以继续适配手柄、触觉反馈和自定义映射。
- Bring keyboard and mouse gaming to iPad — 面向 iPad 游戏补齐键盘、鼠标和触控板输入,适合与多人和排行榜体验一起规划。
评论
GitHub Issues · utterances