Godot 4のCharacterBody2D/3D 完全ガイド

1. はじめに

Godot 4ではキャラクター移動に大きな変更が加えられました。旧KinematicBody2DKinematicBody3DノードはCharacterBody2DCharacterBody3Dに改名され、move_and_slide() APIは完全に再設計されました。Godot 3からの移行でも、新規開始でも、このガイドで必要な情報を全てカバーします。

CharacterBody2DCharacterBody3Dはコードで制御されるキャラクター用の物理ボディです。RigidBodyとは異なり、力に自動的に反応せず、移動はすべてスクリプトで制御します。そのため、プレイヤーキャラクター、NPC、そして正確で決定論的な動きが必要なすべてのものに最適です。

2. Godot 3からの変更点

Godot 3からGodot 4でのキャラクター移動における主要な変更点は以下の通りです:

重要なポイント

Godot 3ではmove_and_slide()は結果の速度を返していました。Godot 4ではbool(衝突が発生したかどうか)を返し、velocityはvelocityプロパティ上で直接更新されます。

3. 基本的な2Dプラットフォーマーコントローラー

これは標準的な横スクロールプラットフォーマーコントローラーです。キャラクターは左右に移動し、地面にいるときにジャンプできます。これはGodotが新しいCharacterBody2Dスクリプトを作成する際に生成するテンプレートです。

GDScript — platformer_controller.gd
extends CharacterBody2D

const SPEED = 300.0
const JUMP_VELOCITY = -400.0

func _physics_process(delta: float) -> void:
    # Apply gravity when not on floor
    if not is_on_floor():
        velocity += get_gravity() * delta

    # Jump when on floor and jump pressed
    if Input.is_action_just_pressed("ui_accept") and is_on_floor():
        velocity.y = JUMP_VELOCITY

    # Horizontal movement
    var direction := Input.get_axis("ui_left", "ui_right")
    if direction:
        velocity.x = direction * SPEED
    else:
        velocity.x = move_toward(velocity.x, 0, SPEED)

    move_and_slide()

1行ずつの解説

ヒント: 必要なノード構造

CharacterBody2Dには少なくとも1つのCollisionShape2D子ノードに形状(RectangleShape2DやCapsuleShape2D等)を設定する必要があります。これがないとmove_and_slide()は衝突を検出しません。

4. 基本的な2Dトップダウンコントローラー

トップダウンゲーム(RPG、ツインスティックシューター等)では、重力なしで4方向に移動します。プラットフォーマーよりコードはシンプルです。

GDScript — topdown_controller.gd
extends CharacterBody2D

const SPEED = 200.0

func _physics_process(delta: float) -> void:
    var input_direction := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
    velocity = input_direction * SPEED
    move_and_slide()

仕組み

加速と摩擦の追加

加速と減速でより滑らかな操作感にするには:

GDScript — topdown_smooth.gd
extends CharacterBody2D

const SPEED = 200.0
const ACCELERATION = 1200.0
const FRICTION = 1000.0

func _physics_process(delta: float) -> void:
    var input_direction := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")

    if input_direction != Vector2.ZERO:
        velocity = velocity.move_toward(input_direction * SPEED, ACCELERATION * delta)
    else:
        velocity = velocity.move_toward(Vector2.ZERO, FRICTION * delta)

    move_and_slide()

5. 3Dサードパーソンコントローラー

3D版も同じパターンに従います。主な違いはVector3を使用し、transform.basisで2D入力を3Dワールド空間の移動に変換する点です。

GDScript — character_3d.gd
extends CharacterBody3D

const SPEED = 5.0
const JUMP_VELOCITY = 4.5

func _physics_process(delta: float) -> void:
    # Apply gravity
    if not is_on_floor():
        velocity += get_gravity() * delta

    # Jump
    if Input.is_action_just_pressed("ui_accept") and is_on_floor():
        velocity.y = JUMP_VELOCITY

    # Get input and convert to 3D direction
    var input_dir := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
    var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).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()

2Dとの主な違い

注意: get_gravity()はGodot 4.4以降が必要

get_gravity()メソッドはGodot 4.4で追加されました。古いバージョンでは、2Dの場合はVector2(0, ProjectSettings.get_setting("physics/2d/default_gravity"))、3Dの場合はVector3(0, -ProjectSettings.get_setting("physics/3d/default_gravity"), 0)を使用してください。

6. 主要プロパティリファレンス

CharacterBody2DCharacterBody3Dの両方が共有する重要なプロパティです。インスペクタまたはコードで調整できます。

プロパティ デフォルト 説明
velocity Vector2 / Vector3 Vector2.ZERO キャラクターの速度。move_and_slide()を呼ぶ前に設定。呼び出し後は結果の速度で更新されます。
floor_snap_length float 1.0 move_and_slide_with_snap()の代替。キャラクターを床にスナップする距離。0で無効化。坂道や階段に便利。
up_direction Vector2 / Vector3 Vector2.UP 「上」の方向を定義。これにより床・壁・天井の判定が決まります。デフォルトは2Dで(0, -1)、3Dで(0, 1, 0)
floor_stop_on_slope bool true trueの場合、静止時にキャラクターが坂道で滑りません。プラットフォーマーに必須。
floor_max_angle float 0.785 (45°) 歩行可能な最大勾配角度(ラジアン)。これより急な面は壁として扱われます。60度に設定するにはdeg_to_rad(60)を使用。
max_slides int 6 move_and_slide()呼び出しごとの最大衝突反復回数。値が大きいほど正確だが遅くなります。
wall_min_slide_angle float 0.262 (15°) 壁スライドの最小角度。ほぼ平行な壁にキャラクターが引っかかるのを防ぎます。
platform_on_leave PlatformOnLeave ADD_VELOCITY 移動プラットフォームを離れた時の挙動。ADD_VELOCITYで運動量を保存、ADD_UPWARD_VELOCITYで上方成分のみ追加、DO_NOTHINGでプラットフォームの速度を無視。
slide_on_ceiling bool true trueの場合、天井でのスライドを許可。falseの場合、天井に当たると水平速度が停止。

7. move_and_slide()後の衝突検出

move_and_slide()を呼んだ後、発生した衝突を検査できます。特定のコライダータイプへの反応、着地時のサウンドエフェクト再生、壁ジャンプの実装などに便利です。

GDScript — collision_detection.gd
func _physics_process(delta: float) -> void:
    # ... set velocity here ...
    move_and_slide()

    # Check all collisions from this frame
    for i in get_slide_collision_count():
        var collision := get_slide_collision(i)
        var collider := collision.get_collider()
        print("Collided with: ", collider.name)
        print("Normal: ", collision.get_normal())
        print("Position: ", collision.get_position())

    # Practical example: bounce off enemies
    for i in get_slide_collision_count():
        var collision := get_slide_collision(i)
        if collision.get_collider().is_in_group("enemies"):
            velocity = collision.get_normal() * 300
            break

便利なKinematicCollisionメソッド

8. 移行チートシート

Godot 3からGodot 4への変換クイックリファレンス:

Godot 3 Godot 4
KinematicBody2D CharacterBody2D
KinematicBody3D CharacterBody3D
velocity = move_and_slide(velocity, Vector2.UP) velocity = ...
move_and_slide()
move_and_slide_with_snap(vel, snap, up) floor_snap_length = 4.0
move_and_slide()
var vel = move_and_slide(...)
velocityを返す
move_and_slide()
velocityプロパティが直接更新される
var gravity = ProjectSettings.get("physics/2d/default_gravity") get_gravity() (4.4+)
move_and_slide(..., up_direction, ...) up_direction = Vector2.UP (プロパティとして設定)
move_and_slide(..., stop_on_slope, ...) floor_stop_on_slope = true (プロパティとして設定)
Godotの自動変換ツール

Godot 4でGodot 3プロジェクトを開くと、エンジンがプロジェクトの変換を提案します。ノードの名前変更やスクリプトの更新を試みますが、move_and_slide()の呼び出しは必ずしも正しく変換されません。移動コードの手動修正が必要になることが多いです。

9. よくある間違い

間違い1: move_and_slide()に引数を渡す

間違い
# ERROR: move_and_slide() takes no arguments in Godot 4
velocity = move_and_slide(velocity, Vector2.UP)
正解
# Set velocity, then call move_and_slide() with no arguments
velocity.x = direction * SPEED
move_and_slide()

間違い2: move_and_slide()の前にvelocityを設定し忘れる

間違い — velocityが設定されず、何も動かない
func _physics_process(delta: float) -> void:
    move_and_slide()  # velocity is Vector2.ZERO — nothing happens

間違い3: _physics_process()の代わりに_process()を使用

move_and_slide()は固定レート(デフォルト60Hz)で実行される_physics_process()内で呼ぶ必要があります。_process()を使うと物理がレンダリングフレームレートに連動し、挙動が不安定になります。

間違い4: CollisionShapeを設定していない

CollisionShape子ノードのないCharacterBody2D/CharacterBody3Dはすべてを通り抜けます。衝突形状がない場合、エディタに警告アイコンが表示されます。

間違い5: 毎フレームvelocity.yを重力で上書きする

間違い — velocity.yがリセットされジャンプが機能しない
# This overwrites any jump velocity!
velocity.y = gravity * delta  # should be +=, not =
正解 — 重力を蓄積
# Gravity accumulates over time
velocity += get_gravity() * delta

間違い6: 床の上にいるとき重力を適用する

重力は必ずif not is_on_floor()で囲んでください。このチェックがないと、床の上でも重力が蓄積し続けます。キャラクターが崖から歩いて落ちるとき、自然に落下する代わりに極端な速度で急降下します。

10. AIでキャラクターコントローラーをセットアップ

AIにキャラクターコントローラーをセットアップさせたいですか?

Godot MCP Proを使えば、AIアシスタントがCharacterBodyノードの作成、物理プロパティの設定、衝突形状のセットアップ、移動スクリプトの作成、ゲームの起動、移動テストまで — すべて自然言語のプロンプトから実行できます。

add_node setup_physics_body setup_collision set_physics_layers create_script simulate_key play_scene capture_frames
Godot MCP Proを入手 — $15