3Dアクション、TPS、一人称探索——どんな3Dゲームでも、最初の一歩は「キャラを気持ちよく歩かせる」ことです。でもいざ動かそうとすると、Rigidbody でやると氷の上みたいに滑る、坂で引っかかる、ジャンプがふわふわする……と壁にぶつかりがちです。実は、プラットフォーマー的なキビキビした操作には CharacterController という専用の仕組みが定番なのです。
この記事では、CharacterControllerを使って 歩く・ジャンプする・坂を登る という3D移動の定番を組み立てます。Rigidbodyとの使い分け から、Move() による移動、isGrounded の 接地判定、重力とジャンプ の自前実装、カメラ基準 の移動、そして Slope LimitとStep Offset による坂・段差まで、ひととおり解説します。
この記事でわかること
- Rigidbody vs CharacterController の使い分 け(物理で押す/自前で動かす)
Move()とisGroundedによる移動と 接地判定- 重力とジャンプ を自前で積む(
velocity.yの扱い)- カメラの向き を基準に前後左右へ動かす
- Slope Limit / Step Offset で坂・段差を登る
- 実践:カメラ相対で歩く+ジャンプ+坂を登れる3Dキャラ
動作確認環境: Unity 2022.3 LTS / Unity 6
2つの流派:Rigidbody vs CharacterController
Unityで3Dキャラを動かす方法は、大きく2つの流派に分かれます。どちらを選ぶかで、実装も操作感もまるで変わります。

| Rigidbody方式 | CharacterController方式 | |
|---|---|---|
| 動かし方 | AddForce などで 力を加える | Move() で 自分で動かす |
| 操作感 | 慣性で滑る・跳ねる(物理的) | 慣性なし・キビキビ(プラットフォーマー的) |
| 坂・段差 | 物理任せ(引っかかりやすい) | Slope Limit / Step Offsetで 自動で登れる |
| 他の物体 | 押せる・押される | 自動では押さない |
| 向いているもの | 転がる玉、リアルな物理、乗り物 | 主人公キャラ、TPS、一人称探索 |
「キャラを狙った通りにキビキビ操作したい」ならCharacterController が定番です。物理エンジンに任せると、壁にぶつかったときの跳ね返りや、坂での滑りを細かく制御するのが難しく、初学者ほど「思った動きにならない」と悩みます。CharacterControllerは、あなたが Move() で指定した通りに動く——素直で扱いやすいのが最大の利点です。
まずはキャラのGameObjectに CharacterController コンポーネント を追加します。カプセル型の当たり判定が付き、Move() で動かせるようになります(Rigidbodyは付けません。両方付けると競合します)。
接地判定と重力・ジャンプ
CharacterControllerには 重力が自動では効きません。「自前で重力を積んで、Move() で落とす」必要があります。ここが最初のつまずきポイントです。

仕組みはこうです。 落下速度を表す velocity.y を用意し、毎フレーム重力を足して下向きに加速させ、Move() で適用する。地面に着いたら(isGrounded)速度をリセットします。
- 接地判定:
CharacterController.isGroundedで、キャラが地面に接しているか分かります。trueなら地面の上、falseなら空中です - 重力を積む:
velocity.y += gravity * Time.deltaTime(gravityは-9.81fなど負の値)を毎フレーム実行し、velocity.yをどんどんマイナスにしていきます - 接地時のリセット:
isGroundedかつvelocity.y < 0のとき、velocity.yを小さな負の値(-2fなど)にリセットします。0ではなく少しだけ下向きにするのがコツで、地面にしっかり張り付きます - ジャンプ:
isGroundedのときだけ、velocity.yに上向きの初速を与えます。あとは重力が自動で減速・落下させてくれます
なぜ0でなく
-2f?: 接地中も少しだけ下向きの速度を残しておくと、坂や段差で接地状態が安定しやすくなります。velocity.y = 0にすると、坂や段差でフワッと浮いて接地判定がガタつくことがあります。-2fはよく使われる目安で、キャラクターの大きさや重力に合わせて調整できます。
カメラ基準で動かす
「Wキーで前に進む」の「前」とは、どちらでしょうか。多くの3Dゲームでは 「カメラが向いている方向」が前 です。これを実装しないと、カメラを回したときに操作がちぐはぐになります。

やり方はシンプルです。入力(前後左右)を、 カメラの forward と right を基準に合成 します。ただしカメラは下向きに傾いていることが多いので、 上下成分(y)は0にして水平に正規化 するのがポイントです。
// 入力(-1〜1)
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
// カメラの前方・右方向(水平面に投影)
Vector3 camForward = cameraTransform.forward;
Vector3 camRight = cameraTransform.right;
camForward.y = 0f; camRight.y = 0f;
camForward.Normalize(); camRight.Normalize();
// カメラ基準の移動方向(斜め入力で速くならないよう、長さを1以下に抑える)
Vector3 moveDir = Vector3.ClampMagnitude(camForward * v + camRight * h, 1f);
最後のVector3.ClampMagnitudeは忘れやすい定番ポイントです。前と右を単純に足すと、斜め入力では長さが約1.4のベクトルになり、 斜め移動だけ1.4倍速くなる バグが生まれます。長さを1以下に丸めておけば全方向が同じ速さになります。
補足: 本記事の入力は旧Input Manager(
Input.GetAxis/Input.GetButtonDown)を使っています。New Input Systemを採用しているプロジェクトでは、入力の読み取り部分を読み替えてください(New Input Systemの記事 参照)。
これで、カメラがどちらを向いていても「Wで画面の奥へ、Dで画面の右へ」と直感通りに動きます。進行方向へキャラを向けたいときは、moveDir を使って LerpとSlerp や Quaternion で滑らかに回転させます。
坂と段差:Slope LimitとStep Offset
CharacterControllerの嬉しい点は、 坂や段差を特別なコードなしで登れる ことです。これはコンポーネントの2つの設定で決まります。

- Slope Limit(坂の限界角度): これ以下の角度の坂は 自動で登れます。デフォルトは45度。これを超える急坂は登れません。「この崖は登れない」といった地形設計に使えます
- Step Offset(段差の高さ): これ以下の高さの段差は、ジャンプせずとも 自動で乗り越えます。階段や小さな縁石を、いちいちジャンプせずに歩いて登れるようになります。これを超える高さは「壁」として扱われ、止まります
この2つを調整するだけで、「なだらかな坂は歩いて登れるが、急な崖は登れない」「階段はスムーズに上れる」といった自然な挙動が手に入ります。コードを書く必要はありません。
Step Offsetは高さより大きくしない: Step OffsetをCharacterControllerのHeightより大きくすると、挙動がおかしくなります(警告も出ます)。段差の高さは、キャラの背丈より小さい常識的な値にしておきましょう。
実践:歩く+ジャンプ+坂を登るキャラ
ここまでの要素を1つにまとめ、 カメラ基準で歩き、ジャンプでき、坂を登れる 3Dキャラを完成させましょう。三人称アクションの主人公、一人称探索のプレイヤー、TPSシューターの操作キャラ——どれもこの土台から始まります。

これまでの「カメラ基準の移動」「重力・接地」「ジャンプ」を1つのスクリプトに統合します。
using UnityEngine;
[RequireComponent(typeof(CharacterController))]
public class PlayerMovement : MonoBehaviour
{
[SerializeField] private Transform cameraTransform;
[SerializeField] private float moveSpeed = 5f;
[SerializeField] private float jumpHeight = 1.5f;
[SerializeField] private float gravity = -20f;
private CharacterController controller;
private Vector3 velocity; // y成分を落下・ジャンプに使う
void Awake() => controller = GetComponent<CharacterController>();
void Update()
{
// --- 接地状態はフレームの最初に1回だけ読んで保存 ---
bool isGrounded = controller.isGrounded;
if (isGrounded && velocity.y < 0f)
velocity.y = -2f; // 地面に張り付かせる
// --- カメラ基準の水平移動 ---
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
Vector3 camForward = cameraTransform.forward;
Vector3 camRight = cameraTransform.right;
camForward.y = 0f; camRight.y = 0f;
camForward.Normalize(); camRight.Normalize();
Vector3 moveDir = Vector3.ClampMagnitude(
camForward * v + camRight * h, 1f); // 斜め移動の1.4倍速を防ぐ
// --- ジャンプ(接地中だけ) ---
if (isGrounded && Input.GetButtonDown("Jump"))
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity); // 目標の高さから初速を逆算
// --- 重力を積む ---
velocity.y += gravity * Time.deltaTime;
// --- 水平と垂直を合成して、Move()は1回だけ呼ぶ ---
Vector3 movement = moveDir * moveSpeed + Vector3.up * velocity.y;
controller.Move(movement * Time.deltaTime);
}
}
ポイントは2つです。 「接地状態はフレームの最初に保存し、Move()は最後に1回だけ呼ぶ」(Move()を呼ぶとisGroundedの値は更新され得るため、途中で何度も読み直すとジャンプ判定が揺れます。最初にbool isGroundedへ保存して使い回し、水平と垂直は別々に計算して最後に1つの移動量へ合成する)と、 「ジャンプ初速は目標の高さから逆算する」(Mathf.Sqrt(jumpHeight * -2f * gravity) で「ちょうどjumpHeightの高さまで跳ぶ初速」が求まる。数字を勘で調整するより、跳びたい高さを直接指定できて便利)。坂・段差はCharacterControllerのSlope Limit / Step Offsetが面倒を見てくれるので、コードは移動・重力・ジャンプに集中できます。
おまけ:先に知っておくと良いこと
- CharacterControllerは自動では物を押さない: 標準状態ではRigidbodyの箱をキャラで押す、といった相互作用は起きません。押したい場合は
OnControllerColliderHitで当たった相手に自分で力を加える処理を追加します。 - isGroundedが不安定なとき: 坂の頂点や高速移動で
isGroundedがガタつくことがあります。より安定させたいなら、足元に Raycast を撃って接地を自前で判定する方法もあります。 - 移動は必ず
Time.deltaTimeを掛ける:Move()に渡す量はフレームレートに依存させないため、必ずTime.deltaTimeを掛けます。掛け忘れると、PCの性能で速度が変わってしまいます。 - カメラはCinemachineに任せる: プレイヤーを追従 するカメラは Cinemachine を使うと、追従・衝突回避・振動などを簡単に付けられます。この記事の
cameraTransformにはCinemachineの追従カメラを割り当てればOKです。
まとめ
- キビキビしたキャラ操作は CharacterController が定番。
Move()で狙った通りに動き、他の物体は自動では押さない - 重力は 自動では効かない。
velocity.yに重力を毎フレーム積み、Move()で落とす - 接地判定は
isGrounded。接地時はvelocity.yを-2fにリセットして張り付かせ、ジャンプは接地中だけ許可する - 移動は カメラの
forward/rightを基準に(y成分を0にして水平化) - 坂・段差は Slope Limit / Step Offset が自動で処理。コード不要
まずはCharacterControllerを付けたカプセルを、カメラ基準で歩かせるところから始めてください。そこにジャンプと重力を足せば、もう立派な「操作できるキャラ」です。あなたの3Dゲームの主人公は、どんな風に世界を歩き回りますか?
さらに学ぶために
- Rigidbody入門 ——物理方式との違い。転がる・跳ねる挙動が欲しいとき
- Raycast完全ガイド ——接地判定の別解、地面や壁の検出
- LerpとSlerpで滑らかに動かす ——進行方向へ滑らかに向ける
- Cinemachineフォローカメラ実践 ——プレイヤーを追従するカメラ
- Unity公式ドキュメント:CharacterController ——Move・isGrounded・各設定の一次情報