iPhone/AndroidのブラウザからWebSocketを使ってUnityのゲーム操作を行う


はじめに
======

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でもおそらく大丈夫です


構成
=====

今回の構成を簡単に描くとこんな感じになります。

![名称未設定_key.png](https://qiita-image-store.s3.amazonaws.com/0/11124/c55b8eff-a8b9-c587-6cb6-3c5e45bc5fdf.png "名称未設定_key.png")

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` を実行すると、最初

![demo_unity_-_aa_-_Web_Player.png](https://qiita-image-store.s3.amazonaws.com/0/11124/fad19b6c-e175-9766-87c9-1a62f23bd27f.png "demo_unity_-_aa_-_Web_Player.png")

というような画面が表示されるので、そこのURLに iPhoneやAndroidでアクセスすると、

![demo_unity_-_aa_-_PC__Mac___Linux_Standalone.png](https://qiita-image-store.s3.amazonaws.com/0/11124/68bdf258-4289-060b-fc6d-04046aae6034.png "demo_unity_-_aa_-_PC__Mac___Linux_Standalone.png")

という表示に変わります。意味としては
* 画面上のTouch位置 (X, Y): (0,0)が中心。-1 ~ 1の値。
* スマートフォンの傾き (X, Y, Z): どの軸がどれって書きにくいので割愛しますすが -1 ~ 1の値をとる傾きです。


API
----

このコードをみてもらうとわかるんじゃないかと思いますが、 `SmartPhoneInput` の static method で、
* (PadX, PadY) -> 画面上のTouch位置
* (PadGradX, PadGradY,PadGradZ) -> 傾き
を表します。

```csharp:DebugDisplay.cs
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の２画面みたいで

JavaScriptのコード的に汚いですが、、、どんまい。

通信内容
------

WebSocketでの通信内容ですが、 ブラウザ → Unity に対してコンマ区切りの文字列で５個の数値を渡しています。
ただ、ここでは -100~100 の整数を送っています。最初、なんか実数を送ると無駄に文字数が増えるなーと思ってそうしていますが、今となってみては気にすることも無いようにも思えて微妙な気もします。

さいごに
====

ちょっといじると、複数スマートフォンを同時接続できて、複数プレイとかもできると思います。
弾を撃つとかもどうにかUIを割り当てたいですねー。