この章では木村秀敬さんのご協力により、WiiFlashをFlashやActionScript環境ではなく、Processingを使って利用する方法を解説してしていきます。
Processingは、マサチューセッツ工科大学のBen FryとCasey Reasによって開発されたフリーのプログラム開発環境です。映像を作り出す、インタラクティブな作品を作るといった用途に向いており、アーティストやデザイナーでも使いやすいように作られています。
【Processing】http://processing.org/
ベースはJava言語なので、Linux,Mac OS X,Windowsと多様な環境で動作します。Javaで開発というと、JDKをインストールしたり、コマンドラインを使った操作をしたりといったことが必要ではと思われてしまうかもしれませんが、Processingはそこの敷居を下げるための工夫がなされています。そのため、Javaはもとより、今までプログラミング言語を使ったことが無いという方にも向いています。
また、プログラムについても「スケッチ」という呼び方を用い,サッと書いてすぐに実行できる点を強調しています。Java言語の入門にありがちなおまじない的なプログラムは不要で、いきなり主目的となる部分から書き始めることができます。このあたりは、JavaというよりもPerlやPythonなどの軽量言語のイメージです。
このように簡単に使えるProcessingですが、低機能かというとそういう事はありません。カメラからの動画入力や、ネットワークとの通信、OpenGLを使った3Dプログラミングなど、たくさんの機能がライブラリによってサポートされています。WiiRemoteも例外ではありません。ProcessingからWiiRemoteを扱うためのライブラリとして、Wrj4P5というライブラリが用意されています。
【Wrj4P5】http://sourceforge.jp/projects/wrj4p5/wiki/FrontPage
しかしこのライブラリを使うために必要なBluetoothスタックなどがかなり限定されており、必ずしも全ての環境で動くとは限りません。特にWindows環境では動かないことが多いようです。
そこでWiiFlashの登場です。前章で紹介されている通り、WiiFlashはもともとFlashからWiiRemoteを扱うためのツール、ライブラリですが、実は他のプログラミング言語からも使うことが出来ます。一度仕組みさえ知ってしまえば、WiiFlashはWiiRemoteに対する汎用的なインタフェースとして機能します。
Processingも例外ではなく、netライブラリを使うことでWiiFlash経由でWiiRemoteを扱うことができるようになります。筆者の感覚では、WiiFlashのほうがWrj4P5よりも多くの環境で動作しているようなので、WiiFlashを使えばより多くの環境でProcessingからWiiRemoteを扱うことができるのではないかと思います。
ProcessingからWiiFlashを経由してWiiRemoteにつなぐために必要な環境は以下のとおりです。
ここでは、Processingのセットアップ方法と、WiiRemoteを扱うための方法について説明します。WiiFlashについては前章を参考にセットアップしてください。また、Processingそのものについての詳細な説明についても割愛します。
Processingのセットアップはとても簡単です。Processingのサイトから圧縮ファイルをダウンロードしてきて解凍するだけです。特にインストーラを使ってインストールするなどの作業は必要ありません。ダウンロードは以下のURLから行うことができます。http://processing.org/download/index.html
ここから、お使いのOSに合ったファイルをダウンロードしてください。Windowsについては注意書きにも書かれているとおり、特に理由が無ければ「Without Java」ではないほうをお勧めします。
なお、執筆時点での最新バージョンは11月29日公開の1.0.1ですので、以後の説明はこの1.0.1を対象とします。皆さんがこの文章を読まれているときの最新バージョンはすでに1.0.1ではなくなっているかもしれませんがご了承ください。
ダウンロードした圧縮ファイルを展開すると、以下のようなファイルが現れます。
あとはProcessing.exeを起動するだけです。起動中のスプラッシュウィンドウが表示された後、以下のような画面になれば成功です。
まずはWiiFlashを使わない、Processingそのもののサンプルを動かしてみましょう。試しにProcessingに付属しているMouse1Dというサンプルを動かすことにします。メニューから[File]の[Examples]を選択すると、とても多くのサンプルスケッチが用意されていることが分かります。この中から[Basics] - [Input] - [Mouse1D]を選択します。すると、50行ちょっとのスケッチが開かれます。
中身の理解は置いておいて、まずは実行してみましょう。左上のRunボタンを押すと、スケッチが実行されます。小さなウィンドウに2つの正方形が現れたでしょうか。マウスカーソルを左右に動かすと、それに反応して色やサイズが変化します。
一通りこのサンプルがどのような動作をするか理解したら、ウィンドウを閉じてスケッチのほうに目を向けてみます。Java言語やそれに近い言語を使ったことがある方なら、このスケッチがsetupメソッド、drawメソッド、updateメソッドの3つで構成されていることが分かるかと思います。
setupメソッドでは、ウィンドウサイズの設定などの初期化を行っています。drawメソッドでは、背景を塗りつぶし、マウスの位置に応じて2つの正方形を描く処理を行っています。updateメソッドでは、正方形の色や座標計算に使うパラメータを計算しています。
updateメソッド内の詳細な計算については特に理解しなくてもいいのですが、この引数にmouseXという変数を指定しているところに注目してください。mouseXとは、名前のとおり現在のマウスカーソルのX座標です。カーソル座標をupdateメソッドに渡すことによって、leftColor、rightColor、gx、gyといった変数に適切な値が設定されます。そしてそれらの値を使って正方形が描かれます。
さて、このサンプルではマウスカーソルのX座標が使われていますが、これをWiiRemoteを使って操作できないものでしょうか。ここからは、WiiFlashを使ってそれを実現する方法について説明します。
サンプルスケッチのMouse1DWiiを開いてみてください。これを動かすには、まずWiiFlashを起動する必要があります。前章を参考に、BluetoothでWiiRemoteを認識させ、WiiFlashを起動してください。正しくWiiFlashが起動したら、ProcessingのRunボタンを押してください。表示される画面はまったくMouse1Dと変わりませんが、WiiRemoteをひねるように回転させると、マウスカーソルを動かしたときのように画面が変化します。
それではスケッチについて詳しく見ていきましょう。スケッチには、以下のようにMouse1DWiiとWiimoteの2つのタブがあります。
Wiimoteのほうについては後で詳しく説明するので、まずはMouse1DWiiのほうに着目してください。
Mouse1DWiiは、元となっているMouse1Dを少し書き換えたものです。以下のように4行の追加、変更があります。
// 前略 float leftColor = 0.0; float rightColor = 0.0; Wiimote wiimote; ..... (1) WiiRemoteを使うための変数 void setup(){ size(200, 200); colorMode(RGB, 1.0); noStroke(); wiimote = new Wiimote(this); ..... (2) 初期化 } void draw() { wiimote.update(); ..... (3) WiiRemoteからの入力を取り込む background(0.0); update((int)((wiimote.x + 1) * width / 2)); ..... (4) 加速度センサの値を使う // 後略
まず最初に、WiiFlash経由でWiiRemoteを使うため、Wiimote型のwiimoteという変数を定義しています(1)。setupメソッドでは、この変数を初期化しています(2)。
drawメソッドではまず、WiiRemoteからの入力を取り込むために、Wiimoteクラスのupdateメソッドを呼び出します(3)。updateメソッドの詳細にはここでは踏み込みませんが、これによって現在のWiiRemoteの加速度などのパラメータが使えるようになります。例えばWiiRemoteを正面に向けたときにひねる方向(X方向)の加速度は、wiimote.xという変数に入っています。
最後は加速度を描画する正方形のサイズに反映させる部分です(4)。元のMouse1Dでは、updateメソッドにマウスカーソルのX座標(mouseX)を渡していました。Mouse1DWiiでは、これにならう形でWiiRemoteのX方向の加速度を変換し、updateメソッドに渡しています。
X方向の加速度を表すwiimote.xは、完全に左に傾けたときに-1、逆に完全に右に傾けたときに1という値になります。勢いがついていたりするとこの範囲を超えますが、基本的には-1から1の範囲と考えて問題ありません。スケッチに書いたとおり、1を足して画面幅(width)をかけ、2で割れば、-1から1の範囲を0から画面幅の範囲に変換できます。
WiiRemoteをProcessingから使うためには、Wiimoteクラスを使います。Wiimoteクラスは、元のWiiFlashの実装を参考に筆者がオリジナルで作成したもので、動作については無保証とします。このWiimoteを使うためのステップは大きく分けて3つです。
newでWiimoteのコンストラクタを呼び出し、Wiimote型のインスタンスを作ります。このとき、内部ではWiiFlashとの接続が行われるので、WiiFlashが起動していないとここでエラーが発生し、以降の処理がうまくいきません。この処理は基本的に1度だけ呼べばいいので、setupメソッドの中で呼び出すのがよいでしょう。
Wiimote wiimote; // 変数の宣言 wiimote = new Wiimote(this); // setupメソッド内などで
Wiimoteのupdateメソッドを呼び出し、WiiRemoteから、WiiFlash経由でデータを取得します。この処理は一般的にはdrawメソッドの中で一度だけ行います。
// drawメソッド内などで wiimote.update();
一度updateメソッドを呼んでから次にupdateメソッドが呼び出されるまでは、WiiRemoteクラスから得られるWiiRemoteの状態は変わらないままです。
Wiimoteのxやyなどのフィールドを参照することで、現在のWiiRemoteの状態を知ることができます。主に用いられるのは、各方向の加速度と、ボタンの状態でしょう。
// (100, 100)の点からWiiRemoteの向きに応じて線を引く line(100, 100, 100 + wiimote.x * 50, 100 + wiimote.y * 50);
Wiimoteクラスを使って得られるデータは表の通りです。
フィールド名 | 型 | 意味 |
---|---|---|
x,y,z | float | 各軸加速度。-1〜+1の値をとり、1Gの時に値が1となる。 |
one,two,a,b,plus,minus,home,up,down,right,left | Button | それぞれのボタンの状態 |
batteryLevel | float | バッテリーの残量 |
extensionType | int | 拡張コントローラのタイプ |
ボタン関連のフィールドは、Buttonクラスを使って表されています。Buttonクラスには、pressedとpushedの2つのboolean変数があります。
これら2つの変数タイプをうまく使い分けてください。
// 上下ボタンが押されている間パラメータを上下させる if (wiimote.up.pressed) { someparam++; } else if (wiimote.down.pressed) { someparam--; } if (wiimote.a.pushed) { background(10); // Aボタンが押されたら画面を消去 }
WiiRemoteを応用したスケッチをつくるにあたって、1からProcessingのスケッチを組んでそれをWiiRemote対応にすると、Wiimoteを使うという点からフォーカスがずれてしまいます。幸い、Processingには多数のサンプルスケッチが添付されていますので、これらのうちいくつかをWiiRemote対応にすることで解説していきます。
ここでは、FireCube、Directional、LightsGL、SineWaveSignalの4つのスケッチをWiiRemoteに対応させた例について紹介します。WiiRemoteに対応させたスケッチは、元のサンプルスケッチと区別するために、名前の最後にWiiを付けています。
FireCubeは、炎が燃え上がるような複雑なエフェクトが100行程度で書かれたものです。このサンプルを、WiiRemoteを振れば振るほど炎が出てくるようにしてみました。サンプルはFireCubeWiiです。
drawの中では、加速度からpowerという値を計算しています。この値に応じて炎の出る量が変わります。
float power = sqrt(wiimote.x * wiimote.x + wiimote.y * wiimote.y + wiimote.z * wiimote.z); power = constrain(power - 1, 0.1, 1);
最初に計算しているのはWiiRemoteにかかっている加速度です。WiiRemoteが動かない状態では、この値が大体1になります。この状態では炎を出したくないので、次の行で1を引くとともに、constrainという関数を使って値を0.1から1の間に収めています。
ここで計算したpowerは、立方体と、下から上がってくる炎の初期値に設定します。詳しくはスケッチ中のpowerという変数を検索してみてください。
Directionalは、マウスカーソルの位置に応じてピンポン球のようなものがライトアップされるものです。これにWiiFlashから得られるX方向、Y方向の加速度を使うことで、あたかもWiiRemoteが懐中電灯になったかのような感覚が味わえます。
このスケッチでは、懐中電灯のような感覚を出すために、WiiRemoteのAボタンが押されているときだけ球が表示されるようにしています。下記のように、Aボタンが押されていればdrawメソッドから途中で抜け出します。
if (!wiimote.a.pressed) { return; }
光を当てる方向については、加速度の値をそのまま使っています。
directionalLight(204, 204, 204, wiimote.x, wiimote.y, -1);
最後は1つ変わったネタを取り上げます。WaveSignalWiiは今までのスケッチとは異なり、音を使ったスケッチです。元となっているスケッチは[Libaries] - [Minim (Sound)] - [SineWaveSignal]です。このスケッチを起動すると、プーというような音が鳴り出します。これは画面にも表示されている通り、いわゆる正弦波です。マウスカーソルを上下左右に動かすことで、音の高さ(ピッチ)が上下したり、ステレオの左右のバランス(パン)が移動したりするのが分かるでしょうか。
Processingでこのように音が鳴らせるのは、Minimというライブラリのおかげです。正弦波を表す変数を作り、ピッチやパンを指定するだけで、このように音を鳴らすことができます。
SineWaveSignalはその名の通り正弦波にしか対応していないのですが、これをWiiRemote対応させたWaveSignalWiiは、のこぎり波や矩形波にも対応させました。左右ボタンを押すことでこれらを切り替えることができます。また、上下ボタンで音量を変えることもできます。
また、向きを変えることでピッチやパンも変化します。上に向けると音が高く、下に向けると音が低くなります。左右方向に向けると、そちらの方から音が聞こえてくるようになります。
さて、ここまで特にこの話の詳細には踏み込んできませんでしたが、なぜProcessingからWiiFlashを使うことができるのでしょうか。答えはWiiFlashに添付されているソースコードの中にあります。
メインとなるソースコードは、Core/api/source-classes/org/wiiflashディレクトリの中にります。ここにあるのはWiiFlashそのもののソースコードではなく、FlashからWiiFlashにつなぐためのActionScript3のソースコードですが、これだけでWiiFlashの挙動を推測することができます。Wiimote.asとWiiSocket.asを見れば、基本的な挙動をつかむことができます。
WiiSocket.asでは、connectメソッドでlocalhostの19028番に接続しています。このことから、WiiFlashが19028番のポートを使ってサーバを立てていることが分かります。そしてソケットからデータを受信したときの処理はonSocketDataメソッドに書かれています。ここを見ると、データが80バイト単位で受信されていることが分かります。最初の1バイトはコントローラのIDとなっており、それ以降のデータはWiimoteクラスのupdateメソッドで読み込まれています。WiiFlashから送られてくる基本的なデータをまとめると、表のようになります。
基本データレイアウト
名前 | 位置 | 型 | 意味 |
index | 0 | byte | コントローラのID |
batteryLevel | 1 | byte | バッテリー残量 |
buttonState | 2 | ushort | ボタンの状態 |
x | 4 | float | X方向の加速度 |
y | 8 | float | Y方向の加速度 |
z | 12 | float | Z方向の加速度 |
extensionType | 16 | byte | 拡張タイプ |
拡張タイプには、ヌンチャク、クラシックコントローラ、バランスボードがあります。このタイプによって、17バイト目以降のデータの解釈方法が変わります。これらについてはNunchuk.as、ClassicController.as、BalanceBoard.asを見るとデータの内容が分かりますが、本書ではそれらについての説明は割愛します。
ProcessingからWiiFlashにつなぐためには、netライブラリのClientクラスを使います。Clientクラスを使うことで、ソケットを使ってWiiFlashと通信することができます。つないだ後は、readメソッドなどを使うことでWiiFlashからバイト列を読み込むことができます。
Wiimoteクラスの詳細な実装については本章では述べませんが、ソースコードは見られる状態となっているので、気になる方はそちらを参照してください。