Apple の Game Center スコア値を取得する

iPhone などの iOS アプリ で Game Center のスコア値を取得するコードを紹介する。

筆者のマシン
Mac mac mini (M1, 2020)
OS Monterey バージョン 12.4
XCode バージョン 13.4
Swift バージョン 5.6.1


ここでは次の手順で説明する。

  1. はじめに
  2. 前準備:​App Store Connect でアプリに Loaderboard を追加
  3. 前準備:​アプリに Game Center ログイン処理を追加
  4. 開発アプリ画面に Game Center のスコア値を表示

はじめに

iOSアプリを開発する際、Game Center と連携することで、自分や全世界のプレイヤーのスコアをLeaderboard 画面で参照できる。ここでは、Loaderboard 画面ではなく、自分の開発アプリ画面上にスコア値を表示するコードを紹介する。

尚、本記事で紹介するコード全体(XCodeプロジェクト)は、GitHubで公開している。

前準備:​App Store Connect でアプリに Loaderboard を追加

開発アプリを Game Center と連携させるために、予め App Store Connect でアプリに Leaderboard を登録しておく。

開発するアプリの「サービス」タブ画面へ移動し、左メニュー「Game center」を選択する。ここでの設定詳細は本記事のメインではないため割愛するが、本記事で紹介するコードのアプリでは、「標準Readerboard」を一つ登録している。
登録後、App Store Connect の「App Store」タプ画面の「Game Center」項目に、登録した Leaderboard 情報が表示される。

また、App Store Connect で指定したアプリのバンドルIDを、XCodeプロジェクトの Bundle Identifier と一致させておくことが必要である。

前準備:​アプリに Game Center ログイン処理を追加

Game Center へスコアをサブミットしたり、Game Center のスコアを参照するためには、ユーザが Game Center へログインしている必要がある。ここでは、Game Center へのログイン処理の簡単な例を紹介する。

エントリーポイント

この例では、AppDelegate クラスで、 Game Center の Access Point 表示(19行目から21行目)と、ログイン処理呼び出し(28行目)を実装している。

import SwiftUI
import GameKit

@main
struct GameCenterGetScoreTestApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate

    var body: some Scene {
        WindowGroup {
            GameCenterGetScoreView()
        }
    }
}

class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Show GameCenter AccessPoint
        GKAccessPoint.shared.location = .topLeading
        GKAccessPoint.shared.showHighlights = true
        GKAccessPoint.shared.isActive = true

        // Call GameCenter authentication
        let window = UIWindow(frame: UIScreen.main.bounds)
        window.rootViewController = UIViewController()
        if let _ = window.rootViewController {
            print("GameCenterのログイン処理を呼び出します")
            GameCenterHelper.loginGameCenter()
        }
        return true
    }
}

Game Center へのログイン処理

下記コードは、ごく簡単なログイン処理である。これにより、Game Center へのログイン画面表示やログイン処理がなされる。
ユーザがログイン済みの場合は、10行目GKLocalPlayer.local.isAuthenticated の戻り値が true となる。

import GameKit

struct GameCenterHelper {

    static func loginGameCenter() {
        GKLocalPlayer.local.authenticateHandler = { _, error in
            if error != nil {
                print("You are not logged into GameCenter.")
                print(error.debugDescription)
            } else if GKLocalPlayer.local.isAuthenticated {
                print("You are logged into GameCenter.")
            }
        }
    }
}

アプリ画面に Game Center への Access Point が表示され、Access Point から Leaderbord を参照して自分や世界中のユーザのスコアを参照できる。

開発アプリ画面に Game Center のスコア値を表示

ここからが本記事の本題である。

Leaderboard 上ではなく、開発アプリ画面上にスコアの値を表示したいときがある。
ここでは、全世界のトップスコアと、アプリの起動ユーザ(Game Center へログインしたユーザ)のスコア値を画面上に表示するコード例を紹介する。

ここからは、次のようなアプリ画面を例に説明する。

このアプリは、画面上の WorldScore で全世界のトップスコアを、myScore でユーザスコアを表示する。左側の初期状態(「Load Score」ボタンをタップする前)は、いずれの値も0である。
「Load Score」ボタンをタップすると、右側の画面のように、Game Center からスコア情報を取得し、WorldScore と myScore に最新のスコアの値を表示する。

View処理

画面のレイアウトである View のコードは以下である。
12行目で、ボタンがタップされたらスコアをロードする関数(後述のloadScore())を呼び出している。
20行目で全世界のトップスコアを、21行目でこのユーザのスコアを表示するようにしている。

import SwiftUI

struct GameCenterGetScoreView: View {

    @ObservedObject private var viewModel = GameCenterGetScoreViewModel()

    var body: some View {
        VStack {
            Spacer()
            VStack {
                Button {
                    viewModel.loadScore()
                } label: {
                    Text("Load Score")
                }
                .buttonStyle(.borderedProminent)
                Text("Load latest scores if you are logged into GameCenter.").font(.caption)
            }.padding()

            Text("WorldScore : \(viewModel.worldHighScore)")
            Text("myScore : \(viewModel.yourHighScore)")
            Spacer()
        }
    }
}

スコア値取得処理

まずは12行目if GKLocalPlayer.local.isAuthenticatedで、ユーザが Game Center へログイン済みかをチェックしている。
次に16行目で、GKLeaderboard クラスの func loadDefaultLeaderboardIdentifier を用いて Leaderboard の Identifier を取得する。

そして22行目で、取得した LeaderboardId が nil かどうかを判定し、nil でなければ 24行目で後述する スコア取得コード を実行している。

import GameKit

class GameCenterGetScoreViewModel: ObservableObject {

    // World score
    @Published private(set) var worldHighScore = 0
    // Your score
    @Published private(set) var yourHighScore = 0

    func loadScore() {
        print("load scores from Loaderboarder.")
        if GKLocalPlayer.local.isAuthenticated {
            print("You are logged in. Start to load scores from Game Center.")
            // Get the Leaderboard ID of this app that you have previously registered in App Store Connect
            // (only one ID is registered here).
            GKLocalPlayer.local.loadDefaultLeaderboardIdentifier(
                completionHandler: { (leaderboardIdentifer, error) in
                if error != nil { // Error occured
                    print(error!.localizedDescription)
                } else { // Got the loaderBoarderIdentifier for this app.
                    // Load scores
                    if let leaderboarderId = leaderboardIdentifer {
                        print("Default leaderboardIdentifer is \(leaderboarderId).")
                        // ここに、下記の スコア取得コード を記述する
                    }
                }
            })
        } else {
            // If you are not logged into GameCenter, displayed scores is set to zero.
            self.worldHighScore = 0
            self.yourHighScore = 0
        }
    }

}

スコア取得コード

GKLeaderboard クラスの func loadLeaderboards で LeaderBoard からスコアを取得する。ここで、全世界のココアはを取得するために4行目で引数 for に .global を、トップのスコア1件のみを取得するため6行目で引数 range の length に 1 を指定している。


GKLeaderboard.loadLeaderboards(IDs: [leaderboarderId]) { (boards, _) in
    boards?.first?.loadEntries(
        for: .global, 
        timeScope: .allTime, 
        range: NSRange(location: 1, length: 1), 
        completionHandler: { (local, entries, _, _) in
            // If entries are loaded, set the value to worldHighScore
            if let entries = entries {
                self.worldHighScore = entries[0].score
            }
            // If local is loaded, set the value to yourHighScore
            if let local = local {
                self.yourHighScore = local.score
            }
        }
    )
}

これにより、Load Score ボタンがタップされたら、最新のスコアを Game Center から取得し、画面上に描画することができる。

以上

シェアする

  • このエントリーをはてなブックマークに追加

フォローする