HoloLens2 × ZIGSIM やーる（Touch）

# はじめに
[HoloLensアドベントカレンダー2021](https://qiita.com/advent-calendar/2021/hololens)の8日目の記事です。
今回はZIGSIMを用いて、iPhoneのタッチ操作をHoloLens2にUDP送信し、タップしたら花火を打ち上げてみましょう。

# 開発環境
- Windows 10 PC
- Unity 2020.3.0f1
- MRTK 2.7.2
- HoloLens2
- iPhone 12 Pro
- ZIG SIM PRO

# 実装

1．[前回の記事](https://qiita.com/SatoshiGachiFujimoto/items/d9616b0cb08e17a17baf)を参考にセットアップお願いします

2．ZigSimTouchManager.csを作成し、particleにNoribenFireworksのn_Fireworksをアタッチします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/4ee308f4-8f20-3a2b-e1d5-e99f67faa317.png)

~~~ZigSimTouchManager.cs
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;

#if UNITY_EDITOR
using System.Net;
using System.Net.Sockets;
#else
using System;
using System.IO;
using Windows.Networking.Sockets;
#endif

public class ZigSimTouchManager : MonoBehaviour
{
    int port = 3333;
    Osc.Parser osc = new Osc.Parser();

    public ParticleSystem particle;
    private bool isPlaying = false;
    private string cmd = "";
    private string prevCmd = "";
    private float radius = 0.0f;

    void OnMessage(Osc.Message msg)
    {
        // Debug.LogFormat("{0} => {1}", msg.path, msg.data[0]);
        cmd = msg.path.Split('/').Last();
        if (String.Equals(cmd, "touchradius0")){
            radius = (float)msg.data[0];
            isPlaying = true;
        } else if (String.Equals(cmd, prevCmd)){
            if(isPlaying){
                particle.Play(true);
                isPlaying = false;
            } else {
                particle.Stop(true, ParticleSystemStopBehavior.StopEmitting);
            }
        }
        prevCmd = cmd;
    }

    void Awake()
    {
        particle.Stop();
    }

#if UNITY_EDITOR
    UdpClient udpClient;
    IPEndPoint endPoint;

    void Start()
    {
        endPoint = new IPEndPoint(IPAddress.Any, port);
        udpClient = new UdpClient(endPoint);
    }

    void Update()
    {
        while (udpClient.Available > 0) {
            var data = udpClient.Receive(ref endPoint);
            osc.FeedData(data);
        }

        while (osc.MessageCount > 0) {
            var msg = osc.PopMessage();
            OnMessage(msg);
        }
    }
#else
    DatagramSocket socket;
    object lockObject = new object();

    async void Start()
    {
        try {
            socket = new DatagramSocket();
            socket.MessageReceived += OnMessage;
            await socket.BindServiceNameAsync(port.ToString());
        } catch (System.Exception e) {
            Debug.LogError(e.ToString());
        }
    }

    void Update()
    {
        lock (lockObject) {
            while (osc.MessageCount > 0) {
                var msg = osc.PopMessage();
                OnMessage(msg);
            }
        }
    }

    async void OnMessage(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
    {
        using (var stream = args.GetDataStream().AsStreamForRead()) {
            byte[] buffer = new byte[1024];
            await stream.ReadAsync(buffer, 0, 1024);
            lock (lockObject) {
                osc.FeedData(buffer);
            }
        }
    }
#endif
}
~~~

Debug.LogFormat("{0} => {1}", msg.path, msg.data[0]);の部分で、ZIGSIMから次のような値がOSCのメッセージで送られてきます。

/UUID/deviceinfo => iPhone13,3
/ZIGSIM/UUID/touch01 => -0.1383758
/ZIGSIM/UUID/touch02 => 0.3032174
/ZIGSIM/UUID/touchradius0 => 35.03931
/ZIGSIM/UUID/touchforce0 => 0.85

同時にタッチした場合は続けて送られてきます。5本指のタッチまで対応しているようです（N < 5）

/ZIGSIM/UUID/touch{N}1
/ZIGSIM/UUID/touch{N}2
/ZIGSIM/UUID/touchradius{N}
/ZIGSIM/UUID/touchforce{N}

touchradius0を受け取ったら、パーティクルを再生。deviceinfoが連続で受け取ったらタッチしていない状態なのでパーティクルをストップしている感じです。

3．花火のパーティクルは、[Noriben Fireworks（花火パーティクル）](https://booth.pm/ja/items/1724776)を使用しています。n_Fireworks以外を非アクティブに、[sparclesも黒く映ってしまった](https://twitter.com/sotongshi/status/1468627089729679360?s=20)ので非アクティブにします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/f49c7d24-4747-35e0-02b3-94b7beb634f2.png)

Play On AwakeとLoopingのチェックを外しておきましょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/1430dc14-60a7-32d7-b1c2-dc1d9ed7c970.png)

4．デプロイして、ZIGSIMを起動します。下記の設定でStartし、タップして花火が上がれば成功です！

|Sensor|Setting|Start|
|:--|:--|:--|
|![264687331_432239768442971_3693891695093676187_n.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/8b326a9d-bd79-78b9-0860-9149cc038f02.jpeg)|![263600181_930417751237651_1450746981106444206_n.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/b846f6eb-033b-2ab2-0997-56a0ae8f40e2.jpeg)|![263463646_3536688429805147_9095840384459498970_n.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/b063fbd0-43f8-44a6-ab9c-b3d4059a43e5.jpeg)|


# デモ

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">画面タップすると花火を打ち上げ！<a href="https://twitter.com/hashtag/HoloLens2?src=hash&amp;ref_src=twsrc%5Etfw">#HoloLens2</a> <a href="https://twitter.com/hashtag/MRTK?src=hash&amp;ref_src=twsrc%5Etfw">#MRTK</a> <a href="https://twitter.com/hashtag/Unity?src=hash&amp;ref_src=twsrc%5Etfw">#Unity</a> <a href="https://twitter.com/hashtag/ZIGSIM?src=hash&amp;ref_src=twsrc%5Etfw">#ZIGSIM</a> <a href="https://t.co/lsGS8ctuAo">pic.twitter.com/lsGS8ctuAo</a></p>&mdash; がちもとさん@メタバース熊本 (@sotongshi) <a href="https://twitter.com/sotongshi/status/1468637447026540545?ref_src=twsrc%5Etfw">December 8, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

お疲れ様でした