Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

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

nmxi
最近は https://www.kemomimi.dev の方に記事書いてます
https://www.kemomimi.dev
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした