WWDC Quick Look 💓 By SwiftGGTeam
Tap into Game Center: Dashboard, Access Point, and Profile

Tap into Game Center: Dashboard, Access Point, and Profile

观看原视频

Highlight

Apple 在 2020 年把 Game Center 重新放回游戏内:玩家通过 Access Point 打开 Dashboard,直接查看资料、好友、排行榜和成就,开发者用 GameKit 的现有控制器接入这套界面。

核心内容

很多游戏原来接入 Game Center 时,入口要自己设计,资料页要跳出游戏,排行榜、成就、好友信息也分散在不同位置。玩家想看自己和朋友的进度,常常要离开当前流程。对开发者来说,这意味着要维护一套游戏内 UI,还要处理登录、隐私、未成年人限制和 tvOS 共享设备上的用户切换。

这场 session 的第一件事,是把 Game Center 变成游戏里的固定入口。游戏启动后仍会显示欢迎横幅,随后出现 Access Point(访问点)。它可以先展示成就数量或排行榜名次,再折叠成玩家头像。玩家点击头像后进入 Dashboard(仪表盘),在同一个覆盖界面里查看资料、排行榜、成就、挑战和好友信息。

第二件事,是让开发者少写界面。Dashboard 仍然由 GKGameCenterViewController 呈现,只是新增了 .dashboard.localPlayerProfile 等状态。Access Point 由 GKAccessPoint.shared 控制位置、亮点和显示状态。游戏只需要在主菜单打开它,在过场、玩法和设置页隐藏它。

第三件事,是把玩家身份变成更明确的开发模型。GKLocalPlayer 表示当前设备上的玩家,GKPlayer 表示其他玩家。认证要尽早开始,因为认证完成后,游戏才能调用 Game Center API,接收邀请、挑战和用户变化通知。玩家隐私、未成年人状态、多人游戏限制和个性化通信限制,也要在认证后检查。

详细内容

GKGameCenterViewController 打开 Dashboard

10:05)新的 Dashboard 是 Game Center 功能的统一入口。它仍然使用熟悉的 GKGameCenterViewController,差异在初始化状态。

// GKGameCenterViewController

public init(state:)
[...]

// Example: Display Main Dashboard
let vc = GKGameCenterViewController(state: .dashboard)
vc.gameCenterDelegate = self
present(vc, animated: true, completion: nil)

[...]
enum GKGameCenterViewControllerState : Int {
   case `default`
   case leaderboards
   case achievements
   case challenges
   case localPlayerProfile
   case dashboard
}

关键点:

  • GKGameCenterViewController(state: .dashboard) 直接打开顶层 Dashboard。
  • gameCenterDelegate 仍然负责处理控制器关闭等委托回调。
  • leaderboardsachievementschallengeslocalPlayerProfile 可以把玩家带到指定区域。
  • 这段代码适合主菜单的“Game Center”按钮,也适合从自定义 UI 进入统一面板。

10:51)如果游戏里已经有一个具体排行榜按钮,可以继续深链接到单个排行榜。

// Display scores for a specific leaderboard
let vc = GKGameCenterViewController(
                leaderboardID: "grp.xyz.laketahoe",
                playerScope: .global,
                timeScope: .allTime)
vc.gameCenterDelegate = self
present(vc, animated: true, completion: nil)

关键点:

  • leaderboardID 对应 App Store Connect 中配置的排行榜。
  • playerScope 控制显示全局玩家还是好友范围。
  • timeScope 控制今天、本周或所有时间这类时间窗口。
  • 深链接进入单个排行榜后,玩家仍可在 Dashboard 中浏览可用区域。

在主菜单显示 Access Point

13:18)Access Point 是一个常驻入口,适合放在游戏主菜单,而不是玩法画面。它的位置会随语言方向变化,例如 topLeading 在从右到左语言中会换到右上角。

// Configure and show Access Point
func showMainMenu() {
    // Call your code to setup the main menu
    self.setupMainMenu()

    // Place access point on top left
    GKAccessPoint.shared.location = .topLeading

    // Show highlights
    GKAccessPoint.shared.showHighlights = true

    // Show it!
    GKAccessPoint.shared.isActive = true
}

关键点:

  • GKAccessPoint.shared.location 选择访问点所在角落。
  • showHighlights 打开成就数量或默认排行榜名次等摘要信息。
  • isActive = true 才会显示 Access Point。
  • session 建议在主菜单显示,在电影式开场、玩法中和设置页隐藏。

在 Dashboard 弹出时暂停菜单动画

14:00)玩家点击 Access Point 后,游戏可能需要暂停主菜单动画或其他背景效果。isPresentingGameCenter 提供了这个信号。

let observation = GKAccessPoint.shared.observe(
           \.isPresentingGameCenter
    ) { [weak self] _,_ in
    self.paused = GKAccessPoint.shared.isPresentingGameCenter
}

关键点:

  • observe(\.isPresentingGameCenter) 监听 Game Center 界面是否正在展示。
  • 回调里把游戏自己的 paused 状态同步到 Access Point 状态。
  • 这能避免 Dashboard 覆盖在游戏上方时,背景仍然播放昂贵动画。
  • 观察对象要由游戏保存,生命周期结束后再释放。

避开 Access Point 的屏幕区域

14:44)Access Point 可能挡住游戏主菜单上的标题、角色或按钮。frameInScreenCoordinates 可以把它的位置交给布局系统。

// Observable properties
// frameInScreenCoordinates

let observation = GKAccessPoint.shared.observe(
           \.frameInScreenCoordinates
    ) { [weak self] _,_ in
    let screenFrame = GKAccessPoint.shared.frameInScreenCoordinates
    let accessPointFrame = myView.convert(screenFrame, from: nil)
    // adjust your layout
}

关键点:

  • frameInScreenCoordinates 给出 Access Point 当前屏幕矩形。
  • myView.convert(screenFrame, from: nil) 把屏幕坐标转到游戏视图坐标。
  • Access Point 展示不同 highlight 时,尺寸可能变化,所以这里适合用观察。
  • 游戏可以移动标题图、按钮或装饰元素,避免被头像入口盖住。

支持 Apple TV 和手柄焦点

15:18)在 tvOS 或手柄场景中,游戏可能自己绘制焦点反馈。此时仍然要把 Access Point 纳入焦点判断。

// Apple TV and controllers

// track and update focus
func trackController(position: CGPoint) {
  let screenFrame = GKAccessPoint.shared.frameInScreenCoordinates
  let accessFrame = myView.convert(screenFrame, from: nil)
  // if the point is in the access point turn on feedback
  accessPointElement.focusFeedback = CGRectContainsPoint(accessFrame, position)
}

关键点:

  • position 是游戏正在追踪的遥控器或手柄焦点位置。
  • 代码先取得 Access Point 的屏幕区域,再转换到游戏视图坐标。
  • CGRectContainsPoint 判断焦点是否落在 Access Point 内。
  • 命中后,游戏可以给自己的 Access Point 代理元素绘制焦点反馈。

15:38)当玩家按下选择键时,用程序化 API 打开 Dashboard。

// Apple TV and controllers

// Handle selection
func accessPointSelected() {
  GKAccessPoint.shared.triggerAccessPoint {}
}

关键点:

  • triggerAccessPoint 模拟玩家触发 Access Point。
  • 这让遥控器和手柄流程不用依赖触摸点击。
  • 调用后,系统会进入与点击头像相同的 Dashboard 流程。

打开本地玩家资料并处理限制

20:01)玩家资料从设置页进入游戏内。开发者可以直接呈现本地玩家资料页。

// Local player profile

let profileVC = GKGameCenterViewController(state: .localPlayerProfile)
profileVC.gameCenterDelegate = self

present(profileVC, animated: true, completion: nil)

关键点:

  • .localPlayerProfile 直接进入当前玩家的资料页。
  • 玩家可以在这里查看成就、找朋友、查看朋友正在玩的游戏。
  • 这段代码适合放在“我的资料”按钮后面。

20:28)认证完成后,游戏还要读取本地玩家限制,决定是否隐藏功能。

// Local player restrictions

GKLocalPlayer.local.authenticateHandler = { viewController, error in
    let isGameCenterReady = (viewController == nil) && (error == nil)

    if isGameCenterReady {
        if GKLocalPlayer.local.isUnderage {
            // Hide explicit game content
        }

        if GKLocalPlayer.local.isMultiplayerGamingRestricted {
            // Disable multiplayer game features
        }

        if GKLocalPlayer.local.isPersonalizedCommunicationRestricted {
            // Disable in game communication UI
        }
    }
}

关键点:

  • authenticateHandler 会自动启动 Game Center 认证,并在状态变化时回调。
  • viewController == nilerror == nil 表示本地玩家已准备好。
  • isUnderage 用来隐藏不适合未成年玩家的内容。
  • isMultiplayerGamingRestricted 用来关闭多人游戏入口。
  • isPersonalizedCommunicationRestricted 是 iOS 14 新增限制,用来关闭游戏内语音或消息等个性化通信 UI。

核心启发

  • 做一个零干扰的 Game Center 主菜单入口:把 Access Point 放在主菜单角落,打开 showHighlights 展示成就数量或默认排行榜名次;值得做的原因是玩家不用离开游戏就能找到个人资料和社交信息;开始时先在主菜单生命周期里设置 GKAccessPoint.shared.locationshowHighlightsisActive

  • 做一个“我的游戏资料”页按钮:在游戏设置页或存档页加入本地玩家资料入口;值得做的原因是玩家可以在同一处查看成就、好友和最近游玩信息;开始时用 GKGameCenterViewController(state: .localPlayerProfile) 呈现系统资料页。

  • 做一个可降级的多人游戏入口:认证后检查 isMultiplayerGamingRestricted,限制打开时隐藏多人按钮,限制关闭时进入匹配流程;值得做的原因是家长控制和账号限制会直接影响多人功能;开始时把限制检查放进 GKLocalPlayer.local.authenticateHandler 的成功分支。

  • 做一个适配手柄的 Dashboard 入口:在 tvOS 或外接手柄菜单中,用 frameInScreenCoordinates 判断焦点是否落在 Access Point 上;值得做的原因是客厅场景没有触摸操作,玩家仍需要清楚的焦点反馈;开始时把手柄追踪坐标转换到同一视图坐标,再调用 triggerAccessPoint

  • 做一个不被系统入口遮挡的主菜单布局:观察 frameInScreenCoordinates,当 Access Point 展示 highlight 导致尺寸变化时移动标题图或按钮;值得做的原因是系统入口会常驻主菜单,遮挡会让玩家误触或看不清核心操作;开始时为主菜单元素增加可响应的安全边距。

关联 Session

评论

GitHub Issues · utterances