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

雑念日記

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

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

関連記事。


ゲームパッドを買ったので、普段いろいろお世話になっているProcessingさんでも使えるようにしてみました。
ちなみに買ったのはコレ。

iBUFFALO USBゲームパッド 8ボタン スーパーファミコン風 グレー BSGP801GY

iBUFFALO USBゲームパッド 8ボタン スーパーファミコン風 グレー BSGP801GY

握り具合や見た目の懐かしい感がいいっす。

Linuxゲームパッドを使う方法

そもそもこれがまずできていなかったので調査。
このへんは世の中に先人がたくさんいるので参考にさせていただきましょう。

Processingでゲームパッドを使う方法

GameControlPlus

調べたところ、GameControlPlusというライブラリを使うのが良さそう。
元々はproCONTROLLという名称だったようですが、processingのライブラリの命名規則に従って変更したものだそうな。

準備

インストールするには、Processingのエディタから Sketch -> Import Library -> Add Library と選択して、「game control」とか「joystick」とかで検索をかけると出てくるはずなので、「Install」を選択します。

リファレンスやProcessingのエディタから辿れるExampleなどを参考にしつつ、以下でテスト。

import org.gamecontrolplus.*;
import java.util.List;

ControlIO control;
List<ControlDevice> list;

control = ControlIO.getInstance(this);
list = control.getDevices();
println(list);

次の例のように出力結果で接続しているゲームパッドが検出されていれば成功。

[USB,2-axis 8-button gamepad  ]

なお、64bitのLinuxな人は次のような警告が出るかも知れません。

Java HotSpot(TM) 64-Bit Server VM warning: You have loaded library /path/to/sketchbook/libraries/GameControlPlus/library/libjinput-linux.so which might have disabled stack guard. The VM will try to fix the stack guard now.
It's highly recommended that you fix the library with 'execstack -c <libfile>', or link it with '-z noexecstack'.

このままでも問題無さげですが、気になる場合は上のメッセージで表示されたパスに、以下のような手順でlibjinput-linux64.soを配置しましょう。

https://github.com/samaaron/jinput

  $ wget https://github.com/samaaron/jinput/archive/master.zip
  $ unzip master.zip
  $ cp /path/to/sketchbook/libraries/GameControlPlus/library/libjinput-linux.so{,.orig}
  $ cp jinput-master/native/linux/x86_64/libjinput-linux64.so \
    /path/to/sketchbook/libraries/GameControlPlus/library/libjinput-linux.so

パーミッションの関係で以下のようなエラーメッセージが出る場合もあるようです。

Failed to open device (/dev/input/event16): Failed to open device /dev/input/event16 (13)

Failed to open device (/dev/input/event15): Failed to open device /dev/input/event15 (13)

Failed to open device (/dev/input/event14): Failed to open device /dev/input/event14 (13)
...
Failed to open device (/dev/input/event1): Failed to open device /dev/input/event1 (13)

Failed to open device (/dev/input/event0): Failed to open device /dev/input/event0 (13)

その場合は適切なソリューションかどうかわかっていませんが以下で解消できるようです。

  $ sudo chmod go=u /dev/input/event*

入力の検出

さて、ゲームパッドを利用する準備が整ったので、実際に入力を検出してみます。
以下のような感じでボタンを押しているかどうか、十字キーをどの方向に押しているか、が検出できました。

import org.gamecontrolplus.*;

ControlIO control;
ControlDevice device;

ControlButton button;
ControlSlider[] sliders = new ControlSlider[2];

void setup() {
  control = ControlIO.getInstance(this);

  // 名前を指定してデバイスを取得
  device = control.getDevice("USB,2-axis 8-button gamepad  ");

  // ボタンをひとつ取得
  button = device.getButton(0);

  // 十字キーを縦横それぞれ取得
  sliders[0] = device.getSlider(0);
  sliders[1] = device.getSlider(1);
}

void draw() {
  // ボタンが押された場合はtrue, そうでない場合はfalseを表示
  println(button.pressed());

  // 十字キーの右が押されたら1.0, 左が押されたら-1.0, それ以外は0.0
  println(sliders[0].getValue());

  // 十字キーの下が押されたら1.0, 上が押されたら-1.0, それ以外は0.0
  println(sliders[1].getValue());
}

ちなみにデバイスを取得する以下の部分ですが、

  // 名前を指定してデバイスを取得
  device = control.getDevice("USB,2-axis 8-button gamepad  ");

名前指定とかダサいし、上の例みたいに名前の末尾に半角スペース2個とか入ってるとワケわかんないとこでハマるし、汎用性ないしであんまりイイことがなさそう。

その場合は以下のようにすることもできます。

  // 接続されているデバイスの一覧を取得
  list = control.getDevices();
  // indexを指定してリストから特定のデバイスを取得
  device = list.get(0);
  // 有効化
  device.open();

ただgetDevices()で得られるデバイス一覧にはキーボードやマウスなども含まれる場合があるので、結局リストの中身を何らかの方法で選り分ける必要があります。あとgetDevice()したときとは異なり、取得したデバイスに対してopenメソッドを呼ぶ必要があります。

あるいは以下のように、dataディレクトリ以下に設定ファイルを用意して任意のデバイスを取得する方法もあります。

  // dataディレクトリ以下から"gamepad_config"という名前のファイルを探し、
  // その中身から適切なデバイスを探して返してくれる
  device = control.getMatchedDevice("gamepad_config");

この設定ファイルについてはまた後日整理して記事を書く予定です。

この記事を書くに至る経緯

余談ですが、最近ぼちぼちお遊びでゲームを作ったりしています。
基本的にRubyで作りたいのでDXRubyを使ったりしてるのですが、Windowsでのみ動くDXRubyのためにサブPCのWindowsマシンをいちいち使うのはめんどくさい。ので、自前のDXRubyRP5を使ってLinuxで開発→Windowsで動作確認、みたいなことをしています。
DXRubyRP5で本家DXrubyと同じように使える機能はかなり限られているのですが、たまたま今作っているゲームがそこまでたくさんのDXRubyのAPIを利用しないためにできる芸当です。

ゲームのシステム面がそこそこできてきたところで、テストプレイをする頻度も高くなってきたのですが、そこで操作性が悪いと結構ストレスがたまります。
せっかくDXRubyがデフォルトでゲームパッドを使えるので、テストプレイはゲームパッドでやろう、と思いつくも、DXRubyRP5はまだゲームパッドに対応しておらず...。

というわけで以下を実施する予定。

  1. Linuxゲームパッドを使う方法を調査 (完)
  2. Processingでゲームパッドを使う方法を調査 (途中)
  3. 調査結果を基にDXRubyRP5でのゲームパッド利用対応 (予定)
  4. DXRubyとDXRubyRP5の互換性が更に向上して(主に僕が)ハッピー! (予定)