2013年9月20日

【iPhone】GameController.frameworkの実装



iOS7から新たに登場した、GameController.frameworkの実装方法のまとめです。

(リリース前情報をまとめた感じですので、リリース後は少し違うかもしれません)


iOS7からGameController.frameworkが登場いたしました。
Appleのリファレンスだけでは分かりづらかったので実装方法をまとめました。


はじめに

今回、ゲームコントローラーには3種類のコントローラーがあります。
基本ゲームパッド、拡張ゲームパッド、独立拡張ゲームパッドです

基本ゲームパッドには

  • 十字キー
  • ボタンA、B、X、Y
  • ボタンL、R

が付いています。

拡張ゲームパッドと独立拡張ゲームパッドには、上のボタンに追加して、

  • 3Dスティック
  • ボタンL2、R2

が付いています。


コントローラーの接続

iPhoneに常にコントローラーが接続されている訳ではありません。
接続されたかどうかをアプリ側で認識する必要があります。

接続確認するには、以下のようなコードで行います。


- (void)setupControllers:(NSNotification *)notification
{
  // Get Controllers
  self.controllerArray = [GCController controllers];
  if ([self.controllerArray count] > 0) {
    // Found controllers
  } else {
    // No controllers
  }
}


NSNotificationが引数に付いているのは、NSNotificationCenterからの通知でこのコードを実行する為です。
通知を登録するには、


NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
// Set up connect notification
[ center addObserver:self selector:@selector(setupControllers:)
  name:GCControllerDidConnectNotification object:nil];
// Set up disconnect notification
[ center addObserver:self selector:@selector(setupControllers:)
  name:GCControllerDidDisconnectNotification object:nil];


と、接続、接続解除の通知を登録します。


コントローラーインスタンスの取得

上のsetupControllerメソッドでNSArray形式で取得していますが、
同様の方法で、どこでも[GCController controllers]で取得出来ます。

取得したNSArrayから、

GCController *controller = [controllers objectAtIndex:0];
controller.gamepad

で、ゲームパッドが取得出来ます。

拡張ゲームパッドど、独立拡張ゲームパッドは

controller.extendedGamepad

から取得出来ます。


値のタイプ

GCControllerButtonInputには、それぞれ、

BOOL pressed;
float value;

という2つの値が割り当てられています。
pressedは押されているかの判定、
valueは押されている強さ(0.0 ~ 1.0)の値で返って来ます。

また、十字キーや3Dスティックのクラス
GCControllerDirectionPadには、

GCControllerButtonInput *up, *down, *left, *right;
GCControllerAxisInput *xAxis, *yAxis;

が割り当てられていて、
GCControllerAxisInputの値はfloatの-1.0から1.0の値で取得する事が出来ます。


値の読み方

ゲームパッドの値を読み込むには、

  • ゲームのメインループで毎回読み込む
  • ゲームパッドの状態が変わった時に呼ぶハンドラを設定する
  • 波動拳を出す為に、ゲームパッドの状態を保存して、差分を確認する

と3つの方法があります。


メインループで取得するには、そのままコントローラの状態を取得出来ます。

-(void)update
{ 
  // Using Extended Gamepad controller
  GCExtendedGamePad *profile = self.myController.extendedGamepad;
  // Take actions for triggers
  if (profile.rightTrigger.isPressed)
    [self fireLasers];
  if (profile.leftTrigger.isPressed)
    [self launchMissiles];
  // Apply thrust based on Y value of thumbstick
  [self applyThrust: profile.leftThumbstick.yAxis.value];
}

のような方法で読む事が出来ます。

ゲームパッドの状態が変わった時に呼ぶには、ハンドラを設定します。
設定方法は

-(void)setupHandlers
{
  // Using extended gamepad profile
  GCExtendedGamepad *profile = self.myController.extendedGamepad;
  // Set up callback for right trigger
  profile.rightTrigger.valueChangedHandler = 
    ^(GCControllerButtonInput *button, float value, BOOL pressed)
  {
    // Take action if pressed
    if (pressed)
      [self fireLasers];
  };
}


ゲームパッドの状態を保存して、保存したゲームパッドの状態を読み込むには、

- (BOOL)writeSnapshotToFile:(NSString *)filePath
{
  // Grab snapshot
  GCGamepadSnapshot *snapshot = [self.myController.gamepad saveSnapshot];
  // NSData representation of snapshot
  NSData *snapshotData = snapshot.snapshotData;
  // Save data to file
  return [snapshotData writeToFile:filePath atomically:YES];
}

- (GCGamepadSnapshot *)snapshotFromFile:(NSString *)filePath
{
  // Read data from file
  NSData *data = (NSData *)[NSData dataWithContentsOfFile:filePath];
  // Init snapshot
  GCGamepadSnapshot *snapshot =
  [[GCGamepadSnapshot alloc] initWithSnapshotData:data];
  return snapshot;
}


参考:Integrating with Game Controllers