これは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を導入しよう!
- ダウンロードまで
- 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)
##Unityへ
ダウンロード出来たらそれを展開しておきます。
次にUnityプロジェクトを開き、JoyconLib-master/Assets
フォルダにあるJoyconLib_scripts
とUnity-Wiimote-master/Assets/Wiimote/Plugins/win64
フォルダにあるhidapi.dll
をドラッグアンドドロップで追加します。
#Joy-conの振動機能を使いこなそう
- 動かせるようになるまで
- 解説
- コードについて
- パラメータについて
##1. 動かせるようになるまで
プロジェクトへ導入ができたら次はスクリプトを書いて実際に動かしてみましょう。プロジェクトにJoyconRumbleという名前のスクリプトを作成し以下のように書いてください。
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.cs
とJoyconLib_script
フォルダ内にあるJoyconManeger.cs
をアタッチします。
できたら動かしてみましょうJoy-conとのbluetooth接続がうまくいっていたら自身の押しているボタンが表示され、コントロ―ラの上ボタンで振動が確認できます。
##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について僕自身も理解しきれていないのでもしチョットワカル方がいらっしゃれば教えてください。