Node.js
Unity
websocket

UnityからNode.jsサーバにWebSocketを使ってデータ送信

Pref.

UnityからNode.jsで動かしてるサーバにオブジェクトの座標を送ってみたかったんです.
こちら@oishihiroaki さんの記事を参考にwebsocket-sharpをUnityに入れてやってみたのでまとめます.ありがとうございます(๑•̀ㅂ•́)و✧

以下に今回作ったサンプルプロジェクトを置いておきました.

https://github.com/nmxi/UnityWebSocketTest

Env.

Windows10 64bit
Unity 20181.5f1
Node v8.11.3

Method

1.Unityに2つのライブラリをインポート

こちらの記事を参考にまずwebsocket-sharpをUnityに入れます.

上記の記事の中ではMonoDeveropを利用してビルドし,dllファイルを生成しているのですが,Unity2018からエディタがVisual Studioになったので(?)今回はそちらの方法を簡単に書き残しておきます.簡単ですがw

まずGitHubからCloneかZipで保存しまして,websocket-sharp.slnをVisual Studioで開きます.

アセット 1@.png

Visual Studioが開かれると思いますので,以下の画像のようにソリューションエクスプローラーの中からwebsocket-sharpを右クリックし,ビルドを選択します.このときソリューションエクスプローラーの中に存在しているExample*は必要ないので私は消しました.

アセット 2@.png

ビルドをするとwebsocket-sharp-master/websocket-sharp/bin/Debugの中に
websocket-sharp.dllが生成されます.

image.png

このdllをUnityのプロジェクト側のAssets/Pluginsに入れてください.
これで,erbsocket-sharpのUnityへのインポートは完了です.

今回UniRXもインポートしました.
UniRxは非同期処理においてはちゃめちゃ便利なライブラリです.
アセットストアからインポートインポートして下さい.

https://assetstore.unity.com/packages/tools/integration/unirx-reactive-extensions-for-unity-17276

image.png

2つともインポートが完了したら,UnityのAssets/Pluginsの中身は以下のようになっていると思います.

image.png

2.UnityでWebSocketクライアントを作る

  • Unity上のオブジェクトの3次元座標情報をNode.jsで動かしているサーバに送信
  • オブジェクトの座標に変化があったときだけサーバに情報を送信

これらができるクライアントを作ります.

まずUnityの空間上に

  • Box
  • Button 2つ

を配置しました.こんな感じ.

image.png

スクリプトをひとつだけ書きました.

PositionSync.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using WebSocketSharp;
using UniRx;

public class PositionSync : MonoBehaviour {

    [SerializeField] private string _serverAddress;
    [SerializeField] private int _port;

    [SerializeField] private Transform _syncObjTransform;   //Share transform

    [SerializeField] private SyncPhase _nowPhase;

    private WebSocket ws;

    public enum SyncPhase {
        Idling,
        Syncing
    }

    private void Awake() {
        _nowPhase = SyncPhase.Idling;

        var cTransformValue = gameObject.ObserveEveryValueChanged(_ => _syncObjTransform.position);
        cTransformValue.Subscribe(x => OnChangedTargetTransformValue(x));
    }

    /// <summary>
    /// Get Down Start Sync Button
    /// </summary>
    public void OnSyncStartButtonDown() {
        var ca = "ws://" + _serverAddress + ":" + _port.ToString();
        Debug.Log("Connect to " + ca);
        ws = new WebSocket(ca);

        //Add Events
        //On catch message event
        ws.OnMessage += (object sender, MessageEventArgs e) => {
            print(e.Data);
        };

        //On error event
        ws.OnError += (sender, e) => {
            Debug.Log("WebSocket Error Message: " + e.Message);
            _nowPhase = SyncPhase.Idling;
        };

        //On WebSocket close event
        ws.OnClose += (sender, e) => {
            Debug.Log("Disconnected Server");
        };

        ws.Connect();

        _nowPhase = SyncPhase.Syncing;
    }

    /// <summary>
    /// Get Down Stop Sync Button
    /// </summary>
    public void OnSyncStopButtonDown() {
        ws.Close(); //Disconnect
    }

    public void OnChangedTargetTransformValue(Vector3 pos) {
        if (_nowPhase == SyncPhase.Syncing) {
            Debug.Log(pos);
            ws.Send(pos.ToString());
        }
    }
}

本当に数分で書いたのではちゃめちゃですが...
以上のスクリプトでは

オブジェクトのTransform.positionに変化があったとき
&
Enumで定義したSyncPhase _nowPhaseSyncingのとき

サーバ側にVector3をstring型にして送信しています.
余談ですが「この値が変化したとき」といったときの処理にUniRxを使っています.

このスクリプトをEmptyObjectなどをMasterとかに名前を変えて空のオブジェクトを作成して,コンポーネントとして追加します.
コンポーネントを追加したら,サーバアドレスとポート,座標情報をサーバに送りたいオブジェクトのTransformを変数SyncObjTransformにセットします.サーバアドレスとポートは特に問題がなければ"localhost"と8080を入れておきます.

image.png

スタートボタンとストップボタンのOnClickには

  • PositionSync.OnSyncStartButtonDowns
  • PositionSync.OnSyncStopButtonDown

をセットしておきます.以下はStartButtonの例

image.png

3.Node.jsでWebSocketサーバを作る

Node.jsを予めインストールしておいて下さい.
今回私の環境ではv8.11.3を利用しました.

適当なディレクトリに以下のserver.jsを作ります.

server.js
var WebSocketServer = require('ws').Server
var wss = new WebSocketServer({
    port: 8080
});

wss.on('connection', function(ws) {
    ws.on('message', function(message) {
        console.log('received: %s', message);
    });
    ws.send('This is server');
});

これでポート番号8080でサーバが立ち,クライアントが接続したときに"This is server"とメッセージを送るようになります.

4.動作確認

まずサーバ側を以下コマンドで起動させます.

$ node server.js

次にUnity側をPlayにし,Sync Startボタンを押して
箱を移動させると...

ecWc.gif

できました.
上の様子ではマウスでドラッグするとボックスが動いていますが,以下の記事を参考させて頂きました.

Ref.

http://neareal.com/1230/
https://qiita.com/oishihiroaki/items/bb2977c72052f5dd5bd9
http://hwks.hatenadiary.jp/entry/2014/07/20/022229
http://blog.katty.in/2206