UnityVR入力スターターキット


## 準備
UnityVRテンプレートから超簡単にワールド内を移動できるようになります。
検証エディタ:Unity2021.1
UnityHubで新しいプロジェクトを作る際にテンプレート「VR」を選択して作成。
プロジェクト設定のXRPluginManagementでOculusをチェック
以下のスクリプトを適当にアセットフォルダに作成します。

```cs:VR_Input.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
public class VR_Input : MonoBehaviour
{
    public enum InputVRBool { Primary, Secondary, Trigger, Grip, Menu, PrimaryAxis };
    public enum InputVRFloat { Trigger, Grip };
    public static bool GetPresseButton(XRNode node, InputVRBool inputVRBool)
    {
        bool value = false;
        var inputdevice = new List<InputDevice>();
        InputDevices.GetDevicesAtXRNode(node, inputdevice);
        if (0 < inputdevice.Count)
        {
            foreach (var device in inputdevice)
            {
                switch (inputVRBool)
                {
                    case InputVRBool.Trigger: device.TryGetFeatureValue(CommonUsages.triggerButton, out value); break;
                    case InputVRBool.Grip: device.TryGetFeatureValue(CommonUsages.gripButton, out value); break;
                    case InputVRBool.Primary: device.TryGetFeatureValue(CommonUsages.primaryButton, out value); break;
                    case InputVRBool.Secondary: device.TryGetFeatureValue(CommonUsages.secondaryButton, out value); break;
                    case InputVRBool.PrimaryAxis: device.TryGetFeatureValue(CommonUsages.primary2DAxisClick, out value); break; 
                    case InputVRBool.Menu:
                        if (node == XRNode.LeftHand)
                        {
                            device.TryGetFeatureValue(CommonUsages.menuButton, out value);
                        }
                        break;
                }
            }
        }
        return value;
    }
    public static float GetAxis1D(XRNode node, InputVRFloat inputVRFloat)
    {
        float value = 0;
        var inputdevice = new List<InputDevice>();
        InputDevices.GetDevicesAtXRNode(node, inputdevice);
        if (0 < inputdevice.Count)
        {
            foreach (var device in inputdevice)
            {
                switch (inputVRFloat)
                {
                    case InputVRFloat.Trigger: device.TryGetFeatureValue(CommonUsages.trigger, out value); break;
                    case InputVRFloat.Grip: device.TryGetFeatureValue(CommonUsages.grip, out value); break;
                }
            }
        }
        return value;
    }
    public static Vector2 GetAxis2D(XRNode node)
    {
        Vector2 value = Vector2.zero;
        var inputdevice = new List<InputDevice>();
        InputDevices.GetDevicesAtXRNode(node, inputdevice);
        if (0 < inputdevice.Count)
        {
            foreach (var device in inputdevice)
            {
                device.TryGetFeatureValue(CommonUsages.primary2DAxis, out value);
            }
        }
        return value;
    }
    public static void Recenter()
    {
        var inputdevice = new List<InputDevice>();
        InputDevices.GetDevicesAtXRNode(XRNode.CenterEye, inputdevice);
        if (0 < inputdevice.Count)
        {
            foreach (var device in inputdevice)
            {
                device.subsystem.TryRecenter();
            }
        }
    } 
}

```

次に、以下のスクリプトを作成、サンプルシーンにある「**XRRig**」というオブジェクトにくっつけます。

```cs:VR_BasicController.cs
using UnityEngine;
[RequireComponent(typeof(CharacterController))]
public class VR_BasicController : MonoBehaviour
{
    private CharacterController cc;
    [SerializeField] private float speed = 2;
    [SerializeField] private int angle = 30;
    private bool RT, LT;
    private Vector2 stickL;
    private Vector2 stickR;
    private float gravity = 20;//9.81f;  
    void Start()
    {
        cc = GetComponent<CharacterController>();
        VR_Input.Recenter();
    }
    void Update()
    {
        stickL = VR_Input.GetAxis2D(UnityEngine.XR.XRNode.LeftHand);
        stickR = VR_Input.GetAxis2D(UnityEngine.XR.XRNode.RightHand);
        Move();
        Rotate();
        if (VR_Input.GetPresseButton(UnityEngine.XR.XRNode.RightHand, VR_Input.InputVRBool.PrimaryAxis))
        {
            VR_Input.Recenter();
        }
    }
    void Move()
    {
        cc.enabled = true;
        Vector3 direction = new Vector3(stickL.x, 0, stickL.y);
        Vector3 velocity = direction * speed;
        velocity.y -= gravity;
        velocity = transform.TransformDirection(velocity);
        cc.Move(velocity * Time.deltaTime);
    }
    void Rotate()
    {
        if (stickR.x < -0.25f && !LT)
        {
            LT = true;
            transform.Rotate(0, -angle, 0);
        }
        if (0.25f < stickR.x && !RT)
        {
            RT = true;
            transform.Rotate(0, angle, 0);
        }
        if (stickR.x == 0)
        {
            LT = false; RT = false;
        }
    }
}
```
## 使い方
左スティックで移動
右スティックで回転
右スティック押し込みでリセンタリング（デバッグ時のみ）

## 余談
Oculus+UnityでVRやりたい場合はアセットストアから「**Oculus Integration**」をインポートすれば大体のことはできる。
が、そんなに機能要らない。。もっと簡単にスクリプトちょっとくっつけるだけでワールドを歩き回りたい！
と思っていたらUnityがVRテンプレートを提供してくれてたので使わせてもらいました。入力関連はどんどんアップデートしてくれているので、
今後さらにシンプルに使えるようになれたらいいね。Unityさんマジ最高です。

## 参考
[Unityマニュアル：Unity の XR 入力] (https://docs.unity3d.com/ja/current/Manual/xr_input.html)