見出し画像

自己移動感を強く感じられるVRランニングシステムを作成しよう ~vol.4Joy-Con編~

前回の記事はこちら

1.走っているときの細かな動きを再現しよう

先週は記事が書けなくて申し訳ないです…。今週からまた書き始めます。
前回、Unity内に動画を入れましたが、今回は走る際の視覚情報の細かな動きを再現します。実際のランニングを想像すると、上下や左右に細かな動きがありますよね?今回はそういった細かな動きをつけるためのシステムを開発したいと思います。

2.測定方法

ランニングの視覚情報の動きを再現するためには実際の動きを測定する必要があります。そこで今回はジャイロ機能を持っているジョイコンを使用して測定器を作成することにしました。しかもちょうど家にジョイスティックが壊れて使用していないジョイコンがあったので好都合でした。何たるタイミング…。
測定方法は頭にジョイコンをつけたベルトを巻き、その時の動きをUnityで測定する、というものです。次に測定器を作った過程を説明します。

3.Unityでジョイコンを使えるようにする

ジョイコンってそもそもUnityで使えるの…?と思っていましたが、調べてみると下記ページに方法が記載されていて簡単に設定することができました。

まず、ジョイコンをPCにペアリングする必要があります。このとき近くにもともとペアリングしていたニンテンドースイッチがあるとペアリングできないため、スイッチとのペアリングは切っておきましょう。
Windowsの場合は設定→Bluetoothとデバイス→デバイスの追加を押すと下の画像のような画面が出てきます。

この一番上のBluetoothを選択し、デバイスを探しましょう。

デバイスを探す画面に変わったら、上図の赤マルのボタンを長押しするとランプが点滅し、ペアリングモードになります。この状態でしばらく待つと下図のようにジョイコンが表示されます。ここでジョイコンを選択すればペアリング完了です。

次にUnity側の設定です。まず、JoyconLibを下のページからダウンロードしましょう。こちらをUnityのプロジェクトに導入することで簡単にUnity上でジョイコンが使用できます。

次にダウンロードしたJoyconLibを導入したいUnityプロジェクトのパッケージにドラッグ&ドロップします。

するとこのようなウィンドウが出るのでImportをクリックします。これでプロジェクト内にJoyconLibがインポートされました。


4.頭の上下の動きをそのまま映像に反映させてみる

では、JoyconLibを使って、ジョイコンの頭の上下の動きを映像にリアルタイムで反映させてみましょう。前回作った映像が流れるオブジェクトを設置したプロジェクトを利用します。まず、そのオブジェクトに先ほどインポートしたJoyconLib内にあるJoyconManager.csをアタッチします。

うまくアタッチできていればエラーが出ない状態で上図のようにオブジェクトにスクリプトが追加されます。
このJoyconManager.csがあれば、ジョイコンの入力情報やジャイロセンサーの情報をアタッチしたオブジェクトに反映させることができます。

次にどのような処理を行うかのスクリプトを書きます。先ほど載せたリンク先のサイトに下図のようなジョイコンの情報を表示するスクリプトがあったのでこのスクリプトをベースに制作します。

コードは以下の通りです。

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

public class Example2 : MonoBehaviour
{
    public float speed =    1.0f;
    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 ( Input.GetKeyDown( KeyCode.Z ) )
        {
            m_joyconL.SetRumble( 160, 320, 0.6f, 200 );
        }
        if ( Input.GetKeyDown( KeyCode.X ) )
        {
            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;
        }

       

        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 key         = isLeft ? "Z キー" : "X キー";
            var button      = isLeft ? m_pressedButtonL : m_pressedButtonR;
            var stick       = joycon.GetStick();
            var gyro        = joycon.GetGyro();
            var accel       = joycon.GetAccel();
            var orientation = joycon.GetVector();

            GUILayout.BeginVertical( GUILayout.Width( 480 ) );
            GUILayout.Label( name );
            GUILayout.Label( key + ":振動" );
            GUILayout.Label( "押されているボタン:" + button );
            GUILayout.Label( string.Format( "スティック:({0}, {1})", stick[ 0 ], stick[ 1 ] ) );
            GUILayout.Label( "ジャイロ:" + gyro );
            transform.position = new Vector3(0,gyro.z,0); 
            GUILayout.Label( "加速度:" + accel );
            GUILayout.Label( "傾き:" + orientation );
            GUILayout.EndVertical();

           
        }
        
            
            

        GUILayout.EndHorizontal();
    }
}

主な部分は元のコードと変わりませんが、ジョイコンのR(右)は今回使わないため、それに関するコードは消去しています。また、オブジェクトにジョイコンの上下の動きを付与するために

transform.position = new Vector3(0,gyro.z,0);

こちらの1行を追加し、gyro.z(ジョイコンのz軸(高さ)の位置情報)をオブジェクトのy軸(高さ)の位置情報に変換します。これにより、ジョイコンのz軸の位置情報がリアルタイムに反映されます。実行結果は下の通りです。

頭の振り幅を細かく設定していないので性格にランニングの動きを再現できているかはなんとも言えませんが、それっぽくなりました。もっと細かい設定を行う必要はありそうですが、とりあえずジャイロセンサーの情報は取れてるっぽいです。VRで見てみたら新たな発見もあるかもですね。

5.まとめ

今回はジョイコンをUnityで使うための設定とジョイコンのジャイロ機能を使ってランニング中の細かな動きの再現を行いました。とりあえず作ってみた段階なので測定する数値などが曖昧ですが、今後はその辺も改良しようと思います。ではでは。

この記事が気に入ったらサポートをしてみませんか?