雑念日記

主に技術的なことをつらとらと(書ければいいな)。

Processingでゲームパッドを使おう (その4)

関連記事。


これまで過去記事でGameControlPlusを使ってゲームパッドを扱う方法を書いてきましたが、いずれも自分(開発者)だけが自分のために使うような方法ばかりでした。
予め使用するゲームパッドの詳細を調べた上で設定ファイルを書いておく、だとか、アプリ起動時に以下のようなゲームパッドの設定画面が表示されるので画面に従って設定をする、だとか。

f:id:hoshi_sano:20140612024357j:plain

しかし汎用的にいろんな人に使ってもらうようなアプリを作ろうと思ったら、これらの手順はウラでやっておきたいこと、表に出したくないことだったりします。
とにかくアプリを起動したらすぐゲームパッドを使えるような状況にしたい!必要ならキーコンフィグ画面はアプリ側で作るから!みたいな需要もあるはず。

それを実現してみたのが以下。

import org.gamecontrolplus.*;
import java.util.List;
import net.java.games.input.Controller;

ControlIO control;
ControlDevice device;
ControlButton[] buttons;

// 取得対象デバイス候補となるタイプの一覧
// ここでは "Stick", "Fingerstick", "Gamepad" が対象となる
List<String> deviceTypeCandidates = new ArrayList<String>() {
  {
    add(Controller.Type.STICK.toString());
    add(Controller.Type.FINGERSTICK.toString());
    add(Controller.Type.GAMEPAD.toString());
  }
};

void setup() {
  control = ControlIO.getInstance(this);
  List<ControlDevice> deviceList = control.getDevices();

  // 利用可能なデバイスのうち、取得対象タイプに含まれるもので
  // 一番最初に見つかったものを取得・有効化
  for (ControlDevice dev : deviceList) {
    String type = dev.getTypeName();
    if (deviceTypeCandidates.contains(type)) {
      device = dev;
      device.open();
      break;
    }
  }

  if (device == null) {
    println("ERROR: No available devices found.");
    return;
  }

  // 取得したデバイスが持つボタンをすべて取得して配列に持つ
  // ボタンを押したときに pressButton() が呼び出されるようにする
  int buttonNum = device.getNumberOfButtons();
  buttons = new ControlButton[buttonNum];
  for (int i = 0; i < buttonNum; i++) {
    buttons[i] = device.getButton(i);
    buttons[i].plug(this, "pressButton", ControlIO.ON_PRESS);
  }
}

// 押されたボタンの名前を表示する
void pressButton() {
  for (ControlButton b : buttons) {
    if (b.pressed()) println("PRESSED: ", b.getName());
  }
}

void draw() {
  // 入力待ち
}

ちょっとした解説

以下の行でこのコードを走らせているマシンで利用可能なデバイスのリストが取得できるため、

  List<ControlDevice> deviceList = control.getDevices();

このリストの中からゲームパッドを探します。
それが次の部分です。

  for (ControlDevice dev : deviceList) {
    String type = dev.getTypeName();
    if (deviceTypeCandidates.contains(type)) {
      ...

getTypeName()メソッドでデバイスのタイプが取得できるため、リストに含まれるデバイス1個1個に対し、そのタイプが取得候補に含まれるかどうかをチェックしています。
ちなみに今回、取得候補はSTICK, FINGERSTICK, GAMEPADとしましたが、それ以外に使われるタイプとしてはUNKNOWN, MOUSE, KEYBOARD, HEADTRACKER, RUDDER, TRACKBALL, TRACKPAD, WHEELがあるようです。

その後、ゲームパッドかそれに近いデバイスが見つからなかったら処理を中断。見つかったら以下の部分でそのデバイスのボタンの数を取得し、

  int buttonNum = device.getNumberOfButtons();

そのボタン全てに対してイベントハンドラを登録します(その3参照)。

    buttons[i].plug(this, "pressButton", ControlIO.ON_PRESS);

欠点

動的にボタンを取得するので、どの変数がどのボタンに割り当てられるかがまったくわかりません。機器依存になりそうです。前述してますが、ひとまずゲームパッドとそのボタンを認識する、というところまでをアプリ起動時に動的にやってしまい、ボタンとイベントの関連付けはアプリ内でやる、という用途に適しているんじゃないかなーと思います。