Meta Quest３ コントローラーを振ったら玉が打つ

### 目的
Unity上でMeta Quest３を用いて、VR空間でコントローラーを振ったらゴーグルから玉が出るようにする！！

### 実行環境
Unity 2022.3.10f1
Meta Quest３

### 実装
前提として、「Meta XR All-in-One SDK」をインストールをしてください。

<img width = "400" alt = "image_01" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3877707/b4817467-0b84-539b-72e5-ddc258287e2a.png">

### コントローラーを振ったら玉が出るようにする
➀「MainCamera」を「Delete」してください。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3877707/77e6dfc2-deca-0fe5-74c0-3f33fb23c9f2.png)
➁「OVRCameraRig」をドラック&ドロップをしましょう。
「Packages」→「Meta XR Core SDK」→「Prefabs」→「OVRCameraRig」
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3877707/5a20f290-7bd8-29b6-e239-57d914954080.png)
➂「OVRControllerPrefab」を「OVRCameraRig」の中の「LeftControllerAnchor」と「RightControllerAnchor」の所にドラック&ドロップをしてください。
「Packages」→「Meta XR Core SDK」→「Prefabs」→「OVRControllerPrefab」
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3877707/c8f80923-7eda-0a30-0e3d-d11c051b22a5.png)
➃「OVRCameraRig」の中の「LeftControllerAnchor」と「RightControllerAnchor」のをクリックして右側のInspectorをみて、「OVRContollerHelper」のScriptの中の「Controller」で「LeftControllerAnchor」は「LTouch」を選んでください。「RightControllerAnchor」は「RTouch」を選んでください。
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3877707/4603a63d-4c61-ddc3-0a71-de212eac1dd6.png)
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3877707/6686ff48-8815-538e-3270-b5125468b012.png)
⑤「OVRCameraRig」に「HandMove」のScriptを作成してください。
「OVRCameraRig」をクリックして右側のInspectorをみて、下の「Add Component」があるのでそこで「HandMove」のScriptを作成してください。![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3877707/49ff1826-cfb3-8a29-354a-15f7e09e7d02.png)
➅「HandMove」をダブルクリックをしてVisual Studioを開いてください。
以下のコードがあるのでコピー&ペーストをして保存を忘れずにしてください。
```C#
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class HandMove : MonoBehaviour
{
    [SerializeField]
    Transform leftControllerTransform; // 左手のTransformをInspectorから割り当てる

    [SerializeField]
    Transform rightControllerTransform; // 右手のTransformをInspectorから割り当てる

    [SerializeField]
    GameObject CenterEyeAnchor;

    [SerializeField]
    GameObject bulletPrefab;
    
    public GameObject cameraRig; // CameraRigオブジェクトをInspectorから割り当てる
    
    public float handMovementThreshold = 0.1f; // 手の動きのしきい値

    private Vector3 previousLeftHandPosition;
    private Vector3 previousRightHandPosition;
    private bool isLeftHandMoving;
    private bool isRightHandMoving;

    private Rigidbody rb;

    private void Awake()
    {
        rb = cameraRig.GetComponent<Rigidbody>();
        if (rb == null)
        {
            rb = cameraRig.AddComponent<Rigidbody>();
            rb.useGravity = false; // VR空間なので重力は通常不要です
        }
    }

    private void Start()
    {
        previousLeftHandPosition = leftControllerTransform.position;
        previousRightHandPosition = rightControllerTransform.position;
    }

    private void Update()
    {
        Vector3 currentLeftHandPosition = leftControllerTransform.position;
        Vector3 currentRightHandPosition = rightControllerTransform.position;
        //Vector3 hmdForward = new Vector3(hmdTransform.forward.x, 0, hmdTransform.forward.z).normalized; // HMDの前方向

        // 左右の手の前後の動きを判定
        isLeftHandMoving = IsHandMoving(currentLeftHandPosition, previousLeftHandPosition);
        isRightHandMoving = IsHandMoving(currentRightHandPosition, previousRightHandPosition);

        // どちらかの手が動いている場合、移動を実行
        if (isLeftHandMoving || isRightHandMoving)
        {
            Debug.Log("コントローラーを振てる"); // コントローラーを振っている時
            GameObject shell = Instantiate(bulletPrefab, transform.position, Quaternion.identity);
            Rigidbody shellRb = shell.GetComponent<Rigidbody>();
            shellRb.AddForce(transform.forward * 500);
            Destroy(shell, 3.0f);
        }
        if(Input.GetKeyDown(KeyCode.Space))
        {
            GameObject shell = Instantiate(bulletPrefab, transform.position, Quaternion.identity);
            Rigidbody shellRb = shell.GetComponent<Rigidbody>();
            shellRb.AddForce(transform.forward * 500);
            Destroy(shell, 3.0f);
        }

        // 手の位置を更新
        previousLeftHandPosition = currentLeftHandPosition;
        previousRightHandPosition = currentRightHandPosition;
    }

    private bool IsHandMoving(Vector3 currentHandPosition, Vector3 previousHandPosition)
    {
        // 手の動きがしきい値より大きいかを判定
        return (currentHandPosition - previousHandPosition).magnitude > handMovementThreshold;
    }
}
```
⑦Unity上に戻ってScriptをドラック&ドロップをしましょう。
「OVRCameraRig」をクリックして右側のInspectorをみて、「HandMove」をたくさんドラック&ドロップをします。

「leftControllerTransform」　：　「LeftOVRControllerPrefab」
「rightControllerTransform」　：　「RightOVRControllerPrefab」
「CenterEyeAnchor」　：　「CenterEyeAnchor」
「bulletPrefab」　：　「BulletBlue」
「cameraRig」　：　「OVRCameraRig」

![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3877707/9e1e34eb-7624-b076-f6ef-150d2bf3156b.png)

### 結果
Unity上で再生して、コントローラーを振ると自分が見ているＶＲゴーグルから玉が出るようになります。

![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3877707/761f5a09-6534-fe86-c494-d56da326d47a.png)