iOS 4.1 から、正式に Game Center が使えるようになりました。Game Center を使うと、ゲームに簡単に対戦やスコア、達成目標などの機能を追加できます。

Game Centerは、プレー中のゲームについての情報をプレーヤー同士で共有したり、ほかのプレー ヤーと一緒にマルチプレーヤー対戦に参加できるソーシャルゲーミングサービスです。Game Center は、ワイヤレスネットワークと携帯電話ネットワークのどちらからでもサービスを提供できます。 Game Centerの主な機能は、次の通りです。

  • 認証 - プレーヤーはGame Centerでセキュアなアカウントを作成し、iOSベースのデバイスでGame Centerにアクセスできます。

  • 友だち - プレーヤーはGame Centerのほかのプレーヤーを友だちとして登録できます。友だちは、最近遊んだゲームなどプレーヤーの詳細情報を確認できます。

  • Leaderboard - プレーヤーのスコアをGame Centerに記録したりGame Centerから取得したりできます。
  • アチーブメント(Achievement、成績) - そのゲームでのプレーヤーのアチーブメントを管理します。アチーブメントは、Game Centerサービスに記録され、Game Centerアプリケーションとゲームの中で閲覧できます。

  • オートマッチ - Game Centerを介して複数のプレーヤーとつながるネットワークゲームを作成できます。プレーヤーは友だちを招待したり、まだ会ったことのないプレーヤーと接続して対戦できます。プレーヤーは、ゲームを実行していないときでも対戦への招待を受信できます。その場合、ゲームが自動的に起動し、招待が処理されます。

  • ボイス - 対戦に接続されたプレーヤー間で音声通信を行うことができます。
『Game Kit プログラミングガイド』より

Game Center を使うためのプログラミングは形式的ながら、視点が二つ(自分と対戦相手)あるため、どの機能が何に当たるのかを理解していないと混乱しがちです。

本記事は、自分で Game Center を使ったアプリを作ったときの、メモをまとめたものです。

開発時の環境

iOS SDK バージョン
4.3
クライアント iOS バージョン
自分: iOS 4.3.2   対戦相手: iOS 4.3.5

Game Center を使った対戦機能開発のメモ

Game Center を使ったアプリの開発手順は、『Game Kit プログラミングガイド』 - Apple Developer(PDF)に詳しく載っています。わかりやすい説明で読めば大体理解できると思います。対戦相手とのマッチングの部分だけ、自分と相手がいるのと、非同期で処理がされていくためどのメソッドがどの役割かが最初は混乱するかもしれません。

Leaderboard とアチーブメントはたぶん、そんなに混乱しないはず。

用語のまとめ

プレイヤー

Game Center でプレイヤーとは、GKPlayer クラスで表される Game Center で認証されたユーザのことを指します。GKPlayer インスタンスの alias プロパティでプレイヤーのニックネームを取得できます。

端末上で認証したプレイヤーのこと(自分自身)を特に GKLocalPlayer クラスで表します。GKLocalPlayer からは友だちの一覧などの情報を取得できます。

マッチメイク

対戦相手を探す機能のことです。対戦相手は友だちへのゲーム招待(相手に PUSH 機能で通知がいく)と自動マッチングで探すことができます。

当然ですが、一つのアプリで、招待機能(Request)と招待受理機能(Invite)を実装する必要があります。

GKMatchRequest

対戦相手を探す際の対戦要求を表すクラス。対戦相手の人数など、細かな条件を設定できます。

GKInvite

対戦要求によって招待されたことをあわらすクラスです。

GKMatch

マッチングされたネットワークセッションを表すクラスです。このオブジェクトに対してデータを送ることで、通信相手にデータが届きます。

Game Center を使ったプログラミングの手順

Game Center を使ったプログラミングの流れは次のようになります。

  1. Game Center が利用可能かどうかを確認する。一度確認すればよい。[コード]
  2. アプリケーション起動時に、できるだけはやく Game Center への認証を済ませる。これは、その後のゲーム招待を処理するために必要。[コード]
  3. 認証が済んだら、ゲーム招待を処理するハンドラを登録する。ゲーム招待を受理してアプリが起動された場合はアプリのトップ画面が表示されるので、アプリのトップで Game Center の認証を行い、続けてゲーム招待を処理するハンドラを登録するべき。そうしないと、せっかくの招待が無駄になる。[コード]
  4. 自分で対戦要求を作成する場合は、GKMatchRequest を作成してマッチメイク画面を開く。招待された側は、ゲーム招待処理ハンドラが呼び出されて、ゲーム招待(GKInvite)を利用してマッチメイク画面を開く。[コード]
  5. 自分で対戦相手を探す場合は、対戦要求を作成する。[コード]
  6. 対戦相手が決まったら、コールバックメソッドを実装して対戦を開始する。[コード]
  7. 対戦相手を自動で決める場合は GKMatchmaker の findMatchForRequest メソッドを利用する。(後で書く)
  8. 対戦が開始されたら、GKMatch に対してデータを送ることで通信ができる。[コード]
  9. 通信を受け取るには、GKMatchDelegate プロトコルを実装し、GKMatch の delegate に設定する。[コード]

プログラミングコードの断片

Game Center が利用出来るかどうか

SDK が Game Center に対応しているか(GKLocalPlayer クラスが参照できるかで確認)と iOS が 4.1 以降であるかを確認する。

Game Center が利用出来るかどうかは、最初の一度だけ行えば良い。すなわち、メンバ変数にキャッシュできる。以降、gameCenterAvailable 変数がそれ。

1
2
3
4
5
6
7
8
9
10
11
12
13
- (BOOL)isGameCenterAvailable
{
  // Test for Game Center availability
  Class gameKitLocalPlayerClass = NSClassFromString(@"GKLocalPlayer");
  BOOL localPlayerAvailable = (gameKitLocalPlayerClass != nil);

  // Test if device is running iOS 4.1 or higher
  NSString *requireSysVer = @"4.1";
  NSString *currentSysVer = [[UIDevice currentDevice] systemVersion];
  BOOL isOSVer41 = ([currentSysVer compare:requireSysVer options:NSNumericSearch] != NSOrderedAscending);

  return localPlayerAvailable && isOSVer41;
}

Game Center の認証

authenticateWithCompletionHandler メソッドで Game Center を使って認証できる。認証済みでない場合は、認証ダイアログが表示される。

認証が済んだら、できるだけはやくゲーム招待を処理するためのハンドラを登録する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- (void)authenticateLocalPlayer
{
  if (gameCenterAvailable) {
    GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
    if (!localPlayer.authenticated) {
      [localPlayer authenticateWithCompletionHandler:^(NSError *error) {
        self.error = error

        if (error == nil) {
          // ゲーム招待を処理するためのハンドラを設定する
          [self initMatchInviteHandler];
        }
      }];
    }
  }
}

ゲーム招待を処理するハンドラを登録する

GKMatchmaker の inviteHandler にブロックを渡すことで、招待が処理された際にコールバックされるようになる。

  • acceptedInviteパラメータは、ゲームが別のプレーヤーから直接招待を受け取るとnil以外の値になります。この場合は、ほかのプレーヤーのゲームがすでに対戦要求を作成しています。 そのため、招待された側のデバイスで実行しているアプリケーションで対戦要求を作成する必要はありません。

  • playersToInviteパラメータは、対戦をホストするGame Centerアプリケーションから直接ゲームが起動されるとnil以外の値になります。このパラメータは、ゲームが対戦に招待すべきプレーヤーを示したプレーヤー識別子の配列を保持します。ゲームは新しい対戦要求を作成し、 通常通りにパラメータを割り当ててから、対戦要求のplayersToInviteプロパティをplayersToInviteパラメータで渡された値に設定する必要があります。マッチメーク画面が表示されると、すでに対戦に参加しているプレーヤーのリストがあらかじめ読み込まれます。

『Game Kit プログラミングガイド』より
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- (void)initMatchInviteHandler
{
    if (gameCenterAvailable) {
    [GKMatchmaker sharedMatchmaker].inviteHandler = ^(GKInvite *acceptedInvite, NSArray *playersToInvite) {
      // 既存のマッチングを破棄する
      self.currentMatch = nil;

      if (acceptedInvite) {
        // ゲーム招待を利用してマッチメイク画面を開く
        [self showMatchmakerWithInvite:acceptedInvite];
      } else if (playersToInvite) {
        // 招待するユーザを指定してマッチメイク要求を作成する
        GKMatchRequest *request = [[[GKMatchRequest alloc] init] autorelease];
        request.minPlayers = 2;
        request.maxPlayers = 2;
        request.playersToInvite = playersToInvite;

        [self showMatchmakerWithRequest:request];
      }
    };
  }
}

マッチメイク画面を開く

マッチメイク画面を開くには、ViewController が必要。マッチメイク要求(Request)かゲーム招待(Invite)かどちらかを使ってマッチメイク画面を開く。

インターフェースはほとんど同じになる。

1
2
3
4
5
6
7
8
9
10
11
12
13
- (void)showMatchmakerWithRequest:(GKMatchRequest *)request
{
  GKMatchmakerViewController *viewController = [[[GKMatchmakerViewController alloc] initWithMatchRequest:request] autorelease];
  viewController.matchmakerDelegate = self;
  [self presentModalViewController:viewController animated:YES];
}

- (void)showMatchmakerWithInvite:(GKInvite *)invite
{
  GKMatchmakerViewController *viewController = [[[GKMatchmakerViewController alloc] initWithInvite:invite] autorelease];
  viewController.matchmakerDelegate = self;
  [self presentModalViewController:viewController animated:YES];
}

自分で対戦要求を作成する場合

自分で対戦要求を作成する場合は、GKMatchRequest を作って、マッチメイク画面を表示する。

対戦要求は任意のタイミングで作成すればよい。例えば、メニューで「ふたりで対戦する」ボタンが押されたとき等。

1
2
3
4
5
6
7
8
9
10
11
12
- (void)requestMatch
{
  GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
  if (localPlayer.authenticated) {
    // 対戦相手を決める
    GKMatchRequest *request = [[[GKMatchRequest alloc] init] autorelease];
    request.minPlayers = 2;
    request.maxPlayers = 2;

    [self showMatchmakerWithRequest:request];
  }
}

対戦相手が決まった際に呼び出されるコールバック

対戦相手が決まるたびに、呼び出されるコールバックメソッド。これは GKMatchmakerViewController の matchmakerDelegate を経由して呼び出される。

コールバックを受け取るには、GKMatchmakerViewControllerDelegate プロトコルを実装している必要がある。

matchStarted はゲームがスタートしているかどうかを表すメンバ変数。match.expectedPlayerCount は対戦要求にあと何人の必要プレイヤーがいるかを表す値。0になれば、必要なプレイヤーが揃ったことになる。

1
2
3
4
5
6
7
8
9
10
11
- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFindMatch:(GKMatch *)match
{
  [self dismissModalViewController];
  self.currentMatch = match;

  // 全ユーザが揃ったかどうか
  if (!matchStarted && match.expectedPlayerCount == 0) {
    matchStarted = YES;
    // ゲーム開始の処理
  }
}

対戦相手にデータを送る

対戦相手がきまり、現在の通信セッションを表す GKMatch が取得できたら、GKMatch に対して sendDataToAllPlayers メソッドを呼び出してデータを送信する。

これによって対戦相手にデータが送られる。

GKMatchSendDataUnreliable モードは、いわゆる UDP で送信するイメージ。GKMatchSendDataReliable モードは TCP で送るイメージ。通常は GKMatchSendDataUnreliable でよいはず。

データの内容や型は、アプリ側で好きに決めることができる。ほとんどの場合、カスタムの構造体を作成してデータを送信する。構造体を作れば、sizeof(myData) でバイトサイズを取得できる。

1
2
3
4
5
6
7
8
9
- (void)sendDataToAllPlayers:(void *)data sizeInBytes:(NSUInteger)sizeInBytes
{
  if (gameCenterAvailable) {
    NSError *error = nil;
    NSData *packetData = [NSData dataWithBytes:data length:sizeInBytes];
    [currentMatch sendDataToAllPlayers:packetData withDataMode:GKMatchSendDataUnreliable error:&error];
    self.error = error;
  }
}

対戦相手からデータを受け取る

対戦相手からデータを受け取るには、GKMatch のデリゲートに GKMatchDelegate を実装したインスタンスを割り当てます。

対戦相手からデータを受け取った場合には、次のコールバックメソッドが呼び出されます。

1
2
3
4
- (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID
{
  // データを受け取ってアプリで利用する
}

対戦機能をテストする方法

Game Center の機能をテストするために、Apple はサンドボックス環境を用意してくれています。サンドボックス環境は、シミュレータ上でも実機でもどちらでも使うことができます。

ただし、シミュレータ上ではマッチメイクの招待の送受信はできません。マッチメイクのテストをするには、実機を二台用意する必要があります。

実機を二台用意したら次の手順でテストできます。

  1. iTunes Connect にアプリを登録して、Game Center 機能を有効にする。『iTuens Connect デベロッパガイド』参照
  2. 実機を二台用意する。
  3. それぞれの実機にテストアプリをインストールする。(Xcode 上でデバッグビルドで起動すれば入る)
  4. サンドボックス環境にスイッチするために、テストアプリ内から認証機能を実行する。
  5. アプリを閉じて、Game Center アプリを立ち上げ、サンドボックス環境であることを確認して友だちを招待する
  6. もう一台の実機のほうでもサンドボックス環境にスイッチし、Game Center アプリを開き友だちリクエストを承認する
  7. アプリに戻り、マッチメイク機能をテストする

マッチメイクの招待には PUSH 配信を利用するので、実機で Game Center の通知機能をオンするのを忘れずに。

サンドボックス環境にスイッチする

もし、すでに Game Center にサインインしている場合は、一度 Game Center アプリを起動して、サインアウトしておきます。

アプリを立ち上げて、認証機能を実行すると、下の図のようなダイアログが表示されます。

Game Center 認証画面

Game Center のアカウントを持っていない場合は、ここで開発用のアカウントを作成します。すでに持っている場合は、Use Existing Account を選択して、既存のアカウントでサインインします。

サンドボックス環境と通常の環境とのスイッチは、開発中のアプリケーションでサインインしたかどうかで決まります。アカウントは同じものを使えます。

サンドボックス環境にスイッチできたかどうかは、一度アプリを終了させ、Game Center アプリを起動することで確認できます。

GameCenterサンドボックス

サンドボックス環境で友だちを招待する

サンドボックス環境の Game Center アプリから、友だちリクエストを送ります。このリクエストは、サンドボックス環境内のアカウントに対して送信されるため、 相手もサンドボックス環境にスイッチする必要があります。

二台目の実機のほうもサンドボックス環境にスイッチして、Game Center アプリを起動すると、リクエストタブに友だちリクエストが着ているはずです。

サンドボックス環境でマッチメイク機能をテストする

二台ともサンドボックス環境にスイッチできたら、ゲーム内から友だちを招待して対戦機能をテストできます。

下の図は、requestMatch メソッドを呼び出した時の画面です。

Game Center マッチメイク画面

cocos2d 本おすすめ

  • Steffen Itterheim (著), 畑 圭輔 (監修), 坂本 一樹 (監修), 加藤 寛人 (監修), 高丘 知央 (監修), 株式会社 クイープ (翻訳)
  • インプレスジャパン

cocos2d は Objective-C で書かれたゲームエンジン、フレームワークです。2D ゲームを作成するに当たっての結構簡単にわかりやすい機能を提供してくれます。

cocos2d は最近 Version 1.0 が正式にリリースされました。OpenGL ES のコードを隠していながら、UIViewController も提供してくれるようになったため、Game Center を使ったアプリともスムーズに連携できるようになりました。

また、『cocos2dで作る iPhone&iPadゲームプログラミング』の中にも1章まるまるつかって、Game Center を使ったプログラミングの解説がされています。

おすすめの一冊です。