11
11

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.

UT-virtualAdvent Calendar 2018

Day 15

NintendoSwitchのJoy-conを使用して簡単な触覚インターフェースを実現しよう

Last updated at Posted at 2018-12-14

これはUT-virtual Advent Calendar 2018の12月15日を担当するとなって書き上げたものです。

#はじめに
この記事で扱うものは筆者がコガネブログさんの記事
【Unity】Nintendo Switch の Joy-Con のジャイロ・加速度・傾きの値を取得したり、振動させたりすることができる「JoyconLib」紹介
を読み記事で紹介されたJoyconLib等を使用して実装したものです。今回はUnityで触覚インターフェースとしてJoy-conを使う方法とJoy-conの振動原理について書こうと思います。

注意:この記事ではJoy-conのキー入力を取得する方法は一部分しか載せません。知りたい方は上記の記事を読んでください。またここに載せたJoyconLibを使う場合はライセンス等1の一読を強く推奨します。

#Joy-conの振動原理
いろいろな記事等を調べてみるとJoy-conにはALPSのハプティックリアクタが採用されているらしくこれは320Hzと160Hzの二つの共振方向によって様々な振動を与えることができるらしいです。実のところ僕自身こういった振動についてあまり詳しくなく、これぐらいのことしかわらないです。

#使用するもの

  • Unity2
  • JoyconLib
  • Joy-con

#Joy-conとパソコンの接続
今回はJoy-conとパソコンとの接続はBluetoothを用います。ご自身の使用しているパソコンによって接続の仕方が違いますが、Windowsでの設定方法については**ここ**の記事を参考にした方がいいでしょう。とてもわかりやすく書いてあります。
macはあまり触ったことがないのですが、調べてみるとBluetoothを検知可能にしてその状態でシステム環境設定 → Bluetoothの接続で設定をすればいいみたいです。

#JoyconLibを導入しよう!

  1. ダウンロードまで
  2. Unityへ

##ダウンロードまで
下記の各URLにアクセスし、上のURLでJoyconLib-master.zipを、下のURLでUnity-Wiimote-master.zipをダウンロード3します。
https://github.com/Looking-Glass/JoyconLib
[https://github.com/Flafla2/Unity-Wiimote]
(https://github.com/Flafla2/Unity-Wiimote)

以下のようになっていれば大丈夫です。
image.png

##Unityへ
ダウンロード出来たらそれを展開しておきます。
次にUnityプロジェクトを開き、JoyconLib-master/AssetsフォルダにあるJoyconLib_scriptsUnity-Wiimote-master/Assets/Wiimote/Plugins/win64フォルダにあるhidapi.dllをドラッグアンドドロップで追加します。

以下のようになっていれば大丈夫です。
image.png

#Joy-conの振動機能を使いこなそう

  1. 動かせるようになるまで
  2. 解説
    1. コードについて
    2. パラメータについて

##1. 動かせるようになるまで
プロジェクトへ導入ができたら次はスクリプトを書いて実際に動かしてみましょう。プロジェクトにJoyconRumbleという名前のスクリプトを作成し以下のように書いてください。

JoyconRumble.cs
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class JoyconRumble : MonoBehaviour
{
    private static readonly Joycon.Button[] m_buttons =
        Enum.GetValues(typeof(Joycon.Button)) as Joycon.Button[];

    private List<Joycon> m_joycons;
    private Joycon m_joyconL;
    private Joycon m_joyconR;
    private Joycon.Button? m_pressedButtonL;
    private Joycon.Button? m_pressedButtonR;

    private void Start()
    {
        m_joycons = JoyconManager.Instance.j;

        if (m_joycons == null || m_joycons.Count <= 0) return;

        m_joyconL = m_joycons.Find(c => c.isLeft);
        m_joyconR = m_joycons.Find(c => !c.isLeft);
    }

    private void Update()
    {
        m_pressedButtonL = null;
        m_pressedButtonR = null;

        if (m_joycons == null || m_joycons.Count <= 0) return;

        foreach (var button in m_buttons)
        {
            if (m_joyconL.GetButton(button))
            {
                m_pressedButtonL = button;
            }
            if (m_joyconR.GetButton(button))
            {
                m_pressedButtonR = button;
            }
        }

        if (m_joyconL.GetButtonDown(Joycon.Button.DPAD_UP))
        {
            m_joyconL.SetRumble(160, 320, 0.6f, 200);
        }
        if (m_joyconR.GetButtonDown(Joycon.Button.DPAD_UP))
        {
            m_joyconR.SetRumble(160, 320, 0.6f, 200);
        }
    }
    private void OnGUI()
    {
        var style = GUI.skin.GetStyle("label");
        style.fontSize = 24;

        if (m_joycons == null || m_joycons.Count <= 0)
        {
            GUILayout.Label("Joy-Con が接続されていません");
            return;
        }

        if (!m_joycons.Any(c => c.isLeft))
        {
            GUILayout.Label("Joy-Con (L) が接続されていません");
            return;
        }

        if (!m_joycons.Any(c => !c.isLeft))
        {
            GUILayout.Label("Joy-Con (R) が接続されていません");
            return;
        }

        GUILayout.BeginHorizontal(GUILayout.Width(960));

        foreach (var joycon in m_joycons)
        {
            var isLeft = joycon.isLeft;
            var name = isLeft ? "Joy-Con (L)" : "Joy-Con (R)";
            var button = isLeft ? m_pressedButtonL : m_pressedButtonR;

            GUILayout.BeginVertical(GUILayout.Width(480));
            GUILayout.Label("押されているボタン:" + button);
            GUILayout.EndVertical();
        }

        GUILayout.EndHorizontal();
    }
}


できたらシーンに空のオブジェクトを作ってそれにJoyconRumble.csJoyconLib_scriptフォルダ内にあるJoyconManeger.csをアタッチします。
image.png
できたら動かしてみましょうJoy-conとのbluetooth接続がうまくいっていたら自身の押しているボタンが表示され、コントロ―ラの上ボタンで振動が確認できます。
image.png

##2. 解説
###2-1. コードについて
今からはコードの解説をしていきます。OnGUI関数内は表示するための部分なので気になった方は調べてみましょう。今回は触れません。


private void Start()
    {
        m_joycons = JoyconManager.Instance.j;

        if (m_joycons == null || m_joycons.Count <= 0) return;

        m_joyconL = m_joycons.Find(c => c.isLeft);
        m_joyconR = m_joycons.Find(c => !c.isLeft);
    }

上記のstart関数内ではJoyconのインスタンスを生成し、Joyconが生成できているなら左右のコントロ―ラを検出しています。

private void Update()
    {
        m_pressedButtonL = null;
        m_pressedButtonR = null;

        if (m_joycons == null || m_joycons.Count <= 0) return;

        foreach (var button in m_buttons)
        {
            if (m_joyconL.GetButton(button))
            {
                m_pressedButtonL = button;
            }
            if (m_joyconR.GetButton(button))
            {
                m_pressedButtonR = button;
            }
        }

        if (m_joyconL.GetButtonDown(Joycon.Button.DPAD_UP))
        {
            m_joyconL.SetRumble(160, 320, 0.6f, 200);
        }
        if (m_joyconR.GetButtonDown(Joycon.Button.DPAD_UP))
        {
            m_joyconR.SetRumble(160, 320, 0.6f, 200);
        }
    }

こちらのUpdate関数内ではJoyconを検出できた場合ボタンが押されたときそのボタンが何ボタンか判別し、それが特定のボタンであったとき振動をするようにしています。つまりもしオブジェクトとの衝突などで振動を引き起こしたかったら、最後のif文の条件式をOnCollsionEnter関数やOnTriggerEnter関数とかに変更するといいと思います。

ここで振動をさせるための関数SetRumble()についてみていこうと思っています。JoyconLibを導入するときにおかれたJoycon.csをみると

 public void SetRumble(float low_freq, float high_freq, float amp, int time = 0)
    {
        if (state <= Joycon.state_.ATTACHED) return;
		if (rumble_obj.timed_rumble == false || rumble_obj.t < 0)
        {
            rumble_obj = new Rumble(low_freq, high_freq, amp, time);
        }
    }

とあります。これから引数は左から低い方の周波数、高い方の周波数、振幅、周期みたいです。ですので一つ目には160Hz、二つ目には320Hzが入っていますね。そして重要なのはnew Rumble(low_freq, high_freq, amp, time);でインスタンスが生成されているところです。これによって振動を起こすオブジェクトが生成されているみたいですね。

###2-2. パラメータについて
では実際にどういった値を入れるのが適切かですが、まず160と320の二つは振動について詳しくない方はいじらない方がいいと思われます。そしてそれ以降の値については振動についての知見がある人はご自由にしていただき、ない人は実験みたいに何度も試してみるのがいいと思います。

気づかれた方もいらっしゃるかもしれませんがこのJoyconLibを使用した振動を起こす方法では二つの周波数で別々に振幅と周期を設定することができないようで、Swithのゲームのようにとてもリアルな触覚を再現するには与えるパラメータの値等の工夫する必要があるみたいです。なのでこの方法では自身の体にオブジェクトが当たったなどの簡単な触覚の提示等に適しているかと思います。

#最後に
今回はJoyconを使った触覚インターフェースについて書きました。振動等を使って触覚を再現するすることはこれからより増えていくことだと思います。(実際にHTC Viveのコントロ―ラにもHD振動の機構がある。)

ぜひ取り組んでみてはいかがでしょう!(スマブラsp買った人ならSwitch持ってますよね?)

あとJoyconLibについて僕自身も理解しきれていないのでもしチョットワカル方がいらっしゃれば教えてください。

  1. JoyconLibのGitHubページ内にあるLICENSEとREADME.mdあたりを読んで置いたらいいと思います。

  2. もし自身の環境でできなかったらバージョンを2018.2.9f1あたりでもう一度やってみてください。

  3. 最初の画面でClone or downloadボタンを押すとOpen in DesktopDownload Zipの二つがありますが後の方を選べばダウンロードできます。

11
11
0

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
11
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?