16
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

toio と Unity の連携

Last updated at Posted at 2019-11-30

#はじめに
これは「toio™(ロボットトイ | toio(トイオ)) Advent Calendar 2019」の1日目の記事になります。

この記事ではUnityとtoioの連携方法を記します。
以下の記事・サイトを参考にしました。

#toio.js とは
toio.js は Node.js を用いたtoio公式のライブラリです。
パソコン側からcoreCubeを動かしたり、マット上の位置を取得したり出来ます。
今回はこれを使ってマット上のcoreCubeにUnity上のCubeを連動させたいと思います。

#環境
OS : MacOS High Sierra 10.13.6

#下準備
##Unity
###Unity Hub のインストール
Unity Hub を入れます。
こちらUnityHubをダウンロードからインストーラをダウンロードできます。

unity hubを起動してインストールで最新バージョンのUnityを入れます。
このとき、Visual Studioも一緒にインストールします。
スクリーンショット 2019-11-26 15.04.54.png

###UniRx
Unity Hub で新規プロジェクトを作成します。
スクリーンショット 2019-11-26 14.48.17.png

プロジェクトが開いたらAssetストアで UniRx をダウンロード、インポートします。
すると、Assetsフォルダ下にPluginsフォルダができ、その中にUniRxが入ります。
スクリーンショット 2019-11-26 15.31.22.png

###C# websocketライブラリ

こちらからライブラリをダウンロードして解凍します。
スクリーンショット 2019-11-28 21.31.12.png

中にある websocket-sharp.csproj をVisualStudioで開きビルドすると bin/Debug 下に websocket-sharp.dll が出来ます。
スクリーンショット 2019-11-28 21.30.09.png

この websocket-sharp.dll を先ほど作成したプロジェクトの Assets/Plugins に入れます。
スクリーンショット 2019-11-26 15.51.16のコピー.png

これでUnity側の下準備は完了です。

##toio.js
###brew install yarn

yarn に関しては公式では npm で入れていますが、

npm install -g yarn

私は以下のように brew を使いました。

brew install yarn 

権限が必要だったり入れ難かった覚えがありましたが、なんかと入れたようです。
良くないことをしたかも知れません。

###toio.js

次に toio の github から toio.js を clone します。
公式曰く、以下のコマンドでパッケージのbuildまで済みます。
yarn example:hogehoge でサンプルプログラムが動きます。

git clone https://github.com/toio/toio.js.git
cd toio.js
yarn install
yarn build
yarn example:keyboard-control

coreCubeの電源を入れて接続され方向キーで動いたらオッケーです。
僕は接続されなかったのでパソコンを再起動したら動きました。

#実装
##Unity側

SceneにCreateから3D Object/Cubeを置きます。
またCreateからUI/Buttonを置いておきます。

GameViewでみるとこんな感じになると思います。
スクリーンショット 2019-11-28 21.10.24.png

Cube に Add Component/NewScript でPositionSyncというスクリプトをつけます。
以下、@nmxi さんの記事*から拝借したコードを改変して書いた中身です。

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 SyncPhase _nowPhase;

    private GameObject tA;
    private WebSocket ws;
    string message = "";
    string messageA = "";

    public float span = 0.5f;

    public enum SyncPhase
    {
        Idling,
        Syncing
    }

    private void Awake()
    {
        tA = GameObject.Find("Cube");
        _nowPhase = SyncPhase.Idling;

    }

    void Update()
    {
        string[] m = message.Split(',');

        switch (m[0])
        {
            case "A":

                if (message != messageA)
                {
                    ////サイズの変更
                    //マット
                    //559mm 410points 
                    //toioコアキューブ
                    //31.8mm about 23.3point

                    tA.transform.position = new Vector3(-(float.Parse(m[2]) - 250.0f) / 10.0f, tA.transform.position.y, -(float.Parse(m[1]) - 250.0f) / 10.0f);
                    tA.transform.rotation = Quaternion.Euler(0, float.Parse(m[3]), 0);
                }
                messageA = message;
                //Debug.Log(m);
                break;
        }


    }
    /// <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) => {
            message = 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;
    }

    public void OnChangedTargetTransformValue(Vector3 pos)
    {
        if (_nowPhase == SyncPhase.Syncing)
        {
            //ws.Send(pos.ToString());
            //ws.Send("1");
        }
    }
}

Cube にある PositionSync (Script)の欄に
Server Address には "localhost"、Port には "8080"を入れて置きます。
スクリーンショット 2019-11-28 21.05.17.png

先ほど置いたButtonのOn Click()に Cube/PositionSync/OnSyncStartButtonDown() を追加します。
スクリーンショット 2019-11-28 21.12.27.png

##toio.js側

toio.js/projectsフォルダを作成し、その中にスクリプトを置きます。
今回はtoio公式のサンプルと@nmxi さんの記事*から拝借したコードを悪魔合体して以下のスクリプトを生成しました。

マット上におけるcoreCubeの絶対位置をUnityに送るプログラムです。

toio_node.js

const { NearestScanner } = require('@toio/scanner')

var WebSocketServer = require('ws').Server

var wss = new WebSocketServer({
    port: 8080
});

var cube;

async function main() {
  // start a scanner to find nearest cube
  cube = await new NearestScanner().start()

  // connect to the cube
  await cube.connect()
}

main()

wss.on('connection', function(ws) {

    //position-idに変化があった時
    //移動、回転
    //toioPositionを更新する
    cube.on('id:position-id', data => {
        ws.send("A,"+data.x+","+data.y+","+data.angle)

    })
    //マットから離れた時
    cube.on('id:position-id-missed', () => {
      // ws.send('Position Miss!');
    })
});

#実行
1.coreCube の電源を入れます。

2.toio_node.js を実行します。(少しして coreCube から音がします。)

cd projects
node toio_node.js

3.Unity のプロジェクトを Run します。

4.GameView 上で Button をクリックします。

この状態でマットに置いた coreCube の位置が Unity の Cube に反映されれば成功です。

こんな感じ

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?