ここでは、「VR での物理的な移動」の処理について、Rigidbody とコライダーの基本的な部分から初級者向けに解説していく。 Rigidbody Locomotion をライブラリとして使う場合にも、基本的なことを理解しておくと不具合にも対応しやすくなる。


はじめに:VRの中の「体」ってどうなってるの?

VRゴーグルをかぶると、自分が仮想の世界の中に立っているように感じるよね。でも、コンピューターの中の「自分の体」は一体どんな仕組みで動いているんだろう?

このプロジェクトでは、仮想の体を カプセル型のコライダー(当たり判定)と Rigidbody(物理演算) を使って表現しているよ。

まずは「コライダー」と「Rigidbody」が何なのかを理解しよう。


第1章:物理エンジンって何?

コライダー(Collider)=「体の形」

コライダーは、ゲームの世界で「ここに何かある」と判定するための 見えない形の枠 だ。

このプロジェクトでは、プレイヤーの体を カプセル型 のコライダーで表現している。カプセルは「筒の両端が丸くなった形」で、人間の体にわりと近いし、壁や床に引っかかりにくい(丸みがあるので角を滑らかに通れる)。

      ( )     ← 丸い頭の部分
      | |
      | |     ← 筒の部分(胴体)
      | |
      ( )     ← 丸い足の部分

Rigidbody(リジッドボディ)=「物理の法則を守る体」

Rigidbody は Unity に「このオブジェクトに物理の法則を適用してね」と伝えるための仕組みだ。

Rigidbody を設定すると:

  • 重力で落ちる
  • 壁にぶつかると止まる(または跳ね返る)
  • 速度(velocity)を持てる

VRプレイヤーの体に Rigidbody をつけると、リアルな物理の動きが自動でついてくるんだ。


第2章:移動する仕組み — velocity(速度)を使う

速度を直接書き換えるとどうなる?

スティックで前に進むとき、このプログラムでは 「プレイヤーの速度(velocity)」を書き換えている。

速度 = どっちの方向に、どのくらいの速さで動くか

たとえば「前に時速 10km で動いてほしい」と思ったら、速度を前向きのベクトルに設定するだけでいい。物理エンジンが「じゃあそのスピードで動かしてあげる」と処理してくれる。

なぜ Y(上下)方向は書き換えないの?

プログラムを見ると、水平方向(X と Z)だけを書き換えて、縦方向(Y)は書き換えていない ことに気づく。

velocity.x = 左右の速度   ← プログラムが決める
velocity.z = 前後の速度   ← プログラムが決める
velocity.y = そのまま     ← 物理エンジンが決める(重力!)

もし Y まで書き換えてしまうと、重力が効かなくなって 空中に浮いたまま になってしまう。

「移動は自分でコントロール、重力は物理エンジンに任せる」という分業をしているんだ。

方向はどうやって決める?

スティックを前に倒しても、「前」がどこを指すかはプレイヤーの向きによって変わる。

このプログラムでは、頭(カメラ)の向き手(コントローラー)の向き を基準に「前」を決めている。

頭が右を向いてスティックを前に倒す
         → 右向きに進む

さらに VRならではの問題として、「頭を真上に向けた状態でスティックを前に倒したらどうなる?」というケースもある。そのときは特別な計算で、ちゃんと水平方向に進めるように調整している。


第3章:ジャンプする仕組み — 力を一瞬だけ与える

Impulse(衝撃力)って何?

ジャンプするとき、このプログラムでは AddForce(力を加える) という命令を使っている。しかも ForceMode.Impulse(瞬間的な衝撃力) というモードだ。

「Impulse」は日本語で「衝撃」という意味。

普通の力(継続的に押す力)と衝撃力の違いをイメージしてみよう:

普通の力:      ゆっくりと加速する(車のアクセルを踏み続けるイメージ)
衝撃力 (Impulse):一瞬だけ強い力を与える(ボールを蹴るイメージ)

ジャンプするときは、地面を蹴って一瞬で速度を与えるから、Impulse がぴったり合っているんだ。

「地面の上にいるか」をどうやって判定する?

空中でジャンプできないようにするために、「今、地面の上にいるかどうか」を確認する 必要がある。

このプログラムでは、カプセルの底の部分に 見えない小さな球を出して、そこに何かが当たっているかチェックする(CheckSphere) という方法を使っている。

      ( )
      | |
      | |
      ( )   ← カプセルの底
     (   )  ← ここに見えない球を出して
  =========== 地面
  
  球が地面に触れていれば「接地している」と判定!

ボタンを押した瞬間だけジャンプする仕組み

「ジャンプボタンを押し続けたら何回もジャンプしてしまう」問題を防ぐため、プログラムでは 「今フレームで押した」と「前のフレームで押していた」の差分を見る という工夫をしている。

前のフレーム:押していなかった
今のフレーム:押している
→ 「今まさに押した!」= ジャンプ実行

前のフレーム:押していた
今のフレーム:押している
→ 「押し続けている」= ジャンプしない

これを 「エッジ検出」 という。ボタンの「立ち上がり」の瞬間だけ反応する仕組みだ。


第4章:回転する仕組み — ピボット回転

単純に回転させると何が起きる?

スティックで体を回転させるとき、最もシンプルな方法は「原点を中心に回す」ことだ。でもこれをやると、カメラ(頭)の位置がぶれてしまう という問題が起きる。

【NG例:ゲームオブジェクトの原点で回転させる場合】

      カメラ
        ★         原点は足元にあるとして…

        ↓ 回転すると

           ★カメラ  ← カメラが予期しない位置に移動してしまう

VRでは、頭(カメラ)の位置がずれると VR酔い の原因になる。

ピボット回転=「足元を軸にして回る」

このプログラムでは、「頭の位置の真下(床面上のポイント)」を軸として回転させる という計算をしている。

      カメラ(頭)の位置
          ★
          |
          |
          ●  ← この点を軸(ピボット)にして回転
       =======  床

こうすることで、頭の位置を固定したまま体の向きだけを変えることができる。VR酔いを防げるんだ。

スナップ回転と連続回転の違い

回転には2種類ある:

スナップ回転(Snap Turn)

  • スティックを倒した瞬間に 一気に45°(または180°) 回転する
  • 「瞬間移動みたいな回転」
  • VR酔いしにくい(目がなめらかな回転を見なくていいから)

連続回転(Continuous Turn)

  • スティックを倒している間、ずっとじわじわ回転し続ける
  • リアルな回転感覚
  • 人によってはVR酔いしやすい

スナップ回転には デバウンス時間 という仕組みもついている。これは「一回スナップしたら、しばらく待ってから次のスナップができる」というもの。これがないと、スティックを倒している間にものすごい速さで何回も回転してしまう。


第5章:Update と FixedUpdate の違い

ゲームのループって何?

ゲームのプログラムは、毎秒何十回も「今のフレームの処理をする」というループを繰り返している。これを ゲームループ と呼ぶ。

ゲームループ(1秒間に60回など):
  ┌─────────────────────────────────┐
  │  1. 入力を読む                   │
  │  2. ゲームの状態を更新(Update) │
  │  3. 画面を描画する               │
  └─────────────────────────────────┘
          ↑繰り返す

FixedUpdate はなぜ必要なの?

物理演算(Rigidbody の動き)は FixedUpdate という別のループで動いている。

Update        :ゲームの処理速度に合わせて動く(fps が変わると間隔が変わる)
FixedUpdate   :一定の間隔で動く(デフォルト 1 秒間に 50 回)

なぜ物理演算に一定の間隔が必要なのか?

たとえば、重力で落ちるボールをシミュレーションするとき、「1秒ごとの速度変化」を計算するには、1秒の刻み幅が毎回同じでないと計算がズレてしまう んだ。

【NG例:更新間隔がバラバラな場合】
0.1秒 → 0.3秒 → 0.05秒 → 0.2秒 ...
重力の計算がずれて、ボールがぴょんぴょん跳んでしまう!

【OK:一定間隔の場合】
0.02秒 → 0.02秒 → 0.02秒 ...
安定した計算ができる!

だから、このプロジェクトでは:

  • 「スティックを読む」「ジャンプボタンを検出する」→ Update(毎フレーム)
  • 「Rigidbody に速度を適用する」「力を加える」「回転させる」→ FixedUpdate(一定間隔)

という使い分けをしているんだ。


まとめ

やりたいこと使う仕組みキーワード
前後左右に移動velocity(速度)を書き換えるlinearVelocity
ジャンプ上向きに瞬間的な力を加えるAddForce / Impulse
地面にいるか確認足元に小さな球で判定CheckSphere
スナップ回転ピボット点を軸に一気に回すMoveRotation
連続回転ピボット点を軸に少しずつ回し続けるMoveRotation
物理演算のタイミング一定間隔で処理するFixedUpdate

物理エンジンを使うと、重力・衝突・摩擦などの複雑な計算を Unity が肩代わりしてくれる。プログラマーは「どう動かしたいか(速度・力・回転)」だけを指示すればよくて、細かい物理計算は Unity に任せられる。このプロジェクトの構成では、これが「物理ベースの移動」の大きな強みのひとつだ。