2Dのキャラ移動はできるようになったけれど、3Dになると「重力は?」「WASDでどう動かす?」「カメラはどう追わせる?」と、一気に分からなくなる——3Dの入り口でつまずく人はとても多いです。でも、部品を1つずつ押さえれば怖くありません。
この記事では、Godotの3Dキャラクター移動を、 CharacterBody3D の基本(重力・移動・ジャンプ)から、 カメラ基準の移動 、そして SpringArm3Dによる三人称カメラ まで、実際に動くコードとともに組み立てていきます。
この記事でわかること
- CharacterBody3D の基本(
velocity・move_and_slide・is_on_floor)- 重力とジャンプ の実装(
get_gravity)- カメラ基準 で移動方向を変換する(
basis)- SpringArm3D で壁を貫通しない三人称カメラを作る
CharacterBody3Dの基本:重力・移動・ジャンプ
3Dのキャラ操作には CharacterBody3D を使います。物理エンジンに任せきりにせず、 コードで速度(velocity)を決めて動かす タイプの物理ボディで、キャラクター操作にぴったりです(2D物理ボディの使い分け の3D版と考えてください)。
動きの土台は、毎フレーム3つのことをするだけです。 重力を足す・入力で速度を決める・move_and_slide() で動かす 。

extends CharacterBody3D
const SPEED := 5.0
const JUMP_VELOCITY := 4.5
func _physics_process(delta: float) -> void:
# 1. 接地していなければ重力で落下させる
if not is_on_floor():
velocity += get_gravity() * delta
# 2. 接地中にジャンプ入力があれば、上向きの初速を入れる
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
# 3. 実際に動かす(壁や床に沿って滑る)
move_and_slide()
is_on_floor():床に接しているかを返します。空中でだけ重力をかけ、接地中だけジャンプできるようにするのに使います。get_gravity():現在かかっている重力(ベクトル)を返します。これをvelocityに足すと落下します(古いプロジェクトではProjectSettingsから重力値を取っていましたが、get_gravity()の方が簡単です)。move_and_slide():velocityに従ってキャラを動かし、壁や床にぶつかったら沿って滑らせます。3Dでもこの1行が移動の心臓部です。
これで「重力で落ちてジャンプできる」土台ができました。次は左右前後の移動です。
カメラ基準で動かす
WASD入力 は Input.get_vector() でまとめて取れますが、3Dで大事なのは 「どの向きを『前』とするか」 です。多くのゲームでは、 カメラが向いている方向を『前』 にします(画面の奥=前に進む)。

そのために、入力方向を カメラの basis(向きの情報)で変換 します。basis は「そのノードがどちらを向いているか」を表す3本の軸で、これを入力に掛けると、カメラ基準の方向が得られます。
@onready var camera: Camera3D = $SpringArm3D/Camera3D
func _physics_process(delta: float) -> void:
# (重力・ジャンプは前掲)
var input := Input.get_vector("move_left", "move_right", "move_forward", "move_back")
# 入力方向をカメラの向きで変換し、水平面(y=0)の移動方向にする
var direction := (camera.global_transform.basis * Vector3(input.x, 0, input.y))
direction.y = 0
direction = direction.normalized()
if direction:
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
else:
# 入力が無ければ滑らかに停止
velocity.x = move_toward(velocity.x, 0, SPEED)
velocity.z = move_toward(velocity.z, 0, SPEED)
move_and_slide()
こうすると、カメラを右に回してから前進すれば、キャラも「新しいカメラの前」へ進みます。TPSでも見下ろしARPGでも、この「カメラ基準の移動」が自然な操作感の要になります。入力が無いときは move_toward() でゼロへ寄せ、ぬるっと止めています(move_and_slideとmove_towardの使い分け 参照)。
三人称カメラをSpringArm3Dで作る
三人称視点でよく困るのが、 キャラの後ろのカメラが壁にめり込む 問題です。これを解決するのが SpringArm3D 。カメラを対象から一定距離に保ちつつ、間に壁が来たら 自動で縮んでめり込みを防ぐ 、バネ付きの腕のようなノードです。

ノード構成はこうします。Playerの子に SpringArm3D、その子に Camera3D を置きます。

Player (CharacterBody3D)
├── MeshInstance3D # 見た目
├── CollisionShape3D # 当たり判定
└── SpringArm3D # カメラの腕(spring_lengthで距離を設定)
└── Camera3D # 実際のカメラ
SpringArm3D は Player の子なので、キャラと一緒に動きます。マウスでカメラを回したいときは、SpringArm3D を回転させます(左右はSpringArm3D自体、上下はSpringArm3Dのx回転)。
@onready var spring_arm: SpringArm3D = $SpringArm3D
func _unhandled_input(event: InputEvent) -> void:
if event is InputEventMouseMotion:
# 左右にカメラを回す(マウスの横移動でy軸回転)
spring_arm.rotate_y(-event.relative.x * 0.005)
# 上下に見上げ/見下ろし(x軸回転・角度を制限すると安定)
spring_arm.rotation.x = clampf(
spring_arm.rotation.x - event.relative.y * 0.005, -1.2, 0.4)
spring_length(腕の長さ)でカメラの距離を、回転で見る角度を決められます。あとは壁に近づけば、SpringArm3D が勝手に縮んでくれます。
実践:三人称で歩き回るキャラを組む
TPSアクションの主人公、オープンワールドの探索キャラ、3D ARPGの操作キャラ——「三人称カメラで、カメラの向きに歩き回る」のは、3D アクションの基本形です。ここまでの部品を1つのスクリプトにまとめると、こうなります。

extends CharacterBody3D
const SPEED := 5.0
const JUMP_VELOCITY := 4.5
@onready var spring_arm: SpringArm3D = $SpringArm3D
@onready var camera: Camera3D = $SpringArm3D/Camera3D
func _physics_process(delta: float) -> void:
if not is_on_floor():
velocity += get_gravity() * delta # 重力
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY # ジャンプ
var input := Input.get_vector("move_left", "move_right", "move_forward", "move_back")
var direction := (camera.global_transform.basis * Vector3(input.x, 0, input.y))
direction.y = 0
direction = direction.normalized() # カメラ基準の移動方向
if direction:
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
velocity.z = move_toward(velocity.z, 0, SPEED)
move_and_slide() # 移動
ポイントは2つです。
- 移動・重力・ジャンプ・カメラ変換を1つの
_physics_processにまとめる :物理挙動なので、必ず_processではなく_physics_processに書きます。フレームレートに左右されない安定した動きになります。 - 入力アクションは自分で定義する :
move_forwardなどのアクション名は、プロジェクト設定で自分でキーに割り当てます(InputMapによるキーバインド管理 参照)。ui_accept(ジャンプに流用)は最初から定義済みです。
キャラを動かす向き(メッシュの回転)を移動方向に合わせたくなったら、MeshInstance3D を direction の向きへ look_at や lerp で回すと、進行方向を向いて歩くようになります。
おまけ:先に知っておくと良いこと
- マウスを画面に固定する :三人称でカメラを回すなら、
Input.mouse_mode = Input.MOUSE_MODE_CAPTUREDでマウスを画面中央に固定すると操作しやすくなります(Escで解除する導線も忘れずに)。 - 坂や段差の登り方 :
floor_max_angle(登れる坂の角度)やfloor_snap_length(段差への吸着)で、坂道や階段の挙動を調整できます。キャラがガタつくときはここを見ます。 - 2Dとの違いは軸だけ :基本の流れ(重力→入力→
move_and_slide)は CharacterBody2Dのモード と同じです。2DがVector2(x, y)なのに対し、3DはVector3(x, y, z)で、水平移動が x・z、上下が y になる、という軸の違いを押さえれば移行は簡単です。
まとめ
- 3Dキャラは
CharacterBody3D+velocity+move_and_slide()で動かす is_on_floor()で接地判定し、空中はget_gravity()で落下、接地中はvelocity.yにジャンプ初速- 入力を カメラの
basisで変換すると、カメラ基準(画面の奥=前)の自然な移動になる - 三人称カメラは
SpringArm3D(→Camera3D) で。壁が来ると自動で縮んでめり込みを防ぐ - 物理挙動なので必ず
_physics_processに書く
まずは重力とジャンプだけのCharacterBody3Dを動かし、次にカメラ基準の移動、最後にSpringArm3D——と1つずつ足していけば、三人称アクションの土台が完成します。
さらに学ぶために
- Node3DとMeshInstance3Dで学ぶ3D空間の基本概念 ——3D空間・座標・見た目の基礎
- 2D物理ボディの使い分け ——CharacterBodyとRigidBodyの違い(3Dも同じ考え方)
- move_and_slideとmove_towardの使い分け ——滑らかな加減速
- InputMapによるキーバインド管理 ——移動アクションの定義