はじめに
OculusRift + Unityを使っていて、キャラをキーボードで操作、とかかなり辛いものがあります。
そこで、Oculusを持っている人なら必ず持っているであろう iPhone/Android と UnityをWebSocketで繋いで操作する方法を共有します。Oculusじゃなくても、スマートフォンで操作できるのは何かと使える機会もあるかな、と思います。
今回は 画面上のTouch位置(X,Y) と 端末の傾き(X,Y,Z) をUnityにリアルタイムに送って操作する というシチュエーションを考えます。
iPhone/Androidはそもそも加速度センサを持っていて傾きが検知できますし、画面上のどこをタッチしているかも取得できます。また、ここ数年のiPhone/AndroidはそれらがWebブラウザから利用できるので、アプリのUI側の構築もHTMLとJavaScriptがちょいちょいかければ作れて手軽で便利です。また、WebSocketによってそれなりにリアルタイムに通信できます。
各バージョン
動作確認した環境は以下になります。
- MacOSX 10.9.4 + Wifi
- Unity 4.5.3f3
- iPhone5S (iOS 8 beta)
###注意事項
- UnityのWebPlayerではこの機能は使えません 。Unity側がWebSocketのサーバになることができない(たぶん)からです。PC向けビルドでのみ使えます。
- 基本的に Mac と iPhone は同一のWifiに接続している必要があります(通信出来る必要がある)。
- Androidではテストしていません。きっと動かないでしょう(^^;; 。ちょっと修正すると動くようになるのではないかな、、、と思っていますが。。
- Macではなく、Windowsでもおそらく大丈夫です
構成
今回の構成を簡単に描くとこんな感じになります。
SourceCode
下記にSource Codeを置いてあります。
https://github.com/mokemokechicken/UnitySmartPhoneInputController
導入の仕方
上記githubをcloneして、
SmartPhoneInputController.unitypackage
を実行してください。
Projectにファイルが追加されるます。
Assets/SmartPhoneInputController/Prefabs/
に
SmartPhoneInput.prefab
というのがあるので、それをSceneに追加しましょう。
Debug用のGUITextの SmartPhoneControllGUIText.prefab
もSceneに追加して Postion=(0,1,0)にすると左上に表示されると思います。
Demo
Assets/SmartPhoneInputController/demo.unity
を実行すると、最初
というような画面が表示されるので、そこのURLに iPhoneやAndroidでアクセスすると、
という表示に変わります。意味としては
- 画面上のTouch位置 (X, Y): (0,0)が中心。-1 ~ 1の値。
- スマートフォンの傾き (X, Y, Z): どの軸がどれって書きにくいので割愛しますすが -1 ~ 1の値をとる傾きです。
API
このコードをみてもらうとわかるんじゃないかと思いますが、 SmartPhoneInput
の static method で、
- (PadX, PadY) -> 画面上のTouch位置
- (PadGradX, PadGradY,PadGradZ) -> 傾き
を表します。
public class DebugDisplay : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
string msg = "";
if (SmartPhoneInput.IsConnected()) {
msg += "Connected, ";
msg += "(" + SmartPhoneInput.PadX + "," + SmartPhoneInput.PadY + ")";
msg += "(" + SmartPhoneInput.PadGradX + "," + SmartPhoneInput.PadGradY + "," + SmartPhoneInput.PadGradZ + ")";
} else {
msg += "Disconnected: Please Access " + SmartPhoneController.WebUrl;
}
guiText.text = msg;
}
}
中の仕組み
WebSocket
Unity側でサーバサイドのWebSocketを実装する必要がありますが、
https://github.com/sta/websocket-sharp を使わせてもらっています。これすごく使いやすいです。
これをUnityで使うときは websocket-sharp の部分だけをBuildして、出てきた websocket-sharp.dll
をAssetsフォルダに追加すればOKです。今回DLLをGitの中に同梱してあります。もし、Windowsなどで不具合が起きるようなら再度buildして、dllを置き換えたりしてみてください。
JavaScript in Webページ の配布
スマートフォンで表示するWebページは、どこから取得しても良い(WebSocketには originルールとか無いので)のですが、別途Webサーバを立てたりするのも面倒なので、それもUnityにさせています。
HTML自体は、 Assets/Resources/SmartPhoneInputController/ws.html
にあります。
「Androidで動かねー!!」という場合はこれをいじってみてください。
※ 動いたら是非Pull Request下さい (^^;
スマートフォンからUnityへの送信間隔もここで setTimeout
しているだけなので、適宜調節してみてください。今は 100msくらい間隔を開けています。
見た目とか表示内容とかもいじると何かと楽しそうです。# DSの2画面みたいで
JavaScriptのコード的に汚いですが、、、どんまい。
通信内容
WebSocketでの通信内容ですが、 ブラウザ → Unity に対してコンマ区切りの文字列で5個の数値を渡しています。
ただ、ここでは -100~100 の整数を送っています。最初、なんか実数を送ると無駄に文字数が増えるなーと思ってそうしていますが、今となってみては気にすることも無いようにも思えて微妙な気もします。
さいごに
ちょっといじると、複数スマートフォンを同時接続できて、複数プレイとかもできると思います。
弾を撃つとかもどうにかUIを割り当てたいですねー。