サイトのトップへ戻る

libGDX ドキュメント 日本語訳

サイト内検索

コントローラー

ネイト氏と私は、ゲームパッドとジョイスティック用の新しい拡張の開発に取り組んできました。 その結果完成したのが gdx-controllersです。これは、初めてプラットフォームごとに異なるバックエンド実装を持った拡張です (他の拡張は大抵、単にクロスコンパイルされたJNIラッパーなだけで、各プラットフォーム上で同じコードを使います)。

この拡張の目標は、以下の機能を提供することです:

  • 接続されたコントローラーを列挙する
  • コントローラーごとのボタン、軸情報、スライダー、POV、加速度センサーをサポートする
  • 全体的に、もしくはコントローラーごとに、コントローラーイベントを受け取る。
  • コントローラーの状態をポーリングする

将来の拡張に備えて、我々はAPIを可能な限り小さくするよう努めています。 API は初期化する必要はなく、基礎となるバックエンドが自動的に初期化を行います。



コントローラーを列挙する

PCや端末には、コントローラーが1つ以上取り付けられていることがあります。 Controllersクラスには、現在接続されている端末を照会するメソッドがあります:

for (Controller controller : Controllers.getControllers()) {
    Gdx.app.log(TAG, controller.getName());
}

Controllers#getControllers()で取得した配列内のコントローラーの順番は、通常はコントローラーが接続されて順番になります。 しかし、この挙動を過信してはいけません。詳細は後述する端末の接続(および取り外し)の項目を参照してください。

Controllers クラスの全てのメソッドは、描写スレッド内、すなわちApplicationListenerの任意のメソッド内で実行しなければなりません。



コントローラーの状態をポーリングする

Controller のインスタンスを作成したら、そのコントローラーの状態を問い合わせることができます。 コントローラによって保有するコンポーネントは異なります:

  • ボタン: これは通常‘X’ボタンと‘Y’ボタンだけではなく、同一コントローラー上にある十字キーも含みます。ボタンは押されたり離されたりします。
  • 軸: 通常はアナログスティックを介して提供される。軸情報は-1~1の間の値を持っており、 with one being the neutral center position.
  • POVs (別名ハットスイッチ): 例えば北、西、南東などのような個別の向いている状態が提供されます。
  • スライダーと加速度センサー: これらはAPI内にありますが、現時点では未テストです。

古典的なコントローラーの例に XBox 360 コントローラーがあります:

It has a left and a right analogue stick, each with an x- and a y-axis, triggers on the back, each representing a single axis and various buttons and a d-pad, which might either be reported as buttons or as axes.

特定のコンポーネントの状態のポーリングを行うのは、とても簡単です:

boolean buttonPressed = controller.getButton(buttonCode);
float axisValue = controller.getAxis(axisCode);
...

各コンポーネントは独自のコード(キーコードやキーボードキーのスキャンコードのようなもの)を持っています。 このコードは、コントローラごとに固有のものを持っています。例えば、XBoxコントローラーのXボタンはおそらくPS3 コントローラーのXボタンとは違うコードを持っています。 この問題については後ほど説明します。



イベントベースのコントローラー入力

コントローラーをポーリングする場合、いくつかの入力イベントを見落とす可能性があります。 いくつかの処理では、ポーリングベースの入力よりもイベントベースの入力の方が適しています。 そのため我々は、全てのコントローラーもしくは特定のコントローラーのコントローラーイベントを受信するためのリスナーを登録する方法を用意しました。 コントローラーイベント受信するために実装する必要があるインタフェースの名前はControllerListenerです:

public interface ControllerListener {
    public void connected(Controller controller);
    public void disconnected(Controller controller);
    public boolean buttonDown (Controller controller, int buttonCode);
    public boolean buttonUp (Controller controller, int buttonCode);
    public boolean axisMoved (Controller controller, int axisCode, float value);
    public boolean povMoved (Controller controller, int povCode, PovDirection value);
    public boolean xSliderMoved (Controller controller, int sliderCode, boolean value);
    public boolean ySliderMoved (Controller controller, int sliderCode, boolean value);
    public boolean accelerometerMoved (Controller controller, int accelerometerCode, Vector3 value);
}

各メソッドでは、イベントを引き起こしたコントローラーのインスタンスを引数として受け取ります。 最初の二つのメソッドは、コントローラーが接続された時、取り外された時に呼び出されます。 次の二つのメソッドは、ボタンが押されたり離されたりした時のイベントを通知します。 両方とも、対象のボタンを識別するためのbuttonCodeを引数として受け取ります。 axisMoved メソッドは軸の値が変更された時などに呼び出されます。これは一目瞭然でしょう。

全てのコントローラーからのイベントを受け取る場合はControllersへControllerListener を追加し、特定のコントローラーからのみイベントを受け取る場合にはそのコントローラーへControllerListener を追加します:

Controllers.addListener(listener); // receives events from all controllers
controller.addListener(listener); // receives events only from this controller

これら全てのメソッドは実装せずに少数のメソッドのみを選んで実装した場合は、サブクラス ControllerAdapterを使用します。

controller.addListener(new ControllerAdapter() {
   @Override
   public void connected(Controller controller) {
      ...
   }

   public void disconnected(Controller controller) {
      ...
   }
};

リスナーメソッドのいくつかはboolean型の値を戻り値として返していることに気づいたでしょうか。 全体の、もしくは特定のコントローラーに複数のリスナーが登録されていた場合にこれが使われます。 これらのメソッドがfalseを戻り値として返した場合、そのイベントは次のリスナーへ渡されます。 メソッドがtrueを戻り値として返した場合は、イベントはそれ以上伝えられません。

普通のInputProcessorの場合と同じ様に、全てのリスナーメソッドは描写スレッド上で呼び出されます。



マッピングとコード

上述のように、コンポーネントが変わればコードも変わります。これらのコードは標準化されていないので、コントローラを扱う際に二つの選択肢を用意しました:

  • 例えばOuya コントローラーのような、特定のコントローラー用にコードをハードコーディングする
  • プレイヤーにコントローラーのボタン割り当てを設定させる。例えばゲーム内での各アクションを画面に表示し、操作を割り当てるボタン、軸、POVなどを押すようプレイヤーに求める。

今のところ、 Ouya コントローラーのボタンと軸に対応したコードは用意してあります。コントローラーがOuya コントローラーかどうかを確認するには、以下を実行します:

if(controller.getName().equals(Ouya.ID)) {
   // we know it's an Ouya controller, so we can use the Ouya codes
   float leftXAxis = controller.getAxis(Ouya.AXIS_LEFT_X);
   boolean oButton = controller.getButton(Ouya.BUTTON_O);
}

また、現在Ouya 端末上で動作しているかを確認することもできます:

if(Ouya.runningOnOuya) {
   // DO SOMETHING!
}

Ouya 製コントローラーは普通のAndroid 端末と組み合わせて使うこともできるので、アプリが実際にOuya 端末上で動いているかどうかを確認することも必要でしょう。

将来的には、例えばbox 360 と PS3コントローラーのような人気のあるコントローラーのマッピングをさらに追加する予定です。

OSによっては、同じ種類のコントローラーでもこれらのコードが変わる可能性があるので注意してください。 私が使っている安物のロジテック製コントローラーは、Windows環境ではx軸にはコード0が割り当てられ、Linux環境 と Mac OS X環境ではコード1が割り当てられます。 上記Ouya クラスのような、com.badlogic.gdx.controllers.mappings package内にあるマッピングとコードについては全てのOS上でコードが動作することを確認済みです。

最後に、自分のゲームパッドをどのように使いたいかユーザーに決めさせるのがベストです。 実際のアクションを表示してユーザーに割り当てるボタンを押させるための、シンプルな設定ダイアログを記述すれば簡単にできます。 これらのマッピング情報をコントローラーの名前と合わせてファイルに保存し、ユーザーが次に使う時にそのファイルを読み込んで再利用することができます。



コントローラーの接続 (および取り外し)

今のところ、コントローラーの接続(および取り外し)はデスクトップ環境とAndroid環境で通知されます。 あなたのゲームがゲームパットをサポートしている場合、端末の取り外しと接続を制御するようにして下さい! 例えば、ゲーム中にコントローラーが取り外された場合は、ゲームを一時停止してユーザーにコントローラーを再接続するよう求めます。 その場合は新規のController インスタンスを取得することになるので、リスナーを正しく設定する必要があることを忘れないでください。 古いcontroller インスタンスは取り外されたと通知されます。



プロジェクトへの組み込み

gdx-setup アプリで、 "Controllers"チェックボックスのチェックを入れるだけです。 LWJGL 3の場合、gdx-controllers-desktopへの依存は gdx-controllers-lwjgl3へ置き換えられ、 デスクトップの依存管理から compile "com.badlogicgames.gdx:gdx-controllers-platform:$gdxVersion:natives-desktop" が削除されます。



テストとデモ

現在接続されているコントローラーとイベントデータを表示できる、簡単なテストを作成しました。 名前はControllersTestです。 また、 gdx-invadersのデモを改良してOuya コントローラーをサポートしました。 これは突貫工事で仕上げた代物なので、コントローラーの取り外しの制御は行わず、設定オプションも用意されていないので注意してください。

前へ | 次へ