UnityでOSCを使う方法がないか探してみたところここが、githubでコードを公開しているものがあった。
これを使ってUnityでOSCでメッセージを送受信してみます。Unityとの通信相手に今回はTouchOSCというiPhoneのアプリを使います。動作確認用なのでOSCアプリは何でも良いです。
環境構築
- UnityOSCをダウンロードUnityOSCのページの右下の方にあるDownload ZipをクリックしてUnityOSCをダウンロードします。pullしても良いけど。
- Unity空プロジェクトを作成し、展開したUnityOSCのフォルダをAssets下に適宜配置します。OSCController.csは今回使うサンプルスクリプト(後で解説)です。展開方法はどうでもいいけどOSCHelper.csはUnityのエディタ拡張のコードなのでEditorフォルダを作成し、必ずその下に置いてください。[Window] -> [OSC Helper]という感じで表示されるはず。
Assets/ Editor/ OSCHelper.cs OSC/ OSCBundle.cs OSCClient.cs OSCHandler.cs OSCMessage.cs OSCPacket.cs OSCServer.cs Scripts/ OSCController.cs // 今回自分で追加したファイル
- 空のGameObjectを作成して追加したOSCController.csを貼付けます。
コード修正
そのままでも良いですが、送信先のIPアドレスや送受信ポートの指定がコード内で行っていたのでこれをUnityのインスペクタビューから編集できるようにします。
OSCController.cs
OSCController.csというファイルをちゃっかり先ほど追加しましたが、これはフォルダに入っていたoscControl.csをベースにしたものです。StartのところでOSCHandlerのシングルトンを取得してInitしているのでそこで、ネットワーク情報を送るようにします。これらのネットワーク情報はクラスの冒頭でpublic変数にして定義しているので、インスペクタから直接編集できるようになります。
using UnityEngine; using System; using System.Collections; using System.Collections.Generic; using System.Text; using UnityOSC; public class OSCController : MonoBehaviour { #region Network Settings public string TargetAddr; public int OutGoingPort; public int InComingPort; #endregion private Dictionary<string, ServerLog> servers; // Script initialization void Start() { OSCHandler.Instance.Init(TargetAddr, OutGoingPort, InComingPort); servers = new Dictionary<string, ServerLog>(); } // NOTE: The received messages at each server are updated here // Hence, this update depends on your application architecture // How many frames per second or Update() calls per frame? void Update() { // must be called before you try to read value from osc server OSCHandler.Instance.UpdateLogs(); // データ受信部 servers = OSCHandler.Instance.Servers; foreach( KeyValuePair<string, ServerLog> item in servers ) { // If we have received at least one packet, // show the last received from the log in the Debug console if(item.Value.log.Count > 0) { int lastPacketIndex = item.Value.packets.Count - 1; UnityEngine.Debug.Log(String.Format("SERVER: {0} ADDRESS: {1} VALUE 0: {2}", item.Key, // Server name item.Value.packets[lastPacketIndex].Address, // OSC address item.Value.packets[lastPacketIndex].Data[0].ToString())); //First data value } } // データ送信部 if(Input.GetMouseButtonDown(0)) { Debug.Log("SendMessage"); var sampleVals = new List<int>(){1, 2, 3}; OSCHandler.Instance.SendMessageToClient("iPhoneTouchOSCApp", "/hoge/a", sampleVals); } } }
OSCHandler.cs
今まではここでネットワーク情報がべた書きでしたが、これはOSCController.csから指定するように変更します。といってもInit関数の引数を追加するだけです。あと少しわかりにくいですがCreateClientでUnityから送信する側、CreateServerでUnityで受信する側の設定になります。直感的に逆な気もしますが、よしとします。
public void Init(string targetAddr, int outGoingPort, int inComingPort) { //Initialize OSC clients (transmitters) // Sender CreateClient("iPhoneTouchOSCApp", IPAddress.Parse(targetAddr), outGoingPort); //Initialize OSC servers (listeners) // Receiver CreateServer("SomeOscClient", inComingPort); }
実行
[Window] -> [OSC Helper]でOSCHelperウインドウを見て実行!そうするとOSC Helperのエディタ上に設定した相手との通信状態が表示されます。コンソールにはTouchOSCから飛んで来た値が随時表示されるようになります。また、マウスをクリックするとOSCデータを相手のOSCクライアントに送信します。TouchOSCではデータを受信するとデータ送信部に光るアイコンの下が光るのでデータが飛んで来ていることがわかります。
おわり