【Godot】CharacterBody3Dで作る3Dキャラクター移動 - 重力・ジャンプ・三人称カメラ

作成: 2026-07-09

Godotの3Dキャラクター移動を基礎から解説。CharacterBody3Dの重力とis_on_floor、WASD移動とジャンプ、カメラ基準の移動方向変換、SpringArm3Dによる三人称カメラまで、実践的なコードと図で学びます。

2Dのキャラ移動はできるようになったけれど、3Dになると「重力は?」「WASDでどう動かす?」「カメラはどう追わせる?」と、一気に分からなくなる——3Dの入り口でつまずく人はとても多いです。でも、部品を1つずつ押さえれば怖くありません。

この記事では、Godotの3Dキャラクター移動を、 CharacterBody3D の基本(重力・移動・ジャンプ)から、 カメラ基準の移動 、そして SpringArm3Dによる三人称カメラ まで、実際に動くコードとともに組み立てていきます。

3Dキャラクター移動のイメージ。3D空間で、三人称カメラに追われながらキャラクターが地面の上を移動する

この記事でわかること

  • CharacterBody3D の基本(velocitymove_and_slideis_on_floor
  • 重力とジャンプ の実装(get_gravity
  • カメラ基準 で移動方向を変換する(basis
  • SpringArm3D で壁を貫通しない三人称カメラを作る

Sponsored

CharacterBody3Dの基本:重力・移動・ジャンプ

3Dのキャラ操作には CharacterBody3D を使います。物理エンジンに任せきりにせず、 コードで速度(velocity)を決めて動かす タイプの物理ボディで、キャラクター操作にぴったりです(2D物理ボディの使い分け の3D版と考えてください)。

動きの土台は、毎フレーム3つのことをするだけです。 重力を足す・入力で速度を決める・move_and_slide() で動かす

CharacterBody3Dの毎フレーム処理の図。is_on_floorで接地判定し、接地していなければget_gravityで重力をvelocityに足す。接地中のジャンプ入力でvelocity.yに上向き初速を入れる。最後にmove_and_slideで実際に動かす、という3ステップ
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で大事なのは 「どの向きを『前』とするか」 です。多くのゲームでは、 カメラが向いている方向を『前』 にします(画面の奥=前に進む)。

カメラ基準の移動方向変換の図。WASDの入力(画面上での上下左右)を、カメラの向き(basis)で回転変換すると、キャラクターは常に「カメラの奥=前」へ進む。カメラを右に回すと、Wで進む方向もそれに合わせて右へ回る

そのために、入力方向を カメラの 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の使い分け 参照)。

Sponsored

三人称カメラをSpringArm3Dで作る

三人称視点でよく困るのが、 キャラの後ろのカメラが壁にめり込む 問題です。これを解決するのが SpringArm3D 。カメラを対象から一定距離に保ちつつ、間に壁が来たら 自動で縮んでめり込みを防ぐ 、バネ付きの腕のようなノードです。

SpringArm3Dの三人称カメラの図。左はプレイヤーの後ろにSpringArm3Dが伸び、その先のCamera3Dがキャラを映す通常状態。右はカメラとキャラの間に壁が来た状態で、SpringArm3Dが自動で縮んでカメラが壁の手前に寄り、壁のめり込みを防いでいる

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

三人称カメラのノード構成図。Player(CharacterBody3D)の下に、見た目のMeshInstance3D、当たり判定のCollisionShape3D、そして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つのスクリプトにまとめると、こうなります。

三人称キャラの完成イメージ図。プレイヤー(青い粘土マネキン)がSpringArm3Dの三人称カメラに追われながら、カメラの向いている方向へWASDで移動し、地面を歩いている様子
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(ジャンプに流用)は最初から定義済みです。

キャラを動かす向き(メッシュの回転)を移動方向に合わせたくなったら、MeshInstance3Ddirection の向きへ look_atlerp で回すと、進行方向を向いて歩くようになります。

おまけ:先に知っておくと良いこと

  • マウスを画面に固定する :三人称でカメラを回すなら、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キャラは CharacterBody3Dvelocitymove_and_slide() で動かす
  • is_on_floor() で接地判定し、空中は get_gravity() で落下、接地中は velocity.y にジャンプ初速
  • 入力を カメラの basis で変換すると、カメラ基準(画面の奥=前)の自然な移動になる
  • 三人称カメラは SpringArm3D(→Camera3D) で。壁が来ると自動で縮んでめり込みを防ぐ
  • 物理挙動なので必ず _physics_process に書く

まずは重力とジャンプだけのCharacterBody3Dを動かし、次にカメラ基準の移動、最後にSpringArm3D——と1つずつ足していけば、三人称アクションの土台が完成します。

さらに学ぶために