1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

VR空間内でコントローラーを振って移動するシステムを作成してみよう

Last updated at Posted at 2025-11-17

VR空間で実際に腕を振って移動してみたいですよね?
本記事ではMeta Quest(Oculus)コントローラーを振ることで、VR空間内を移動できるロコモーションシステムを作る方法を紹介します!

VRにおけるロコモーションとは、 「仮想空間(VR空間)の中を移動する方法」 のことです。

両手のコントローラーを上下に振る動作を検出し、その速度に応じてキャラクターが前進するシステムを作成してみましょう!
Adobe Express GIF 2025-11-17.gif

  • 自然な移動感: コントローラーを振る動作で移動するため、実際に歩いているような感覚を体験できます
  • CharacterController対応: Unity標準のCharacterControllerを使用し、重力処理や地形との衝突判定に対応
  • 視線方向への移動: HMD(ヘッドマウントディスプレイ)が向いている方向に移動します
  • カスタマイズ可能: 移動速度、感度の閾値、重力の強さを調整できます

ShakingMoveForCC スクリプト

ShakingMoveForCC.cs
using UnityEngine;

// このスクリプトは CharacterController がアタッチされていることを前提とします
[RequireComponent(typeof(CharacterController))]
public class ShakingMoveForCC : MonoBehaviour
{
    [Header("移動速度")]
    [Tooltip("コントローラーを振った際の移動速度の倍率")]
    [SerializeField] private float moveSpeed = 2.0f;

    [Header("速度の閾値")]
    [Tooltip("このY軸速度を超えたら移動として判定")]
    [SerializeField] private float speedThreshold = 0.1f;

    [Header("重力")]
    [Tooltip("キャラクターにかかる重力")]
    [SerializeField] private float gravity = -9.81f;

    [Header("カメラ参照")]
    [Tooltip("CenterEyeAnchorなどのカメラTransformを設定")]
    [SerializeField] private Transform playerCamera;

    private CharacterController characterController;
    private Vector3 verticalVelocity; // 重力計算用の速度

    private void Start()
    {
        characterController = GetComponent<CharacterController>();

        // 必須項目が設定されているかチェック
        if (playerCamera == null)
        {
            Debug.LogError("Player Camera(CenterEyeAnchorなど)が設定されていません。インスペクターから設定してください。", this);
        }
    }

    private void Update()
    {
        // 必須項目がなければ処理を中断
        if (playerCamera == null) return; // ← OVRCameraRigのチェックを削除


        // ---1. 重力処理 ---
        if (characterController.isGrounded)
        {
            // 地面にいる時は重力速度をリセット(蓄積させない)
            verticalVelocity.y = -2f; // わずかに下向きの力をかけておくと安定します
        }
        else
        {
            // 空中にいる時は重力を加算
            verticalVelocity.y += gravity * Time.deltaTime;
        }

        // --- 2. 移動入力の計算 ---
        Vector3 moveDirection = Vector3.zero;

        // 右手と左手の(ローカル座標系での)Y軸速度を取得
        Vector3 velocityR = OVRInput.GetLocalControllerVelocity(OVRInput.Controller.RTouch);
        Vector3 velocityL = OVRInput.GetLocalControllerVelocity(OVRInput.Controller.LTouch);

        // Y軸方向の速度の絶対値を取得(上下に振る動きを検出)
        float speedR = Mathf.Abs(velocityR.y);
        float speedL = Mathf.Abs(velocityL.y);

        // どちらかの手の速度が閾値を超えた場合のみ
        if (speedR > speedThreshold || speedL > speedThreshold)
        {
            // 両手の速度を合計して移動速度を計算
            float totalSpeed = (speedR + speedL) * moveSpeed;

            // 頭(カメラ)の向いている正面方向を取得
            Transform headTransform = playerCamera.transform;
            Vector3 forwardDirection = headTransform.forward;

            forwardDirection.y = 0; // 水平移動のみ(上下を向いても前進する)
            forwardDirection.Normalize();

            // 移動ベクトルを計算
            moveDirection = forwardDirection * totalSpeed;
        }

        // --- 3. 移動の実行 (CharacterController.Move) ---
        // 水平移動(moveDirection) と 垂直移動(verticalVelocity) を合算してMoveに渡します
        // Time.deltaTimeを掛けてフレームレートに依存しない移動にします
        characterController.Move((moveDirection + verticalVelocity) * Time.deltaTime);
    }
}
  1. コントローラー速度検出

    • OVRInput.GetLocalControllerVelocity()を使用して、左右のコントローラーのローカル座標系でのY軸速度を取得
    • 上下に振る動作を検出し、その速度の絶対値を計算
  2. 移動方向の決定

    • HMDのカメラ(CenterEyeAnchor)の正面方向を取得
    • Y軸成分を0にして水平方向のみに正規化
    • これにより、上下を向いても水平移動のみが行われます
  3. 重力処理

    • CharacterControllerのisGroundedプロパティで接地判定
    • 空中では重力加速度を加算し、自然な落下を実現
    • 地面にいる時は重力速度をリセット
  4. 移動の実行

    • 水平移動ベクトルと垂直移動ベクトル(重力)を合算
    • CharacterController.Move()で移動を実行
    • Time.deltaTimeを使用してフレームレート非依存

Unity エディタでのセットアップ方法

(前提条件)

  • Unity 2021.3以降(推奨)

ステップ1: プロジェクトの準備

Package Managerから以下のパッケージをインストール:
- XR Plugin Management
- Meta All in One SDK

ステップ2: OVRCameraRig の設置

初めに既存のMainCameraは削除する!
MetaメニューのTools > Building BlocksからCameraRigをインポート
スクリーンショット 2025-11-17 15.34.17.png

スクリーンショット 2025-11-17 15.34.37.png

(上記の方法でCameraRigを取得できない場合)
ProjectビューでOVRCameraRigと検索してOVRCameraRigのPrefabをシーンにドラッグ&ドロップをする

ここでSearch対象は In Packages にしましょう

スクリーンショット 2025-11-17 15.35.34.png

ステップ3: プレイヤーオブジェクトの作成

  1. Hierarchyで空のGameObjectを作成(右クリック → Create Empty
  2. 名前を「VRPlayer」などに変更
  3. OVRCameraRigを「VRPlayer」の子オブジェクトにドラッグ

ステップ4: CharacterController の追加

  1. VRPlayerオブジェクトを選択
  2. Inspectorウィンドウで Add Component をクリック
  3. 「Character Controller」と入力して、Character Controllerコンポーネントを追加
  4. CharacterControllerのパラメータを調整:
    • 例:
      • Center: (0, 1, 0) - キャラクターの中心位置
      • Radius: 0.3 - カプセルの半径
      • Height: 1.8 - キャラクターの高さ
      • Skin Width: 0.08 - 衝突判定の余白

ステップ5: ShakingMoveForCC スクリプトの追加

  1. VRPlayerオブジェクトを選択(CharacterControllerと同じオブジェクト)
  2. InspectorAdd Component をクリック
  3. 「ShakingMoveForCC」と入力して、スクリプトを追加

ステップ6: Meta Controllerの設定

  1. ShakingMoveForCCコンポーネントのインスペクターを確認

  2. パラメータを調整:

    • Move Speed: 2.0〜5.0(お好みで調整)
    • Speed Threshold: 0.1〜0.5(感度の調整)
    • Gravity: -9.81(通常の重力)
  3. 重要: スクリプト内のplayerCameraフィールドに参照を設定する必要があります

    • Hierarchyで OVRCameraRig/TrackingSpace/CenterEyeAnchor を探します
      スクリーンショット 2025-11-17 16.09.04.png
    • ShakingMoveForCCコンポーネントに上記のCenterEyeAnchorをアタッチ
      スクリーンショット 2025-11-17 16.08.24.png
  4. Camera RigのLeftControllerAnchorRightControllerAnchorの下にOVRControllerPrefabを設置する

OVRControllerPrefabはProjectビューでOVRControllerPrefabと検索して取得する

スクリーンショット 2025-11-17 16.04.59.png

ステップ7: 動作確認用の地面を作成

  1. Hierarchyで右クリック → 3D ObjectPlane を作成
  2. Planeの位置を(0, 0, 0)に設定
  3. スケールを(10, 1, 10)などに設定して広い床を作成

ステップ8: ビルド設定

  1. FileBuild Settings を開く
  2. PlatformAndroidに変更(Meta Questの場合)
  3. Switch Platformをクリック
  4. Player Settingsを開き、以下を設定:
    • XR Plug-in ManagementAndroidOpenXRにチェック
      スクリーンショット 2025-11-17 15.44.03.png

    • XR Plug-in ManagementOpenXREnabled Interaction ProfilesOculus Youch Controller Profilesをセット
      スクリーンショット 2025-11-17 15.43.26.png

    • Minimum API Level: Android 10.0以上

    • Install Location: Auto

  5. 実行時はWindowsのOculusデスクトップによるAirlinkでの起動...またはBuild And RunによるMetaQuestでのスタンドアロン実行をする

実装の詳細

コントローラー速度の取得

// 右手と左手の(ローカル座標系での)Y軸速度を取得
Vector3 velocityR = OVRInput.GetLocalControllerVelocity(OVRInput.Controller.RTouch);
Vector3 velocityL = OVRInput.GetLocalControllerVelocity(OVRInput.Controller.LTouch);

// Y軸方向の速度の絶対値を取得(上下に振る動きを検出)
float speedR = Mathf.Abs(velocityR.y);
float speedL = Mathf.Abs(velocityL.y);

移動方向の計算

// 頭(カメラ)の向いている正面方向を取得
Transform headTransform = playerCamera.transform;
Vector3 forwardDirection = headTransform.forward;
forwardDirection.y = 0; // 水平移動のみ(上下を向いても前進する)
forwardDirection.Normalize();

// 移動ベクトルを計算
float totalSpeed = (speedR + speedL) * moveSpeed;
moveDirection = forwardDirection * totalSpeed;

重力と移動の統合

// 空中にいる時は重力を加算
if (!characterController.isGrounded)
{
    verticalVelocity.y += gravity * Time.deltaTime;
}

// 水平移動と垂直移動を合算
characterController.Move((moveDirection + verticalVelocity) * Time.deltaTime);

参考リンク

1
2
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
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?