godot-physics について
Godot 4.xの2D・3D物理を扱う開発者向けのスキルガイドです。物理ボディ、衝突、重なり検出、レイ判定に加え、Jolt Physicsの違いも説明します。
主な機能
- 01物理ボディタイプの選択
- 02衝突レイヤーとマスクの設定
- 03Areaによる重なり検出
- 04RigidBodyへの力とインパルス
- 05レイクエリの実行
- 06Jolt Physicsの差異の把握
活用シーン
- 01壁や敵との衝突設定
- 02トリガーやヒットボックスの作成
- 03物理シミュレーション物体の駆動
- 04視線や接地の判定
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ gamedev-skills/ awesome-gamedev-agent-skills --skill godot-physicsインストール後、Claude Code で/godot-physicsを入力して読み込まれたか確認します。
同梱ファイルreferences/bodies-and-queries.md
詳細
Godot Physics(4.x、2D + 3D)
適切な物理ボディを選び、コリジョンレイヤー/マスクを設定し、重なりを検出してレイをキャストします。概念は2Dと3Dの両方に適用できます(2D/3Dのサフィックスを入れ替えてください)。対象はGodot 4.7です。3Dでは、Godot 4.6以降で作成されたプロジェクトはデフォルトでJolt Physicsを実行します。古いプロジェクトでは、切り替えていない限りGodotPhysics3Dが使われます。2Dでは常にGodot独自の2Dエンジンが使われます。
使用する場面
- ボディタイプの選択、適切なオブジェクト同士が衝突するようにコリジョンレイヤー/マスクを設定する場合、
Areaで重なり(トリガー、ヒットボックス)を検出する場合、RigidBodyに力/インパルスを適用する場合、視線や地面のチェック用にレイをキャストする場合に使用します。
使用しない場面: キネマティックキャラクターコントローラー(move_and_slide)→ godot-2d-movement;タイルのコリジョン設定 → godot-tilemap;物理の感触(タイムステップ、質量、ジッター)の調整 → physics-tuning。
基本的なワークフロー
- 3Dでは、挙動のデバッグ前に実行中のエンジンを確認します。 Project Settings > Physics > 3D > Physics Engine(
project.godot内の[physics]3d/physics_engine="Jolt Physics")を確認してください。APIは同じですが、ジョイント、レイキャストの面インデックス、キネマティック接触、コリジョンマージンの挙動は異なります(「注意点」を参照)。 - ボディタイプを選択します。
StaticBody— 動きません(床、壁)。衝突しますが、シミュレーションは行われません。RigidBody— 完全にシミュレーションされます(重力、力、反発)。positionを直接設定せず、力/インパルスを適用するか、linear_velocityを設定してください。CharacterBody— スクリプトで動かすキネマティックボディです(godot-2d-movementを参照)。Area— 重なりを検出し、重力/減衰を適用できます。ソリッドな衝突はありません。 すべてのボディには、子としてCollisionShape(またはCollisionPolygon)が必要です。
- レイヤーとマスクを設定します。 ボディは自身のレイヤーに属し、自身のマスクの対象を検知します。一方のボディのレイヤーが他方のマスクに含まれている場合にのみ、2つのボディは相互作用します。わかりやすいように、Project Settings > Layer Namesでレイヤーに名前を付けてください。
Areaのシグナル(body_entered、area_entered)で重なりを検出します。RigidBodyには力/インパルスを適用します。 または、完全に制御する場合は_integrate_forcesをオーバーライドします。- レイをキャストします。 毎フレームポーリングする
RayCast2D/3Dノードを使うか、コードから一度だけスペース状態クエリを実行します。
パターン
1. コリジョンレイヤーとマスク(コードから設定)
# Player is on layer 1, scans layers 2 (walls) and 3 (enemies).
func _ready() -> void:
set_collision_layer_value(1, true) # I am on layer 1
set_collision_mask_value(2, true) # I collide with things on layer 2
set_collision_mask_value(3, true) # ...and layer 3
# Bit-field forms also exist: collision_layer = 1; collision_mask = 0b110
2. トリガー/ヒットボックスとしてのArea2D
extends Area2D # e.g. a damage zone
func _ready() -> void:
body_entered.connect(_on_body_entered)
area_entered.connect(_on_area_entered)
func _on_body_entered(body: Node2D) -> void:
if body.has_method("take_damage"):
body.take_damage(10)
func _on_area_entered(area: Area2D) -> void:
print("Overlapped area: ", area.name)
3. RigidBody3Dへの力とインパルスの適用
extends RigidBody3D
func push(direction: Vector3) -> void:
apply_central_impulse(direction * 8.0) # instantaneous velocity change
func _physics_process(_delta: float) -> void:
apply_central_force(Vector3.FORWARD * 4.0) # continuous force (per tick)
# Never set `position` on a RigidBody to move it; use forces/impulses or
# set linear_velocity. Use freeze=true if you must hold it in place.
4. 2種類のレイキャスト
# A) RayCast2D node: enable it, then poll after physics has updated.
@onready var ray: RayCast2D = $RayCast2D # set target_position in the editor
func _physics_process(_delta: float) -> void:
if ray.is_colliding():
var hit := ray.get_collider()
var point := ray.get_collision_point()
# B) One-shot query from code (no node needed).
func ground_under(global_from: Vector2) -> Dictionary:
var space := get_world_2d().direct_space_state
var query := PhysicsRayQueryParameters2D.create(global_from, global_from + Vector2(0, 64))
query.collision_mask = 1 # only layer 1
return space.intersect_ray(query) # {} if nothing hit, else collider/position/normal
注意点
- レイヤーとマスクの混同は、最も多いバグです。レイヤーは「自分が何であるか」、マスクは「何を探すか」です。AがBを検出するには、BのレイヤーがAのマスクに含まれている必要があります。検出は一方向のみでも可能です。
positionによるRigidBodyの移動はソルバーと競合し、すり抜けやジッターを引き起こします。インパルス/力を使うか、linear_velocityを設定するか、freezeしてください。テレポートするには、_integrate_forces内で位置を設定し、速度をゼロにします。Areaがイベントを発生させない場合、監視も監視可能も設定されていないか、レイヤー/マスクが重なっていない可能性があります。Areaが検出するにはmonitoringを有効にする必要があります。ほかのオブジェクトから検出できるようにするには、monitorableを有効にします。- RayCast2D/3Dから古いデータが読み取られる、またはデータが取得できない場合、
enabledが無効になっているか、物理更新前に読み取っている可能性があります。_physics_process内で読み取り、同じティック内で移動した後はforce_raycast_update()を呼び出してください。 CollisionShapeを忘れる(または空のままにする)と、ボディは衝突しません。- 高速なオブジェクトは薄い壁をすり抜けることがあります。RigidBodyの連続CD(
continuous_cd)を有効にするか、レイキャストに基づくチェックを使ってください。 intersect_rayは自身のボディを除外しますか? 自分自身へのヒットを除外するには、query.exclude = [self.get_rid()]を渡してください(ノードの配列ではなく、Array[RID]です)。
Jolt Physics(3D)の違い
- Jolt では、
intersect_ray()/RayCast3Dの結果でface_indexは常に-1です。 必要な場合は、Project Settings > Physics > Jolt Physics 3D > Queries > Enable Ray Cast Face Index を有効にしてください(ConcavePolygonShape3Dではメモリ使用量が約25%増加します)。 - エンジンを切り替えると、ボディが1つだけのジョイントで制限が反転します。 Jolt は
ボディ1つだけの場合、そのボディを
node_b、node_aをワールドとして扱います。GodotPhysics3D は常にnode_aとして扱います。ボディを Jolt が想定するスロットに割り当てるか、以前のプロジェクトとの互換性のために Physics > Jolt Physics 3D > Joints > World Node を使用してください。 - Jolt ではジョイントのソフト制限プロパティは機能しません(例:Pin、Hinge、ConeTwist ジョイントの
bias/softness/relaxation、Slider および Generic6DOF ジョイントの制限の softness/restitution/damping)。デフォルト以外の値に設定すると Godot が警告します。 - フリーズ中のキネマティックな
RigidBody3Dは、静的ボディやキネマティックボディとの接触を報告しません。max_contacts_reported > 0の場合も同様です。ゲームプレイでこれらの接触が必要な場合は、Physics > Jolt Physics 3D > Simulation > Generate All Kinematic Contacts を有効にしてください。 - Jolt では、形状の
marginは形状に余白を加えるのではなく、縮小します。 そのためサイズは 正確に保たれますが、小さな形状では形状クエリが不自然な法線を返す場合があります。有効な margin は Physics > Jolt Physics 3D > Collisions > Collision Margin Fraction で決まります。 - Jolt では、
Area3DがSoftBody3Dに対してもbody_enteredを発火するようになりました(GodotPhysics3D では発火しません でした)。以前の動作を期待する場合は、レイヤー/マスクでソフトボディを除外してください。
参考資料
_integrate_forces、ジョイント、一方向衝突、PhysicsServerの直接アクセス、 形状クエリ(intersect_shape)、3D のmove_and_collideについては、references/bodies-and-queries.mdをお読みください。- Jolt 固有の情報:Godot のドキュメント「Using Jolt Physics」
(
https://docs.godotengine.org/en/stable/tutorials/physics/using_jolt_physics.html)。
関連スキル
godot-2d-movement— キネマティックなCharacterBody2Dコントローラー。godot-tilemap— タイルの衝突形状とそのレイヤー。physics-tuning— エンジンに依存しない操作感の調整:タイムステップ、質量、抵抗、CCD。godot-3d-essentials— これらのボディが配置される3Dシーンのセットアップ。
コメント
Markdown 対応