読者です 読者をやめる 読者になる 読者になる

WonderPlanet DEVELOPER BLOG

ワンダープラネットの開発者ブログです。モバイルゲーム開発情報を発信。

MFi Game Controllersに対応してみよう!

今回のエンジニアブログを担当する村田です。

本日はiOS7で追加された「MFi Game Controllers」について紹介します。
「MFi Game Controllers」はiOS7で追加された機能にも関わらず、
これについて書かれた記事を目にする事はあまりありません。何だか残念です。

MFi Game Controllersとは?

簡単に言いますと、AppleにはMFi Programというものがあり、このMFiライセンスに対応したGame ControllersのことをMFi Game Controllersと呼びます。

国内ではLogicool社から「G550 Powershell controller + battery」という製品が発売されております。
まだ少ないのが現状です。

MFi Game Controllers対応アプリ

Logicool社のホームページ情報によると、G550に対応したアプリは170以上はあるようです。
※ Logicool社による G550に対応したアプリ一覧

最近では「MONSTER HUNTER PORTABLE 2nd G for iOS」が、MFi Game Controllersに対応されております。
スクウェア・エニックスの「ファイナルファンタジー」シリーズが随時対応していくニュースも話題になったかと思います。

徐々にではありますが、MFi Game Controllers対応アプリが増えてきております。

MFi Game Controllers対応アプリの作り方

ここからは、MFi Game Controllers対応アプリの作成手順を説明します。

1. 必要なフレームワークの追加
MFi Game Controllersからの入力をプログラムで受け取るには、
「GameController.framework」が必要です。
Xcodeのプロジェクト設定 - [General] から追加します。

あとは 「GameController.framework」内のGameController.hファイルをimportすれば、関連するクラスは全て扱えます。
【使用例】

#import <UIKit/UIKit.h>  
#import <GameController/GameController.h>  
  
@interface AppDelegate : UIResponder <UIApplicationDelegate>  

2. MFi Game Controllersの接続/切断の通知
MFi Game Controllersが接続/切断されたイベントを受け取りたい場合は、
NSNotificationCenterクラスに通知を登録します。

NSNotificationCenter* center = [NSNotificationCenter defaultCenter];  
  
// 接続されたときの通知を登録  
[ center addObserver:self  
            selector:@selector(setupControllers:)  
                name:GCControllerDidConnectNotification  
              object:nil];  
  
// 切断されたときの通知を登録  
[ center addObserver:self  
            selector:@selector(setupControllers:)  
                name:GCControllerDidDisconnectNotification  
              object:nil];  

Appleのドキュメントでは、
 -application:didFinishLaunchingWithOptions:

で、通知の登録を行いましょうと記載されております。

3. MFi Game Controllersのエントリポイントの取得
現在接続されているMFi Game Controllersを取得する場合は、
GCControllerクラスに定義されたcontrollersというstaticなメソッドを呼び出します。

@interface GCController : NSObject  
+ (NSArray *)controllers  
...  

戻り値のNSArrayには現在接続されているゲームコントローラーが、GCControllerクラスのインスタンスとして格納されます。

【使用例】

- (void)setupControllers:(NSNotification *)notification  
{  
  // Controllersを取得  
  self.controllerArray = [GCController controllers];  
    
  if ([self.controllerArray count] > 0) {  
    // 接続されたControllersがある場合  
  } else {  
    // 接続されたControllerが無い場合  
  }  
}  

4. MFi Game Controllersからの入力
まず、MFi Game Controllersには、2つのProfileが存在します。
1つは「Standard Gamepad Profile」、もう1つは「Extended Gamepad Profile」です。
「G550 Powershell controller + battery」は「Standard Gamepad Profile」になります。

今回は「Standard Gamepad Profile」を紹介します。「Standard Gamepad Profile」には、大きく3つの入力方法が存在します。
実際に「G550 Powershell controller + battery」の写真で確認してみましょう。
IMG_13132

  • LRボタンの『Shoulder buttons』
  • 十字キーの『D-pad』
  • ABCDボタンの『Face buttons』

ごく一般的なゲームコントローラーと同じ入力ですね。

では、これら入力方法の入力値の取得方法について、まずサンプルソースを見てみましょう。

// self.myControllerは、GCControllerのインスタンスです。  
// Shoulder buttons  
self.myController.gamepad.leftShoulder.pressed; // Lボタンが押されているか  
self.myController.gamepad.leftShoulder.value;   // Lボタンがどこくらい押されているか  
  
// D-pad  
self.myController.gamepad.dpad.up.pressed;   // 十字キーの上方向が押されているか  
self.myController.gamepad.dpad.up.value;     // 十字キーの上方向がどのくらい押されているか  
self.myController.gamepad.dpad.xAxis.value;  // 十字キーのX座標方向(左右の方向)にどう押されているか  
  
// Face buttons  
self.myController.gamepad.buttonY.pressed; // Yボタンが押されているか  
self.myController.gamepad.buttonY.value;   // Yボタンがどのくらい押されているか  

GCControllerにはgamepadプロパティがあり、GCGamepadクラスのインスタンスを取得できます。
GCGamepadから各入力方法へアクセスします。表にまとめると、このようになります。

入力方法プロパティ名タイプ
Shoulder buttonsleftShoulderButton Input
rightShoulder
D-paddpadDirectionPad
Face buttonsbuttonAButton Input
buttonB
buttonX
buttonY

プロパティ名が分かりやすいので、あまり迷う事はないかと思います。
タイプについて説明します。

タイプ:「Button Input」
「Button Input」では、2パターンの値を返します。

  • BOOL pressed;
    ボタンが押されたかを、BOOL値で取得。
  • float value;
    ボタンがどのくらい押されているか。値の範囲は、0.0〜1.0。

大抵、pressedのみで足りるかと思います。

タイプ:「DirectionPad」
「DirectionPad」では、まず入力の方向を取得し、その方向に対しての押し込み具合を返します。

  • GCControllerButtonInput *up, *down, *left, *right;
    上下左右を取得。
    • BOOL pressed;
      ボタンが押されたかを、BOOL値で取得。
    • float value;
      ボタンがどのくらい押されているか。値の範囲は、0.0〜1.0。
  • GCControllerAxisInput *xAxis, *yAxis;
    X軸、Y軸を取得。
    • float value;
      ボタンがどのくらい押されているか。値の範囲は、-1.0〜1.0。
      図で表すとこのようになります。
      Axis
      ニュートラルな状態が、0.0になります。

5. プログラムへの実装
MFi game controllersからの入力方法が分かれば、あとはプログラムに実装するだけです。
iOS、Objective-Cでゲームと言えば、SpriteKitです。
SpriteKitについては、こちらのブログをご覧下さい。

SpriteKitを使っている場合は
 - (void)update:(CFTimeInterval)currentTime
で使用します。

【使用例】

-(void)update:(CFTimeInterval)currentTime {  
    // AppDelegateで保持しているGCControllerからGCGamepadを取得  
    AppDelegate *delegate =  [UIApplication sharedApplication].delegate;  
    GCGamepad *pad = delegate.controller.gamepad;  
      
    // D-padの上ボタン押下時  
    if (pad.dpad.up.isPressed) {  
        self.spaceship.position = CGPointMake(self.spaceship.position.x,  
                                              self.spaceship.position.y + 5.0f);  
    }  
    // D-padの下ボタン押下時  
    if (pad.dpad.down.isPressed) {  
        self.spaceship.position = CGPointMake(self.spaceship.position.x,  
                                              self.spaceship.position.y - 5.0f);  
    }  
    // D-padの左ボタン押下時  
    if (pad.dpad.left.isPressed) {  
        self.spaceship.position = CGPointMake(self.spaceship.position.x - 5.0f,  
                                              self.spaceship.position.y);  
    }  
...  

self.spaceshipは、SpriteKit Gameのプロジェクトを作成すると存在するSpaceship.png画像になります。
使用例では、D-padを押した方向にSpaceship.png画像が移動します。

まとめ

調べる前は一見大変そうだなと思いましたが、調べてみると思いのほかMFi Game Controllers対応は簡単でした。
Apple DeveloperのWWDC 2013 Session Videosの中に「Integrating with Game Controllers」というセッションのドキュメントがありましたので、こちらが分かりやすく一番参考になりました。今回は説明しなかった、PauseボタンやLEDといったものの制御方法まで記載されております。

MFi Game Controllers製品は、まだまだ少ないですが、発売予定はあるので楽しみです。
特にWirelessタイプは、iPhoneとの接続が簡単で、サイズを問わないので楽しみです。