vaguely

和歌山に戻りました。ふらふらと色々なものに手を出す毎日。

UnityでWebSocketを使ってみたい

はじめに

前回に引き続きWebSocketについてのお話。

ですが、今回はUnityからwebsocket-sharpというライブラリを使ってWebSocket Clientとしてアクセスします。

そして、アクセスする先はgorilla/websocketのExamplesにあるチャットです。

Springはどうしたんじゃいという話なのですが、C#でSTOMPを使う方法がわからなかったため、
とりあえず今回はGolangのものを使用することにしました。

こちらについては問題が解決すれば別途ブログにまとめたいと思います。

websocket-sharp

まずUnityからWebsocketでアクセスするのに利用する、websocket-sharpの準備です。

Unityから呼び出せるようにするために、dllファイルを作成する必要があります。

上記GitHubのReadmeの通りなのですが、一応手順を載せておきます。
(Jetbrains Riderで実行しました)

  1. プロジェクトをダウンロードしてソリューションファイルを開きます。
  2. ソリューションが5つ(websocket-sharpとExample4つ)あり、その中の「websocket-sharp」の上で右クリック->「Build selected projects」でビルドします。
  3. ビルドに成功したら、websocket-sharp > websocket-sharp > bin > Debug(or Release)にwebsocket-sharp.dllが出力されるため、UnityプロジェクトのAssets以下に置きます。

  4. Step2で、プロジェクト全体に対してビルドすると、Exampleのどれかでエラーになります。

で、Websocketでアクセスするコードはこんな感じです。

WebsocketAccessor.cs

using System;
using System.Collections.Generic;
using UnityEngine;
using WebSocketSharp;

public class WebsocketAccessor : MonoBehaviour
{
    private void Start()
    {
        // サーバー側ではlocalhost:8088/wsにアクセスした時に登録処理を行う.
        using(WebSocket ws = new WebSocket("ws://localhost:8088/ws")){
            // 接続開始時のイベント.
            ws.OnOpen += (sender, e) =>
            {
                Debug.Log("Opended");
            };
            // メッセージ受信時のイベント.
            ws.OnMessage += (sender, e) =>
            {
                Debug.Log("Received " + e.Data);
            };
            // 接続.
            ws.Connect ();
            // メッセージ送信.
            ws.Send ("世界さん、チーッす!");
        }
    }
}

パスワードもないものにアクセスするだけとはいえ、シンプルですね。

サーバー側ではメッセージの送受信をbyte型のスライスで行っていますが、
Unity側からはstring型のデータを渡すことができます。

また、このUnityプロジェクトをビルドして複数起動すれば、Unityアプリ同士でメッセージの送受信も行うことができます。便利!

Json

さて、上記のように単純にメッセージを送り合うだけなら問題がないのですが、
例えば3Dモデルの座標値を送りたい場合。

前述の通りメッセージとしてstring型のデータを扱えるため、JsonUtilityを使ってJson形式に変換し、それを送信してみたいと思います。

まずJsonに変換するデータを格納するためのクラスを用意します。

ObjectStatus.cs

using System;

[Serializable]
public class ObjectStatus
{
    public float PositionX;
    public float PositionY;
    public float PositionZ;
}
  • クラス名については気にしない方向でお願いいたします(白目)

で、入れ物が用意できればあとはデータを詰めてJsonに変換するだけです。

WebsocketAccessor.cs

using System;
using System.Collections.Generic;
using UnityEngine;
using WebSocketSharp;

public class WebsocketAccessor : MonoBehaviour
{
    public GameObject TargetModel;
    private WebSocket ws;
    private ObjectStatus objectStatus;

    private void Start()
    {
        objectStatus = new ObjectStatus();

        ws = new WebSocket("ws://localhost:8088/ws");

        ws.OnOpen += (sender, e) =>
        {
            Debug.Log("Opended");
        };
        ws.OnMessage += (sender, e) =>
        {
            Debug.Log("Received " + e.Data);
        };
        ws.Connect ();
    }

    private void Update()
    {
        if (Input.GetMouseButtonUp(1))
        {
            // データをクラスにセット.
            objectStatus.PositionX = TargetModel.transform.localPosition.x;
            objectStatus.PositionY = TargetModel.transform.localPosition.y;
            objectStatus.PositionZ = TargetModel.transform.localPosition.z;

            // セットしたクラスを使ってJson形式に変換.
            var json = JsonUtility.ToJson(objectStatus);
            // 変換したデータを送信する.
            ws.Send (json);
        }
    }
    private void OnDestroy()
    {
        // 接続を切る.
        ws.Close();
    }
}
  • 今回は右クリック時にメッセージを送信しています。

送信したデータは下記のような内容となります。
特に送信するデータが多い場合など、要素名は短くしておいた方が良いかもしれません。

{"PositionX":1.84,"PositionY":1.28,"PositionZ":0.0}

おわりに

今回はとりあえずサンプルを試しただけで、あまり中身に触れられませんでした。

ということで、次回あたりでもう少し触れてみたいと思います。

また、サーバー側の処理についても少し追いかけてみたいと思います。

参照