![](https://habrastorage.org/storage2/e4a/2fb/3ed/e4a2fb3ed4f0049e934ab73205d8b782.png)
Game Centerを使用したマルチプレイヤーのiOSゲームへの統合に関する優れたチュートリアルの翻訳。 著者のサイトには、初心者のゲーム開発者を支援するために設計された多くのレッスンがあります。
あなたが取り組んでいるゲームは非常に簡単です。 これは、犬と子供が参加するレースです。 できるだけ早くタップして勝ちましょう!
このチュートリアルでは、ユーザーがCocos2Dの基本に精通していることを前提としています。 それ以外の場合は、 ここで見つけることができる他のCocos2Dレッスンに慣れることをお勧めします。
注:アプリケーションでGame Centerの動作を確認するには、登録済みのiOS開発者である必要があります。 また、少なくとも1つの物理iOSデバイスが必要です(アプリケーションの1つのコピーがシミュレーターで動作し、もう1つがデバイスで動作するため)。 最後に、テストには少なくとも2つの異なるGame Centerアカウントが必要です(別の電子メールアドレスが必要な場合のみ、無料で作成できます)。
準備はいい? その後、GO!
それでは始めましょう
このレッスンでは、マルチプレイヤーコンポーネントをシンプルなゲームに追加する方法を示します。 ゲームプロセスのロジックの作成はこのレッスンの目標の一部ではないため、ネットワークを操作せずにゲームコードを含むブランクを準備しました。
コードをダウンロードして、プロジェクトを実行します。 次のようなものが表示されるはずです。
![画像](https://habrastorage.org/getpro/habr/post_images/70f/195/a7b/70f195a7b173eaf49c0e3aa18d490335.jpg)
ゲームは非常にシンプルで、コードはよくコメントされています。 それをチェックして、すべてがあなたに明らかであることを確かめてください。
Game Centerをオンにする
現時点では、プレイできるシンプルなゲームがありますが、一人でプレイするのは非常に退屈です! Game Centerを使用して友だちを招待したり、マッチファインダーを使用してランダムな人とプレイしたりするのはもっと楽しいでしょう。 ただし、Game Centerの使用を開始する前に、次の2つのことを行う必要があります。
- アプリIDを作成および構成します。
- iTunes Connectでアプリケーションを登録します。
始めましょう。
アプリIDを作成して構成する
最初のステップは、アプリIDを作成および構成することです。 これを行うには、 iOS Dev Centerにログインし、そこからiOS Provisioning Portalにログインします。 スクリーンショットのように、[アプリID]タブを開いて、アプリケーションの新しいアプリIDを作成します。
![画像](https://habrastorage.org/getpro/habr/post_images/3fa/8c6/2e6/3fa8c62e64e7b2fbb529ab9d62eacfa4.jpg)
最も重要な部分はバンドル識別子です。 一意の文字列である必要があります(つまり、使用している文字列と一致することはできません!)良い方法は、ドメイン名の後に一意の文字列を使用して、名前の一致を回避することです。
完了したら、[送信]をクリックします。 次に、Cat Raceプロジェクトを開き、Resources \ Info.plistを選択します( 注: Xcodeの以降のバージョンでは、このファイルはSupporting Filesフォルダーにあり、%Project_name%-Info.plistと呼ばれます)。バンドル識別子をiOSプロビジョニングポータルに入力したものに変更します以下に示すように(もちろん、別の値を入力します):
![画像](https://habrastorage.org/getpro/habr/post_images/0b1/502/225/0b1502225ddd9aa81c161a59983c25e4.jpg)
そして最後のこと。 Xcodeの問題を回避するには、次の手順を実行します。
- デバイスまたはシミュレーターからアプリケーションのすべてのコピーを削除します。
- 実行中のシミュレーターを終了します。
- Project \ Cleanを実行します。
おめでとうございます。これでアプリのアプリIDが取得でき、使用するように設定されました。 これで、アプリケーションをiTunes Connectに登録し、Game Centerを有効にできます。
iTunes Connectでアプリケーションを登録する
次のステップは、 iTunes Connectにログインして、新しいアプリケーションを登録することです。
iTunes Connectにログインしたら、[アプリケーションの管理]を選択し、左上の青い[新しいアプリの追加]ボタンをクリックします。 スクリーンショットのように、アプリケーションの名前、SKU番号を入力し、以前のサンプルと同様にバンドルIDを選択します。
![画像](https://habrastorage.org/getpro/habr/post_images/830/ee6/c5e/830ee6c5e99a1b40433a7d005f344745.jpg)
[続行]をクリックして、アプリケーションに関する基本情報を入力します。 後で変更できるので、それが非常に重要になるまで正確性について心配する必要はありません。 とりあえず、iTunes Connectを幸せにするために何か(アイコンとスクリーンショットを含む)を提供するだけです。
完了したら、[保存]をクリックします。すべてが正常に完了したら、スクリーンショットのように、アプリケーションのステータスは「アップロードの準備」になります。
![画像](https://habrastorage.org/getpro/habr/post_images/3fa/1a6/9d5/3fa1a69d57a1f50acf0214d0931a63be.jpg)
右上にある青い「Manage Game Center」ボタンをクリックして、「有効にする」をクリックします。 その後、「完了」をクリックします。 それだけです。GameCenterはアプリケーションに含まれており、コードの記述を開始できます。
ところで、「Manage Game Center」セクションでは、リーダーボードと、もちろん実績も管理できます。 このレッスンでは、それらの操作については説明しません。
ローカルプレイヤーの承認:理論
ゲームが開始されると、最初のステップはローカルプレーヤーを認証することです。 とても簡単です。 authenticateWithCompletionHandlerを呼び出すだけです。 必要に応じて、ユーザー認証の直後に特定のコードブロックが実行されることを確認できます。
しかし、1つのトリックがあります。 承認にはもう1つの方法があります。 これを行うには、Game Centerアプリケーションに切り替え、そこからログインして、アプリケーションに戻ります。
アプリケーションは、承認ステータスがいつ変更されるかを知る必要があります。 これについては、「認証が変更されました」通知に登録することで確認できます。 そのため、プレーヤーを認証するには以下が必要です。
- シングルトンオブジェクトを作成します( 約Transl。:シングルトンは、クラスが1つのインスタンスのみを持ち、このインスタンスへのグローバルアクセスを提供する設計パターンです)、Game Centerコードを1か所に保持します。
- シングルトンオブジェクトが作成されると、「認証が変更されました」という通知を受信するように登録されます。
- ゲームはプレーヤーを認証するためにシングルトンオブジェクトメソッドを呼び出します。
- プレーヤーがログインまたはログアウトすると、認証変更機能へのコールバックが実行されます。
- コールバック関数は、プレーヤーが現在ログインしているかどうかを追跡します。
ローカルプレーヤー認証:実装
Cat Raceプロジェクトで、新しいファイルを作成し、iOS \ Cocoa Touch \ Objective-Cクラスを選択して、[次へ]をクリックします。 [サブクラス]フィールドにNSObjectと入力し、[次へ]をクリックして新しいクラスにGCHelperという名前を付け、[完了]をクリックします。 次に、GCHelper.hの内容を次のものに置き換えます。
#import <Foundation/Foundation.h> #import <GameKit/GameKit.h> @interface GCHelper : NSObject { BOOL gameCenterAvailable; BOOL userAuthenticated; } @property (assign, readonly) BOOL gameCenterAvailable; + (GCHelper *)sharedInstance; - (void)authenticateLocalUser; @end
このコードはGameKitヘッダーファイルをインポートし、2つのブール変数を持つオブジェクトを作成します。 そのうちの1つはGame Centerの可用性ステータスを監視するために必要であり、もう1つはプレーヤーがいつ承認されるかを決定するために必要です。
また、次のものも作成します。GameCenterが利用可能であることをゲームが報告できるようにするプロパティ。 オブジェクトのインスタンスの一意性を維持する静的メソッドと、ローカルユーザーを承認する別のメソッド(アプリケーションの起動時に呼び出されます)。
次に、GCHelper.mに移動して、@ implementation内に次のコードを追加します。
@synthesize gameCenterAvailable; #pragma mark Initialization static GCHelper *sharedHelper = nil; + (GCHelper *) sharedInstance { if (!sharedHelper) { sharedHelper = [[GCHelper alloc] init]; } return sharedHelper; }
これにより、gameCenterAvailableプロパティが合成され、クラスの単一インスタンスを作成するメソッドが設定されます。 シングルトンメソッドを記述するためのオプションは多数ありますが、多くのスレッドが同時にシングルトンを初期化しようとすることを心配する必要がない場合、これが最も簡単な方法です。
次に、sharedInstanceメソッドの直後に次のメソッドを追加します。
- (BOOL)isGameCenterAvailable { // check for presence of GKLocalPlayer API Class gcClass = (NSClassFromString(@"GKLocalPlayer")); // check if the device is running iOS 4.1 or later NSString *reqSysVer = @"4.1"; NSString *currSysVer = [[UIDevice currentDevice] systemVersion]; BOOL osVersionSupported = ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending); return (gcClass && osVersionSupported); }
この方法は、 AppleのGame Kitの使用ガイドから直接取られました。 このメソッドは、特定のデバイスでGame Kitの可用性を確認します。 これにより、アプリケーションはiOS 4.0以前で実行できます(マルチプレイヤーなしでのみ)。
次に、前のメソッドの直後に次のコードを追加します。
- (id)init { if ((self = [super init])) { gameCenterAvailable = [self isGameCenterAvailable]; if (gameCenterAvailable) { NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; [nc addObserver:self selector:@selector(authenticationChanged) name:GKPlayerAuthenticationDidChangeNotificationName object:nil]; } } return self; } - (void)authenticationChanged { if ([GKLocalPlayer localPlayer].isAuthenticated && !userAuthenticated) { NSLog(@"Authentication changed: player authenticated."); userAuthenticated = TRUE; } else if (![GKLocalPlayer localPlayer].isAuthenticated && userAuthenticated) { NSLog(@"Authentication changed: player not authenticated"); userAuthenticated = FALSE; } }
initメソッドは、Game Centerの可用性をチェックし、肯定的な結果が得られた場合、「認証が変更されました」という通知に登録されます。 ユーザーを認証する前に、アプリケーションがこの通知に登録されていることが重要です。そのため、認証が完了した後に動作します。
authenticationChangedコールバック関数は非常に単純です。つまり、状態の変更中にユーザーが承認されたかどうかを確認し、それに応じてフラグを変更します。
トレーニング目的で、関数を連続して数回呼び出して承認または終了し、userAuthenticatedフラグが現在のステータスと異なることを確認し、しばらくして変更があったかどうかのみを表示できることに注意してください。
最後に、authenticationChangedメソッドの直後にローカルプレーヤーを認証するメソッドを追加します。
#pragma mark User functions - (void)authenticateLocalUser { if (!gameCenterAvailable) return; NSLog(@"Authenticating local user..."); if ([GKLocalPlayer localPlayer].authenticated == NO) { [[GKLocalPlayer localPlayer] authenticateWithCompletionHandler:nil]; } else { NSLog(@"Already authenticated!"); } }
これは、後述するauthenticateWithCompletionHandlerメソッドを呼び出します。 これは、プレーヤーを認証する必要性についてGame Kitに通知するのに役立ちます。 完了ハンドラを渡さないことに注意してください。 「認証が変更されました」通知を受信するように登録しているため、これはオプションです。
さて、GCHelperにはプレーヤーを認証するために必要なすべてのコードが含まれているので、使用するだけです! AppDelegate.mに切り替えて、次の変更を行います。
// #import "GCHelper.h" // applicationDidFinishLaunching, // , runWithScene: [[GCHelper sharedInstance] authenticateLocalUser];
これにより、単一のインスタンス(初期化プロセス中に「認証が変更された」コールバックに登録する)が作成され、authenticateLocalUserメソッドが呼び出されます。
ほぼ完了! 最後のステップは、ゲームキットフレームワークをプロジェクトに追加することです。 これを行うには、[グループとファイル]タブの左上にあるCat Raceプロジェクトを選択し、[ビルドフェーズ]タブに移動して、[バイナリとライブラリをリンク]を展開し、[+]ボタンをクリックします。 GameKit.frameworkを選択し、[追加]をクリックします。 タイプを「必須」から「オプション」に変更すると、画面は次のようになります。
![画像](https://habrastorage.org/getpro/habr/post_images/c12/2dc/04f/c122dc04f1ee8f8e10669075036c6439.jpg)
やった! プロジェクトをビルドして実行します。GameCenterにログインしている場合、次のように表示されます。
![画像](https://habrastorage.org/getpro/habr/post_images/8ff/128/581/8ff128581695689c9e1b687bd06b42da.jpg)
プレーヤーを承認したので、たとえば、一緒に遊ぶ相手を見つけるなど、楽しんでください!
Game Center、Game Center、私をマッチさせて
Game Centerで遊ぶ相手を見つけるには2つの方法があります。 これは、プログラムによる、または組み込みのマッチメイキングインターフェイスを使用した一致検索です。
このレッスンでは、組み込みのマッチメイキングインターフェイスについて学習します。 アイデアは、一致を見つけたいとき、いくつかのパラメーターをGKMatchRequestオブジェクトに渡し、GKMatchmakerViewControllerインスタンスを作成して表示するというものです。
仕組みを見てみましょう。 まず、CGHelper.hにいくつかの変更を加えます。
// @protocol GCHelperDelegate - (void)matchStarted; - (void)matchEnded; - (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID; @end // @interface @interface GCHelper : NSObject <GKMatchmakerViewControllerDelegate, GKMatchDelegate> { // @interface UIViewController *presentingViewController; GKMatch *match; BOOL matchStarted; id <GCHelperDelegate> delegate; // @interface @property (retain) UIViewController *presentingViewController; @property (retain) GKMatch *match; @property (assign) id <GCHelperDelegate> delegate; - (void)findMatchWithMinPlayers:(int)minPlayers maxPlayers:(int)maxPlayers viewController:(UIViewController *)viewController delegate:(id<GCHelperDelegate>)theDelegate;
このコードを簡単に見ていきましょう。
- GCHelperDelegateプロトコルを定義します。これは、次のような重要なイベントを別のオブジェクトに通知するために使用されます:一致の開始、データの終了または受信。 このゲームでは、Cocos2Dレイヤーがこのプロトコルを実装します。
- GCHelperオブジェクトは2つのプロトコルを実装しています。 1つ目は、一致を作成するためのインターフェイスが、一致が見つかった場合または見つからなかった場合にこのオブジェクトに通知できるようにするためのものです。 そして2つ目-データが受信されたとき、または接続ステータスが変更されたときにGame Centerがこのオブジェクトに通知できるように。
- 新しいインスタンス変数とプロパティが作成され、ViewMakingインターフェースに沿って表示されます。 マッチへのリンクだけでなく、マッチが開始されたかどうかを知らせる変数、およびデリゲート。
- Cocos2Dレイヤーがプレイする人を見つけることができるように、新しいメソッドが作成されています。
GCHelper.mに切り替えて、次の変更を行います。
// @synthesize presentingViewController; @synthesize match; @synthesize delegate; // , authenticateLocalUser - (void)findMatchWithMinPlayers:(int)minPlayers maxPlayers:(int)maxPlayers viewController:(UIViewController *)viewController delegate:(id<GCHelperDelegate>)theDelegate { if (!gameCenterAvailable) return; matchStarted = NO; self.match = nil; self.presentingViewController = viewController; delegate = theDelegate; [presentingViewController dismissModalViewControllerAnimated:NO]; GKMatchRequest *request = [[[GKMatchRequest alloc] init] autorelease]; request.minPlayers = minPlayers; request.maxPlayers = maxPlayers; GKMatchmakerViewController *mmvc = [[[GKMatchmakerViewController alloc] initWithMatchRequest:request] autorelease]; mmvc.matchmakerDelegate = self; [presentingViewController presentModalViewController:mmvc animated:YES]; }
このメソッドは、一致を検索するためにCocos2Dレイヤーによって呼び出されます。 Game Centerが利用できない場合、このメソッドは何もしません。
彼はまだ開始していないマッチを初期化し、マッチのオブジェクトをnilとして初期化します。 将来の使用のために外部からView Controllerとデリゲートを保存し、それ以前に存在していたView Controllerをキャンセルします(GKMatchmakerViewControllerが現在表示されている場合)。
次に重要な部分があります。 GKMatchRequestオブジェクトを使用すると、プレーヤーの最小数や最大数など、探している試合のタイプを指定できます。 このメソッドは、転送されたときにそれらを設定します(このゲームでは、少なくとも2人のプレイヤー、最大2人のプレイヤー)。
次に、受信したリクエスト( 約 Transl。:GKMatchRequestインスタンス)でGKMatchmakerViewControllerの新しいインスタンスを作成し、GCHelperオブジェクトをデリゲートとして設定し、送信されたView Controllerを画面に表示します。
この瞬間から、制御はGKMatchmakerViewControllerに転送され、ユーザーはランダムなプレーヤーを見つけてゲームを開始できます。 その後、いくつかのコールバック関数が呼び出されるので、それらを追加しましょう:
#pragma mark GKMatchmakerViewControllerDelegate // - (void)matchmakerViewControllerWasCancelled:(GKMatchmakerViewController *)viewController { [presentingViewController dismissModalViewControllerAnimated:YES]; } // - (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFailWithError:(NSError *)error { [presentingViewController dismissModalViewControllerAnimated:YES]; NSLog(@"Error finding match: %@", error.localizedDescription); } // , - (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFindMatch:(GKMatch *)theMatch { [presentingViewController dismissModalViewControllerAnimated:YES]; self.match = theMatch; match.delegate = self; if (!matchStarted && match.expectedPlayerCount == 0) { NSLog(@"Ready to start match!"); } }
プレーヤーがマッチ検索をキャンセルした場合、またはエラーが発生した場合、マッチ作成ビューは単に閉じます。
一致が見つかった場合、一致オブジェクトを保存し、GCHelperを一致のデリゲートとして設定します。これにより、着信データと接続ステータスの変更を通知できます。
また、試合を開始する時間かどうかを確認します。 一致オブジェクトは、expectedPlayerCount変数に検索するプレーヤーの数を格納します。 0の場合、誰でも開始できます。 ログアウトするだけです。後でここで何か面白いことをします。
次に、GKMatchDelegateコールバック関数の実装を追加します。
#pragma mark GKMatchDelegate // - (void)match:(GKMatch *)theMatch didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID { if (match != theMatch) return; [delegate match:theMatch didReceiveData:data fromPlayer:playerID]; } // (, , ) - (void)match:(GKMatch *)theMatch player:(NSString *)playerID didChangeState:(GKPlayerConnectionState)state { if (match != theMatch) return; switch (state) { case GKPlayerStateConnected: // handle a new player connection. NSLog(@"Player connected!"); if (!matchStarted && theMatch.expectedPlayerCount == 0) { NSLog(@"Ready to start match!"); } break; case GKPlayerStateDisconnected: // a player just disconnected. NSLog(@"Player disconnected!"); matchStarted = NO; [delegate matchEnded]; break; } } // - - (void)match:(GKMatch *)theMatch connectionWithPlayerFailed:(NSString *)playerID withError:(NSError *)error { if (match != theMatch) return; NSLog(@"Failed to connect to player with error: %@", error.localizedDescription); matchStarted = NO; [delegate matchEnded]; } // - - (void)match:(GKMatch *)theMatch didFailWithError:(NSError *)error { if (match != theMatch) return; NSLog(@"Match failed with error: %@", error.localizedDescription); matchStarted = NO; [delegate matchEnded]; }
match:didReceiveData:fromPlayerは、別のプレーヤーがデータを送信するときに呼び出されます。 このメソッドは、データをデリゲートにリダイレクトするだけで(このゲームではCocos2Dレイヤーになります)、ゲームエンジンで使用できます。
match:player:didChangStateは、プレーヤーを接続するときに使用され、すべてのプレーヤーが接続されているかどうかを確認して、試合を開始できるようにします。 それ以外の場合、プレーヤーが切断すると、試合は終了し、デリゲートに通知が送信されます。
さて、一致を作成するコードができたので、HelloWorldLayerで使用してみましょう。 HelloWorldLayer.hに切り替えて、次の変更を行います。
// #import "GCHelper.h" // @interface GCHelperDelegate @interface HelloWorldLayer : CCLayer <GCHelperDelegate>
HelloWorldLayer.mに切り替えて、これらの修正を行います。
// #import "AppDelegate.h" #import "RootViewController.h" // init, setGameState AppDelegate * delegate = (AppDelegate *) [UIApplication sharedApplication].delegate; [[GCHelper sharedInstance] findMatchWithMinPlayers:2 maxPlayers:2 viewController:delegate.viewController delegate:self]; // #pragma mark GCHelperDelegate - (void)matchStarted { CCLOG(@"Match started"); } - (void)matchEnded { CCLOG(@"Match ended"); } - (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID { CCLOG(@"Received data"); }
ここで最も重要な部分は、initメソッドです。 このView Controllerは一致を作成するView Controllerを表示するため、App DelegateからRootViewControllerを取得します。 次に、View Controllerを表示して一致を作成することにより、一致を検索するメソッドが呼び出されます。 これは、GCHelperで作成したメソッドです。
次に、一致の開始または終了の機能の空白があります。これは後で実装します。
最後に。 デフォルトでは、Cocos2DテンプレートにはApp DelegateのRootViewControllerのプロパティが含まれていないため、追加する必要があります。 AppDelegate.hに切り替えて、次を追加します。
@property (nonatomic, retain) RootViewController *viewController;
AppDelegate.mでそれを合成します。
@synthesize viewController;
できた! アプリケーションをビルドして実行すると、一致を作成するためのView Controllerがどのように表示されるかがわかります。
![画像](https://habrastorage.org/getpro/habr/post_images/7c3/3bf/788/7c33bf788a43a90f4c65f8b4a44103de.jpg)
ここで別のデバイスでアプリケーションを実行して、同時に2つの実行中のコピーがあるようにします(たとえば、シミュレーターとiPhoneにすることができます)。
重要:各デバイスで異なるGame Centerアカウントを使用していることを確認してください。そうしないと何も機能しません。
両方のデバイスで「今すぐ再生」をクリックすると、しばらくすると、試合を作成するためのView Controllerが消え、ログに次のようなものが表示されます。
CatRace[16440:207] Authentication changed: player authenticated. CatRace[16440:207] Player connected! CatRace[16440:207] Ready to start match!
おめでとうございます! 2つのデバイス間の一致を作成しました! これで、オンラインゲームを作成できます。
横向きとGKMatchmakerViewController
デフォルトでは、GKMatchmakerViewControllerがポートレットの向きに表示されることに注意してください。 明らかに、このCocos2Dゲームはランドスケープであるため、これは非常に迷惑です!
幸いなことに、GKMatchmakerViewControllerに横向きのみを許可することで、これを修正できます。 これを行うには、新しいファイルを作成し、iOS \ Cocoa Touch \ Objective-Cクラスを選択し、GKMatchmakerViewController-LandscapeOnlyという名前でNSObjectをサブクラス化します。
GKMatchmakerViewController-LandscapeOnly.hの内容を次のものに置き換えます。
#import <Foundation/Foundation.h> #import <GameKit/GameKit.h> @interface GKMatchmakerViewController(LandscapeOnly) - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; @end
そして、GKMatchmakerViewController-LandscapeOnly.mの内容:
#import "GKMatchmakerViewController-LandscapeOnly.h" @implementation GKMatchmakerViewController (LandscapeOnly) - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return ( UIInterfaceOrientationIsLandscape( interfaceOrientation ) ); } @end
それだけです! アプリケーションをビルドして実行します。 これで、View Controllerが横向きビューで表示されます:
![画像](https://habrastorage.org/getpro/habr/post_images/413/66f/319/41366f3194d908f4df11bd4d5bd573bc.jpg)
次は?
このチュートリアルで説明したすべてのコードを含むプロジェクトの例を次に示します。
第2部では、デバイス間でデータを転送する方法を学び、ゲームを素晴らしい猫対ベビーレースに変えます!