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で開きます.
Visual Studioが開かれると思いますので,以下の画像のようにソリューションエクスプローラーの中からwebsocket-sharpを右クリックし,ビルドを選択します.このときソリューションエクスプローラーの中に存在しているExample*は必要ないので私は消しました.
ビルドをするとwebsocket-sharp-master/websocket-sharp/bin/Debugの中に
websocket-sharp.dllが生成されます.
このdllをUnityのプロジェクト側のAssets/Pluginsに入れてください.
これで,erbsocket-sharpのUnityへのインポートは完了です.
今回UniRXもインポートしました.
UniRxは非同期処理においてはちゃめちゃ便利なライブラリです.
アセットストアからインポートインポートして下さい.
https://assetstore.unity.com/packages/tools/integration/unirx-reactive-extensions-for-unity-17276
2つともインポートが完了したら,UnityのAssets/Pluginsの中身は以下のようになっていると思います.
2.UnityでWebSocketクライアントを作る
- Unity上のオブジェクトの3次元座標情報をNode.jsで動かしているサーバに送信
- オブジェクトの座標に変化があったときだけサーバに情報を送信
これらができるクライアントを作ります.
まずUnityの空間上に
- Box
- Button 2つ
を配置しました.こんな感じ.
スクリプトをひとつだけ書きました.
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 _nowPhaseがSyncingのとき
サーバ側にVector3をstring型にして送信しています.
余談ですが「この値が変化したとき」といったときの処理にUniRxを使っています.
このスクリプトをEmptyObjectなどをMasterとかに名前を変えて空のオブジェクトを作成して,コンポーネントとして追加します.
コンポーネントを追加したら,サーバアドレスとポート,座標情報をサーバに送りたいオブジェクトのTransformを変数SyncObjTransformにセットします.サーバアドレスとポートは特に問題がなければ"localhost"と8080を入れておきます.
スタートボタンとストップボタンのOnClickには
- PositionSync.OnSyncStartButtonDowns
- PositionSync.OnSyncStopButtonDown
をセットしておきます.以下はStartButtonの例
3.Node.jsでWebSocketサーバを作る
Node.jsを予めインストールしておいて下さい.
今回私の環境ではv8.11.3を利用しました.
適当なディレクトリに以下の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ボタンを押して
箱を移動させると...
できました.
上の様子ではマウスでドラッグするとボックスが動いていますが,以下の記事を参考させて頂きました.
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