Siv3DでWiiリモコンを使う


これは、Siv3D Advent Calendar 2017 10 日目の記事です。

きっかけ

1年ほど前、Wiiリモコンをレーザーポインターのように使って見たいと思ったのが
Wiiリモコンについて調べ始めたきっかけでした。
Wiiリモコンは実は、Bluetoothで通信しているのでパソコンで使うこともできます。
当時は、「WiimoteLib」というライブラリを使って、
C#でスライドを切り替えられるアプリを作りました。
WiimoteLibはWiiリモコンだけでなく、バランスWiiボードなどの拡張コントローラにも対応しており、
とても使いやすかったです。
その後、Siv3Dでゲームを作るようになりWiiリモコンをコントローラとして使ってみたくなりました。
ライブラリを調べたのですが、動作すらしなかったり使いづらかったりとイマイチだったので、
自分で作ってみようと思うようになり、実際に作っちゃいました。

「wm4s3d」について

wm4s3d (https://github.com/oyakodon/wm4s3d)


YouTube

Siv3DでWiiリモコンを使うためのプログラムです。

  • Wiimote
  • wm4s3d

の二つに分かれており、Wiimote単体だとSiv3D無しでも使うことができます。
「Wiimote.cpp&hpp」と「wm4s3d.cpp&hpp」をプロジェクトに追加し、
「wm4s3d.hpp」をインクルードすると使えるようになります。

追記

このプログラムは、MurakamiShun様のプログラムに大きな影響を受けています。
私は、こちらのプログラムに音を出す機能と自動ペアリング機能を付けて少し形を整えただけです。
おかげで、部活で使用したり等することができます、ありがとうございます。
事前の連絡なしの利用、また後々の追記になってしまい、申し訳ありません。

主な機能

1. WiiリモコンをPCに自動でペアリング

// #include "wm4s3d.hpp"

Wii wii;
Wiimote::startScan();

とするとWiiリモコンのスキャンを開始します。
ここでWiiリモコンの1+2ボタンを押してしばらく待つと、自動でプログラムで使える状態にしてくれます。

#include <Siv3D.hpp>
#include "wm4s3d.hpp"

void Main()
{
  Wii wii;
  const Font font(30);

  while(System::Update())
  {
    if (Wiimote::waitConnect(4))
    {
      // 待っている間の処理
      font(L"接続待機中...").draw();
      continue;
    }

    // 接続していたらここから下を実行
    font(L"Aボタン: ", wii.buttonA.pressed).draw();

    wii.update();
  }
}

台数を指定してその台数接続されるまで待つこともできます。

2. Wiiリモコンのボタンや加速度、ポインター、ヌンチャク等の状態の取得・設定

wii.update(); // 状態を更新するために必要です。メインループ中に一回呼び出してください。

// ボタンの状態(clicked / pressed / released / pressedDuration)
wii.buttonA.clicked
wii.buttonB.pressed
wii.buttonPlus.released
wii.buttonMinus.pressedDuration

wii.controller.acc.x // Wiiリモコンの加速度
wii.rumble(10); // 10ms振動させる
wii.setLED(3, true); // 右端のLEDを点灯させる (LED左から0,1,2,3)

wii.getPointerInWindow() // ウィンドウサイズに合わせてポインターの座標を返す(Pointで)

// ヌンチャク
wii.isNunchukConnected() // ヌンチャクが接続されているかどうか
wii.buttonC.pressed

Wiiリモコンのボタンや3軸加速度センサ・ポインターの座標の情報を取得したり、
振動・プレイヤーインジケータ(LED)を設定することができます。
外部拡張コネクタにヌンチャクが接続されているときは、ヌンチャクの
加速度とボタン・ジョイスティックの状態を取得することができます。

3. Wiiリモコンのスピーカーから音を出す

多くのライブラリでは対応していなく、個人的に実装に苦労したのがスピーカーから音を出す機能です。
苦労した割に音質が悪く、そんなに使わないかもしれませんが。

wii.controller.playSound("sample.raw", 100);

とすると音を再生することができます。
"sample.raw"はファイル名です。
8bit符号付きPCMでサンプリングレート2kHz、モノラルの音じゃないと再生できず、
うまく再生できる音と再生できない音があります。
100の部分は音量です。0-100の範囲で指定します。

自作センサーバーを使ってポインター操作

Wiiリモコンで画像のようにポインター操作したい、と思ってもセンサーバーが必要です。
だからといってWiiが起動していないと操作できないというのも不便なので、センサーバーを自作してみました。1

外観 中身

というのも、センサーバー、実はただの赤外線LEDが左右に5個ずつついているだけのシンプルな構造なんです。
制作したセンサーバーでは、USBから電源を取ってきて左右3個ずつのLEDを点灯させています。
Wiiリモコンは先端のCMOSセンサ(カメラ)でLEDを検出し、Wiiはその情報を使ってポインターを表示させていたわけです。

wm4s3dでは、ウィンドウサイズに合わせてポインターの座標を返す関数wii.getPointerInWindow()があるので、
これを使ってこんなコードで画像のようにポインターを表示することができます。

#include <Siv3D.hpp>
#include "wm4s3d.hpp"

void Main()
{
    const Font font(30);
    Wii wii;

    while (System::Update())
    {
        if (Wiimote::waitConnect(1))
        {
            font(L"Wiiリモコンの接続待機中...").draw();
            continue;
        }

        wii.setLED(0, true);

        font(L"ようこそ、Siv3D の世界へ!").draw();

        Circle(wii.getPointerInWindow(), 15).draw({ 255, 0, 0, 127 });

        wii.update();
    }
}

Wiiリモコンを使ったゲーム制作

最近、学園祭的なところで、急ピッチで1,2日でWiiリモコンを使ったゲームを作って展示しました。
このゲームは、ポインターを使って金魚すくいをするゲームです。


YouTube

今、このゲームを古いwm4s3dから新しいものに書き換えたり、2人プレーに対応させたり、
シーンに分けたりゲームモードを追加したりしていて、完成したらGitHubで公開したいと思っています。

最後に

Wiiリモコンは誕生から既に11年が経過しているものの、様々な用途に応用できる可能性を秘めています。
皆さんもWiiリモコンで遊んでみてはいかがでしょうか。

明日は、para7さんです。
よろしくお願いします。

読んでいただいて、ありがとうございました。


  1. センサーバーを作る部分は、自分のブログで紹介しています。 (http://donlab.oykdn.com/2018/01/31/make-wiimote-sensorbar/