UnityOSCについて学ぶ

#はじめに
今回はUnityOSCの学習がてらクライアントからサーバへのデータ送信を伴う簡単なアプリケーションを作ってみました。即興なのでアプリのクオリティは悪しからず笑

#OSCとは
OSC（Open Sound Control）とは通信プロトコルの一種で、本来は電子楽器の制御に使われていたましたが、今ではその他にも様々な用途に使われているらしいです。クライアントからサーバにデータを送信するようなアプリケーションでは有効な手段の１つだと思います。UnityにもOSC通信を行うためのパッケージがあるようなので、今回はそのうちの１つを使ってみました。

#作成したアプリケーション
**クライアント側**
はじめにサーバ側のPCのIPアドレスと使用するポート番号を入力します。
Startボタンを押したらゲームスタートです！
<img width="705" alt="スクリーンショット 2019-01-12 22.26.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/245462/2a6233ea-a843-8090-3820-50034c448e8e.png">

この画面になったら１〜９の数字を入力します。
<img width="703" alt="スクリーンショット 2019-01-12 22.27.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/245462/5ad946b4-49ea-e0a3-0cde-57d07ad60bf9.png">

**サーバ側**
こちらではクライアント側で入力した数字に対応した部分が黄色に変化します。
全てが黄色に変わると全て白に戻ります。
<img width="705" alt="スクリーンショット 2019-01-12 22.27.58.png" src="https://qiita-image-store.s3.amazonaws.com/0/245462/a87c6517-5b00-e81f-f222-b504da39f945.png">

それでは早速UnityOSCを使うための準備から始めましょう！

#準備
[jorgegarcia/UnityOSC](https://github.com/jorgegarcia/UnityOSC)をダウンロードします。
その中のsrcフォルダをUnityのプロジェクトのAssetsフォルダにインポートします。
これをクライアント側とサーバ側両方で行なったら準備は完了です！

#実装
それではクライアント側とサーバ側に分けて実装の説明をしていきます。

##クライアント側
まずクライアントからです。
はじめにインポートしたsrcフォルダの中にあるOSCHandler.csのInit関数を編集します。
InputFieldに入力したIPアドレスとポート番号を取得しipNumとportNumに代入しています。

```cs:OSCHandler.cs
public void Init()
{
    string ipNum = FindObjectOfType<GameController>().ip;
    int portNum = FindObjectOfType<GameController>().port;
    //Initialize OSC clients (transmitters)
    //Example:		
    CreateClient("OSCClientTest", IPAddress.Parse(ipNum), portNum);

    //Initialize OSC servers (listeners)
    //Example:
    //CreateServer("OSCTest", 8001);
    }
```

続いてOSCClientTest.csという新たなスクリプトを作成します。
キーボードで押した数字をサーバ側に送信するためのスクリプトです。

```cs:OSCClientTest.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityOSC;

public class OSCClientTest : MonoBehaviour
{

    bool startFlag = false;
    void Start()
    {
        startFlag = FindObjectOfType<GameController>().flag;
        OSCHandler.Instance.Init();
    }

    void Update()
    {
        // ゲームがスタートしてから送信可能になる
        if (startFlag)
        {
            if (Input.anyKeyDown)
            {
                string inputStr = Input.inputString;
                string allNumStr = "0123456789";
                if (allNumStr.Contains(inputStr))
                {
                    Debug.Log(inputStr + " is pressed");
                    int sentInt;
                    int.TryParse(inputStr, out sentInt);
                    OSCHandler.Instance.SendMessageToClient("OSCClientTest", "/Int", sentInt);
                }
            }
        }
    }
}
```

これは本質的ではないですが、InputFieldにIPアドレスとポート番号を入力してゲームを始めるまでの部分を管理するスクリプトです。

```cs:GameController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class GameController : MonoBehaviour {
    
    public InputField ipField;
    public InputField portField;
    public Button startButton;
    public GameObject client;
    public GameObject canvas2;

    public string ip;
    public int port;

    public bool flag = false;

	void Start () {
        startButton.onClick.AddListener(ConnectToServer);
	}

    // IPアドレスとポート番号を入力してサーバと接続する関数
    public void ConnectToServer()
    {
        ip = ipField.text;
        port = int.Parse(portField.text);
        flag = true;
        GameObject.Find("Canvas").SetActive(false);
        canvas2.SetActive(true);
        client.SetActive(true);
    }
}
```

##サーバ側
次にサーバ側です。
クライアント側と同じくOSCHandler.csを以下のように編集します。

```cs:OSCHandler.cs
public void Init()
	{
        //Initialize OSC clients (transmitters)
        //Example:		
        //CreateClient("SuperCollider", IPAddress.Parse("127.0.0.1"), 5555);

        //Initialize OSC servers (listeners)
        //Example:

        CreateServer("OSCServerTest", 8001);
    }
```

クライアントから送信されたデータを受信するスクリプトOSCServerTest.csを作成します。

```cs:OSCServerTest.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityOSC;

public class OSCServsrTest : MonoBehaviour {

    public Image[] images;
    string s1 = "123456789";

    int currentDataLen = 0;

	void Start () {
        OSCHandler.Instance.Init();
	}

    void Update()
    {
        OSCHandler.Instance.UpdateLogs();
        Dictionary<string, ServerLog> servers = new Dictionary<string, ServerLog>();
        servers = OSCHandler.Instance.Servers;
        foreach (KeyValuePair<string, ServerLog> item in servers)
        {
            // データを新たに受信したら
            if (currentDataLen != item.Value.packets.Count)
            {
                currentDataLen = item.Value.packets.Count;

                // 最後に受信したデータのIndexを取得
                int lastPacketIndex = item.Value.log.Count - 1;

                // 最後に受信したデータを取得
                string s2 = item.Value.packets[lastPacketIndex].Data[0].ToString();

                // 取得したデータの数字に対応する部分を黄色に変更
                if (s1.Contains(s2))
                {
                    Debug.Log("s2: " + s2);
                    int i = int.Parse(s2);
                    images[i - 1].color = new Color(255.0f, 255.0f, 0f);
                    s1 = s1.Replace(s2, "");

                    // 9つの数字の色が全て変更したら全て白に戻す
                    if (s1 == "")
                    {
                        for (int j = 0; j < images.Length; j++)
                        {
                            images[j].color = new Color(255.0f, 255.0f, 255.0f);
                            s1 = "123456789";
                        }
                    }
                }
            }
        }
    }
}
```

#おわりに
今回はUnityOSCの使い方について学習しました。
今回作成したアプリケーションは[こちら](https://github.com/knt3110/UnityOSCTest)に上げてあります。

UnityOSCを用いれば、
- スマホをコントローラーにしたPCゲーム
- Leap Motionなどを用いてスマホのゲームを操作する
など色々面白いことができるのではないでしょうか。

これ使って何か面白いコンテンツ作ってみたいですね〜