【Godot】CharacterBody2D vs RigidBody2D vs StaticBody2D - Godot Engine 2D物理ボディの使い分け

作成: 2025-12-08最終更新: 2025-12-16

Godot Engineの主要な2D物理ボディ、CharacterBody2D、RigidBody2D、StaticBody2Dの機能、特徴、パフォーマンス、そして実践的な使い分けをコード例とともに解説します。

Godot Engineで2Dゲームを開発する際、オブジェクトに「物理的な振る舞い」を持たせるために、どのノードを選択するかは非常に重要です。特に、CharacterBody2DRigidBody2DStaticBody2Dの3つの主要な物理ボディノードは、それぞれ異なる設計思想と用途を持っています。これらを正しく使い分けることは、ゲームのパフォーマンス、制御のしやすさ、そしてバグの少なさに直結します。

本記事では、これら3種類の物理ボディノードの基本的な定義、特徴、そしてどのようなゲームオブジェクトに適用すべきかを、具体的なコード例を交えて解説します。


3つの物理ボディ:基本概念

これら3つのノードは、すべてCollisionObject2Dを継承し、衝突形状を持つことができますが、その「動き」の主体が全く異なります。

ノード名制御の主体物理エンジンの影響他のオブジェクトとの相互作用主な用途
StaticBody2Dなし(固定)受けない衝突をブロックする「壁」になる地面、壁、動かない障害物
RigidBody2D物理エンジン受ける(完全にシミュレーション)衝突によって動かされ、また動かすボール、箱、物理パズル要素
CharacterBody2D開発者のコード一部受ける(衝突検知)衝突をブロックするが、基本的には動かされないプレイヤー、敵、移動プラットフォーム

1. StaticBody2D:不動の基準点

StaticBody2Dは、物理演算の世界における「不動の存在」です。重力や外部からの力によって動くことは一切ありません。その役割は、他のオブジェクトが衝突するための「壁」や「床」を提供することです。

  • 主なプロパティ: constant_linear_velocity, constant_angular_velocity
  • ポイント: 基本的に動かすべきではありませんが、もし動かす場合はAnimatableBody2Dの使用を検討してください。これはアニメーションと同期して動く特殊な静的ボディです。

2. RigidBody2D:物理法則の体現者

RigidBody2Dは、物理エンジンの主役です。一度ワールドに配置すれば、あとは重力、摩擦、衝突といった物理法則に従って自律的に動き回ります。開発者はpositionを直接操作するのではなく、力やインパルスを与えることで間接的に制御します。

実践コード例:RigidBody2Dでオブジェクトを投げる

extends RigidBody2D

@export var throw_force: float = 500.0

func throw(direction: Vector2):
    # 既存の動きをリセット
    linear_velocity = Vector2.ZERO
    angular_velocity = 0.0

    # 指定された方向に衝撃を与える
    apply_central_impulse(direction.normalized() * throw_force)

パフォーマンスに関する注意点

RigidBody2Dは計算コストが高いノードです。数百個のRigidBody2Dが互いに衝突しあうようなシーンでは、パフォーマンスが著しく低下する可能性があります。オブジェクトが静止しているときに物理計算をスキップする スリープ(can_sleep 設定を有効にすることが非常に重要です。


3. CharacterBody2D:コードによる精密制御

CharacterBody2Dは、開発者がキャラクターの動きを完全にコントロールするために設計された、最も特殊で最も重要なノードです。物理エンジンの衝突検知能力を利用しつつも、動きそのものはmove_and_slide()メソッドを通じてコードで決定します。

実践コード例:より実践的なプレイヤー制御

Godot 4ではvelocityが組み込みプロパティになりました。以下は、ジャンプの先行入力(Coyote Time)とジャンプバッファリングを考慮した、より実践的なコードです。

extends CharacterBody2D

@export var speed: float = 300.0
@export var jump_velocity: float = -450.0
@export var gravity: float = 980.0

# コヨーテタイムとジャンプバッファ用のタイマー
# CoyoteTimer: wait_time = 0.1, one_shot = true
# JumpBufferTimer: wait_time = 0.15, one_shot = true
@onready var coyote_timer: Timer = $CoyoteTimer
@onready var jump_buffer_timer: Timer = $JumpBufferTimer

var was_on_floor: bool = false

func _physics_process(delta: float) -> void:
    # 1. 重力の適用
    if not is_on_floor():
        velocity.y += gravity * delta

    # 2. ジャンプ入力のバッファリング
    if Input.is_action_just_pressed("jump"):
        jump_buffer_timer.start()

    # 3. ジャンプの実行
    # 地面にいるか、コヨーテタイム中、かつジャンプがバッファされていればジャンプ
    if (is_on_floor() or not coyote_timer.is_stopped()) and not jump_buffer_timer.is_stopped():
        velocity.y = jump_velocity
        jump_buffer_timer.stop()

    # 4. 左右移動
    var direction: float = Input.get_axis("move_left", "move_right")
    velocity.x = direction * speed

    # 5. 移動と衝突検知
    var was_on_floor_before = is_on_floor()
    move_and_slide()

    # 6. 地面から離れた瞬間にコヨーテタイマーを開始
    if not is_on_floor() and was_on_floor_before:
        coyote_timer.start()

このコードは、単に動くだけでなく、プラットフォームゲームで「操作感が良い」と感じさせるための重要なテクニックを実装しています。


よくある間違いとベストプラクティス

よくある間違いなぜ問題なのかベストプラクティス
プレイヤーキャラクターにRigidBody2Dを使う物理演算の慣性や反発で、入力通りの機敏な動きが実現できない。プレイヤーや敵には必ずCharacterBody2Dを使う
CharacterBody2Dpositionを直接変更するmove_and_slide()による衝突検知が機能せず、壁を抜けたりする。必ずvelocityを更新し、move_and_slide()を呼び出す
物理演算を_process(delta)で行う_physics_process(delta)は固定フレームレートで呼び出され、物理演算の安定性を保証する。物理関連の処理はすべて_physics_process(delta)に記述する
複雑すぎるCollisionShape2Dを使う多角形の頂点数が多いほど、衝突判定の計算コストが増大する。できるだけシンプルな形状(RectangleShape2D, CircleShape2D)を使う。

適切なノード選択のためのヒント

ノード選択に迷った際は、以下の質問に答えてみてください。

  1. そのオブジェクトは動きますか?
    • No: StaticBody2Dを選択します。(例:壁、地面)
  2. そのオブジェクトの動きを、物理法則(重力、衝突、力)に完全に任せたいですか?
    • Yes: RigidBody2Dを選択します。(例:ボール、箱)
  3. そのオブジェクトの動きを、プレイヤーの入力やAIロジックで精密に制御したいですか?
    • Yes: CharacterBody2Dを選択します。(例:プレイヤー、敵)

まとめ

Godot Engineの2D物理ボディは、それぞれの役割が明確に分かれています。

  • StaticBody2D: 動かない環境要素。
  • RigidBody2D: 物理法則に完全に委ねるオブジェクト。
  • CharacterBody2D: コードで精密に制御するキャラクター。

これらの違いを理解し、ゲームオブジェクトの性質に合わせて適切なノードを選択することで、よりスムーズで、意図した通りの挙動をするゲーム開発を進めることができるでしょう。