Game Center 设计指南
Design for Game Center
2020年6月26日
一句话判断
Game Center 在 iOS 14 中迎来了视觉和体验的全面重做,新的成就展示、排行榜 UI 和多人游戏界面让你的游戏社交功能看起来不再像 2013 年的产物。
这场 Session 讲了什么
Game Center 自 iOS 4 引入以来,外观几乎没有大改过。iOS 14 对 Game Center 做了一次全面的视觉刷新,让它与 iOS 14 的设计语言保持一致。
重点更新包括:成就页面采用全新的卡片式布局,每个成就有更大的图标和更清晰的描述;排行榜支持在 Widget 中展示玩家的排名变化;多人游戏邀请界面重新设计,支持通过 iMessage 和邀请链接来邀请好友;新增了 “Access Point” UI 组件——一个浮动的 Game Center 入口按钮,玩家点击后可以快速查看成就、排行榜和好友列表。Session 还讨论了如何在游戏中合理放置 Game Center 的 UI 元素,以不打断游戏体验为原则。
值得深挖的点
Access Point:Game Center 的浮动入口
这是 Game Center 在 iOS 14 中最重要的 UI 更新。GKAccessPoint 是一个可以放在屏幕角落的浮动按钮,它显示玩家的 Game Center 头像和昵称。玩家点击后,系统会弹出一个半屏的 Game Center 面板,展示成就进度、排行榜排名和好友状态。这个设计解决了之前 Game Center UI 需要开发者自己实现入口的问题——现在只需要一行代码就能添加一个标准的入口。
成就的重设计
iOS 14 的成就展示从之前的”列表”模式改为了”卡片”模式。每个成就有更大的展示空间,包括 100x100 的图标、标题、描述和进度条。完成后的成就会有一个金色的完成标记。你的游戏不需要做任何改动就能获得新的展示效果——系统会自动使用新 UI 渲染你的成就数据。
代码片段
添加 Game Center Access Point
场景:在游戏主界面添加 Game Center 的浮动入口。
import GameKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupGameCenter()
}
private func setupGameCenter() {
// 认证玩家
GKLocalPlayer.local.authenticateHandler = { [weak self] viewController, error in
if let vc = viewController {
// 需要显示 Game Center 登录界面
self?.present(vc, animated: true)
} else if GKLocalPlayer.local.isAuthenticated {
// 已认证,配置 Access Point
self?.configureAccessPoint()
}
}
}
private func configureAccessPoint() {
// 获取 Access Point 实例
let accessPoint = GKAccessPoint.shared
// 设置位置(屏幕角落)
accessPoint.location = .topLeading // 或 .topTrailing, .bottomLeading, .bottomTrailing
// 设置是否显示
accessPoint.isActive = true
// 设置父视图控制器(用于弹出 Game Center 面板)
accessPoint.parentWindow = view.window
}
// 在游戏进行中隐藏 Access Point
func startGameplay() {
GKAccessPoint.shared.isActive = false // 游戏中隐藏,避免遮挡
}
// 游戏结束后重新显示
func endGameplay() {
GKAccessPoint.shared.isActive = true
}
}
报告成就进度
场景:玩家完成特定挑战后更新成就进度。
import GameKit
class AchievementManager {
/// 报告成就进度
func reportAchievement(identifier: String, percentComplete: Double) {
let achievement = GKAchievement(identifier: identifier)
achievement.percentComplete = percentComplete
achievement.showsCompletionBanner = true // 完成时显示通知横幅
GKAchievement.report([achievement]) { error in
if let error = error {
print("报告成就失败: \(error)")
} else {
print("成就进度已更新: \(identifier) - \(percentComplete)%")
}
}
}
/// 加载所有成就定义
func loadAchievements() {
GKAchievementDescription.loadAchievementDescriptions { descriptions, error in
guard let descriptions = descriptions else { return }
for desc in descriptions {
print("成就: \(desc.title)")
print(" 描述: \(desc.achievedDescription)")
print(" 未完成描述: \(desc.unachievedDescription)")
// desc.image 包含成就图标
}
}
}
/// 加载玩家的成就进度
func loadPlayerProgress() {
GKAchievement.loadAchievements { achievements, error in
guard let achievements = achievements else { return }
for achievement in achievements {
print("\(achievement.identifier): \(achievement.percentComplete)%")
print(" 最后更新: \(achievement.lastReportedDate)")
}
}
}
}
提交排行榜分数
场景:游戏结束时将分数提交到排行榜。
import GameKit
class LeaderboardManager {
/// 提交分数
func submitScore(_ score: Int, leaderboardID: String) {
GKLeaderboard.submitScore(
score,
context: 0,
player: GKLocalPlayer.local,
leaderboardIDs: [leaderboardID]
) { error in
if let error = error {
print("提交分数失败: \(error)")
} else {
print("分数已提交: \(score) 到排行榜 \(leaderboardID)")
}
}
}
/// 加载排行榜数据
func loadLeaderboard(leaderboardID: String) {
let request = GKLeaderboard()
request.identifier = leaderboardID
request.playerScope = .friendsOnly // 只看好友排名
request.timeScope = .allTime
request.range = NSRange(location: 1, length: 25) // 前 25 名
request.loadScores { scores, error in
guard let scores = scores else { return }
for score in scores {
print("排名 \(score.rank): \(score.player.alias) - \(score.value) 分")
}
}
}
}
多人游戏邀请
场景:使用新的 Game Center 邀请界面邀请好友。
import GameKit
class MultiplayerManager: NSObject, GKMatchmakerViewControllerDelegate {
private var match: GKMatch?
/// 显示邀请界面
func showInviteScreen(minPlayers: Int = 2, maxPlayers: Int = 4) {
let request = GKMatchRequest()
request.minPlayers = minPlayers
request.maxPlayers = maxPlayers
request.defaultNumberOfPlayers = minPlayers
// 使用近场邀请(同处一室的玩家)
request.inviteeResponseHandler = { player, response in
print("\(player.alias) 的回应: \(response)")
}
let matchmakerVC = GKMatchmakerViewController(matchRequest: request)
matchmakerVC?.delegate = self
if let vc = matchmakerVC {
// present(vc, animated: true)
}
}
// GKMatchmakerViewControllerDelegate
func matchmakerViewController(_ viewController: GKMatchmakerViewController,
didFind match: GKMatch) {
// 找到了匹配的玩家
self.match = match
print("匹配成功,共 \(match.players.count) 名玩家")
viewController.dismiss(animated: true)
startGame()
}
func matchmakerViewController(_ viewController: GKMatchmakerViewController,
didFailWithError error: Error) {
print("匹配失败: \(error)")
viewController.dismiss(animated: true)
}
func matchmakerViewControllerWasCancelled(_ viewController: GKMatchmakerViewController) {
print("用户取消了匹配")
viewController.dismiss(animated: true)
}
private func startGame() {
// 开始多人游戏
}
}
最佳实践
已有项目:如果你的游戏已经集成了 Game Center,在 iOS 14 上添加 GKAccessPoint 作为统一的 Game Center 入口。移除你自定义的 Game Center 入口 UI,使用系统标准的 Access Point 更省力也更一致。确保在游戏进行中隐藏 Access Point 以避免遮挡。
新项目:从第一天就集成 Game Center。在游戏主界面添加 Access Point,定义合理的成就和排行榜。成就的数量建议在 20-50 个之间——太少没有收集动力,太多让玩家望而却步。排行榜建议按时间范围(每日、每周、全时间)分类。
还有什么值得关注
- Game Center 的 Widget 可以在 iOS 14 的主屏上显示玩家的排行榜排名。
- 通过 iMessage 邀请好友时,好友可以直接在消息中看到游戏名称和邀请描述。
GKPlayer.profileImage可以获取玩家的 Game Center 头像,用于游戏内的社交展示。