【Godot】Godotの3D当たり判定入門:RigidBody3Dで木箱を倒し、Area3Dで宝箱の前を感知する

作成: 2026-09-23最終更新: 2026-10-10

3Dの当たりの形の選び方と、RigidBody3Dで木箱の山を崩し、Area3Dで宝箱の前に立ったことを感知する方法を解説します。

3Dのゲームで、ボールをぶつけて木箱の山を崩したり、宝箱の前に立ったら「開ける」を出したりするには、RigidBody3D と Area3D を使います。どちらも、見た目とは別に当たりの形を持たせて作ります。

形を付けずに置くと、箱は床をすり抜けて落ち、ボールは箱を素通りします。物理が見ているのは見た目のメッシュではなく、そこに重ねた当たりの形だからです。

この記事では、当たりの形の選び方と、RigidBody3D で木箱の山を崩し、Area3D で宝箱の前を感知する方法を解説します。

積んだ木箱にボールが飛んでいき、横では宝箱の前に人形が立って、宝箱の上に吹き出しが出ている

この記事でわかること

  • 物理が見ているのは、見た目のメッシュではなく当たりの形であること
  • 当たりの形を動くかどうかで選び、大きさは Scale ではなく形のサイズで変える方法
  • RigidBody3D を力で動かす方法と、重さの効き方
  • Area3D で「前に立った」を取り、プレイヤーだけに反応させる方法

動作確認環境: Godot 4.7

Sponsored

見た目のメッシュと当たりの形

3Dの物は、見た目と当たりを別々に持ちます。木箱なら、MeshInstance3D が見た目の絵で、CollisionShape3D が当たりの形です。2つは、動き方を決める物理ボディの直接の子に並べます。

木箱を分解した図。物理ボディの下に、見た目の MeshInstance3D と当たりの CollisionShape3D が並び、物理は形だけを見る

物理が見ているのは、当たりの形だけです。積める・落ちる・反応するは、すべて形のほうで決まります。見た目だけ置いた箱は床をすり抜け、形が見た目より小さいと箱が床に沈んで見えます。

当たりの形は、実行中に表示できます。エディタ上部の Debug メニューで Visible Collision Shapes をオンにします。3Dの当たりで困ったら、まずこれで形がどこにあるかを確かめます。

物理ボディの選び方は2Dと同じで、動きを決めるのが誰かで分けます。当たらずに知らせるだけの Area3D も並べておきます。

  • StaticBody3D: 誰も動かさない。床、壁、宝箱
  • RigidBody3D: 物理エンジンが動かす。木箱、ボール、落石
  • CharacterBody3D: 自分のコードが動かす。プレイヤー、敵
  • Area3D: 当たらずに、重なりを知らせる。宝箱の前、落とし穴、回復の泉

それぞれの考え方は 2Dの物理ボディ入門 で扱っています。3Dで新しく決めるのは、当たりの形です。

他のエンジンでいうと: RigidBody3D は Unity の Rigidbody や、UE で Simulate Physics を有効にしたコンポーネントにあたります。Area3D は Unity の Is Trigger を有効にした Collider や、UE で Overlap を検出するコリジョンに近い仕組みです。

当たりの形の選び方

当たりの形は、見た目をそのまま写すのではなく、単純な形で近づけます。選び方は、その物が動くかどうかで分かれます。

当たりの形の早見図。木箱は Box、ボールは Sphere、人は Capsule、樽は Cylinder。動かない地形だけ Trimesh
  • 動く物: 箱・球・カプセル・円柱の形(BoxShape3D など)で近づける。単純な形で表せない小物は、Convex(へこみを埋めて包んだ形)にする
  • 動かない物: 床や壁も単純な形で足りる。くぼみのある地形や建物だけ、メッシュの三角形をそのまま使う Trimesh にする

Trimesh(ConcavePolygonShape3D)は、動かないステージ用の形です。物理で動く木箱や岩に付けると、正しく当たりません。メッシュから当たりを作ることもできます。MeshInstance3D を選ぶと上部に出る Mesh メニューで、形の種類(Trimesh か Convex)と置き場所を選びます。木箱のように物理ボディの子にあるメッシュなら、置き場所は兄弟(Sibling)にします。

形を替えると、同じ物の動きが変わります。ボールに箱の形を付けると、滑ったり角で倒れたりして、球のようには転がりません。木箱に球の形を付けると、見た目は平らでも積み重ねが不安定になります。動きがおかしいときは、スクリプトより先に形を疑います。

同じボールでも、球の形なら転がっていき、箱の形を付けると球のようには転がらなくなる

当たりの大きさの変え方

箱を大きくしたいとき、ノードの Scale を2倍にしたくなります。物理ボディと CollisionShape3D では、これを避けます。

大きさは Scale を1のまま、BoxShape3D と BoxMesh の Size を同じ値にそろえて変える

物理ボディや CollisionShape3D の Scale を変えると、思った大きさや動きにならないことがあります。縦だけ伸ばすような、軸ごとに倍率が違う Scale は特に避けます。大きさは形のほうで変えます。単位はメートルです。箱は BoxShape3D の Size、球は SphereShape3D の Radius です。カプセルと円柱は Radius と Height で変えます。見た目のメッシュも同じ大きさにそろえます。複製した箱は同じ Shape(使い回せるデータ=リソース)を共有しているので、1つだけ変えるときは、Shape 欄の右の ▼ から Make Unique を選んでから変えます。

Unity では Collider が Transform の Scale に付いてくるので、ここは手癖が裏目に出ます。物理ボディとその当たりの Scale は、(1, 1, 1) のままにしておきます。

Sponsored

RigidBody3D と力(インパルス)

RigidBody3D は、動きを物理エンジンに任せる物理ボディです。重力で落ち、ぶつかれば押し返されます。コードからは、位置ではなく力を渡します。

ball.apply_central_impulse(Vector3(0, 3, -12))   # 一瞬だけ押し出す

インパルスは、一瞬だけ加える勢いです。速さの変化は「インパルス ÷ Mass(重さ)」で決まります。Mass の既定は 1 なので、上の1行でボールは (0, 3, -12) の速さで飛び出します。同じインパルスを Mass が 4 の物に与えると、速さは4分の1です。

同じインパルスを軽いボールと重いボールに与えた図。軽いボールは速く遠くまで飛び、重いボールは同じ勢いでも遅く手前に落ちる

インパルスは1回だけ呼びます。毎フレーム呼ぶと、そのたびに加速します。押し続けたいときは、押しているあいだ物理の更新ごとに、力を加える apply_central_force() を呼びます。

RigidBody3D の position を毎フレーム書き換えるのも避けます。物理が決めた位置とスクリプトの位置が取り合いになり、震えたり、壁にめり込んだりします。投げるまで止めておきたいときは、Freeze をオンにしておきます。凍っているあいだは力が効かないので、投げる瞬間にオフにしてから、インパルスを渡します。

落ち着いた RigidBody3D は、しばらくすると自分で眠り(Sleeping)、計算を休みます。動いている物がぶつかるなどすると起きて動き出すので、ふだんは気にしなくて大丈夫です。

Area3D(重なりを知らせる範囲)

Area3D は、当たりの形を持っていても物を止めません。形に何かが入ったときと出たときに、シグナルで知らせるだけです。宝箱の前、落とし穴、回復の泉のように「そこに入ったか」を知りたい場所に置きます。

宝箱の前の Area3D に、人形とボールと床が重なっている。何もしないと全部に反応し、グループで player だけを見るとプレイヤーにだけ反応する

入ったときは body_entered、出たときは body_exited が、入った物を引数にして届きます。

ここで引っかかるのが、反応する相手です。Area3D は、Collision Mask(見に行く相手のレイヤー)に合う物理ボディなら何にでも反応します。プレイヤーにも、転がってきたボールにも、重なっている床にもです。既定はどれもレイヤー1なので、そのままでは全部が相手です。

プレイヤーだけに反応させるには、body_entered につないだ関数の中で、届いた物がプレイヤーかを確かめます。見分けに使うのはグループです。グループは、ノードに付けておく分類の名前で、Player を player グループに入れておき、届いた物がそのグループに入っているかを見ます。

func _on_front_area_body_entered(body: Node3D) -> void:
	if body.is_in_group("player"):      # プレイヤーのときだけ
		open_label.visible = true

レイヤーで分ける方法もあります。プレイヤーの Collision Layer を2へ移し、Area3D の Collision Mask を2だけにします。Mask だけ変えてプレイヤーを1に残すと、誰にも反応しなくなります。プレイヤーに当たる敵や弾があれば、その Collision Mask にも2を入れます。レイヤーの考え方は Collision Layer と Mask 入門 にあります。

Sponsored

実践:ボールで木箱を崩し、宝箱の前で「開ける」を出す

アクションゲームの樽、パズルの積み木、探索ゲームの宝箱 —— 崩れる物と、前に立つと反応する場所は、3Dのゲームの定番です。ボールで木箱の山を崩し、宝箱の前に立つと「開ける」と出るところまで作ります。

実践の配置。奥に木箱が3つ積まれ、手前にボール、右に宝箱と、その前の Area3D の範囲、プレイヤーの人形が立っている

① 置くもの

新しい3Dシーンを作り、ルートを Node3D にして Main と名付けます。空と太陽は、3Dビューの上のツールバーで、太陽と環境のプレビューボタンの右にある「︙」から、「Add Sun to Scene」と「Add Environment to Scene」を1つずつ押して置きます。

残りは次の表のとおりです。物理ボディの子に CollisionShape3D と MeshInstance3D を並べ、表の形を Shape に入れます。見た目は MeshInstance3D の Mesh に、同じ大きさの BoxMesh・SphereMesh・CapsuleMesh を入れます。

ノード型位置形と設定
GroundStaticBody3D(0, -0.5, 0)BoxShape3D (20, 1, 20)
Crate1〜Crate3RigidBody3D(0, 0.5, -4)・(0, 1.51, -4)・(0, 2.52, -4)BoxShape3D (1, 1, 1)。Mass は既定の 1
BallRigidBody3D(0, 1.5, 2)SphereShape3D(Radius 0.25)。Freeze をオン
ChestStaticBody3D(4, 0.5, -2)BoxShape3D (1, 1, 1)
Chest/FrontAreaArea3D(0, 0.5, 1.3)子に BoxShape3D (2, 2, 1.5) の CollisionShape3D。宝箱の手前を覆う
Chest/OpenLabelLabel3D(0, 1.2, 0)3D空間に文字を出すノード。Text を「開ける」。Billboard を Enabled(いつもカメラのほうを向く)。Visible をオフ
PlayerCharacterBody3D(2, 1, 1)CapsuleShape3D(高さ2・半径0.4)。Player 本体を選び、Groups ドック(インスペクタの隣のタブ)で player グループに入れる
Camera3DCamera3D(1, 7, 8)Rotation を (-35, 0, 0)。FOV は既定の 75

箱どうしが食い込まないように、1センチずつすき間を空けて積みます。再生すると少し落ちて、積み重なった状態で落ち着きます。

プロジェクト設定の「インプットマップ」に、move_forward(W)・move_back(S)・move_left(A)・move_right(D)と、throw(Space)・reset(R)を登録します。

② 組み立て

Player に、歩くだけのスクリプトを付けます。

# player.gd(Player に付ける)
extends CharacterBody3D

const SPEED := 4.0

func _physics_process(delta: float) -> void:
	if not is_on_floor():
		velocity += get_gravity() * delta
	var input := Input.get_vector("move_left", "move_right", "move_forward", "move_back")
	velocity.x = input.x * SPEED
	velocity.z = input.y * SPEED
	move_and_slide()

重力の足し方と入力の読み方は、CharacterBody3D入門 と同じです。

Main に、ボールを投げて宝箱の前を見るスクリプトを付けます。

# main.gd(Main に付ける)
extends Node3D

const THROW := Vector3(0, 3, -12)  # 投げる勢い。Mass 1 のボールなら、この速さで飛び出す

@onready var ball: RigidBody3D = $Ball
@onready var front_area: Area3D = $Chest/FrontArea
@onready var open_label: Label3D = $Chest/OpenLabel

func _ready() -> void:
	front_area.body_entered.connect(_on_front_area_body_entered)
	front_area.body_exited.connect(_on_front_area_body_exited)

func _unhandled_input(event: InputEvent) -> void:
	if event.is_action_pressed("throw") and ball.freeze:
		ball.freeze = false                 # ここから物理に任せる
		ball.apply_central_impulse(THROW)   # 1回だけ押し出す
	elif event.is_action_pressed("reset"):
		get_tree().reload_current_scene()   # 箱を積み直す

func _on_front_area_body_entered(body: Node3D) -> void:
	if body.is_in_group("player"):          # 床やボールでは反応しない
		open_label.visible = true

func _on_front_area_body_exited(body: Node3D) -> void:
	if body.is_in_group("player"):
		open_label.visible = false

③ 動かして確かめる

実践の結果の3コマ。積まれたままの木箱、ボールが真ん中の箱の上のほうに当たって山が崩れる瞬間、宝箱の前に立つと宝箱の上に「開ける」

Debug の Visible Collision Shapes をオンにして、F6(いま開いているシーンを実行)で動かします。見るのは3つです。

まず、箱は少しだけ落ちて、積まれたまま立っています。床を抜けて落ちるなら、まずその箱と床に当たりの形があるかを見ます。再生した瞬間に崩れるなら、箱どうしが食い込んで置かれていないかを見ます。

次に Space を押すと、ボールが少し山なりに飛び、0.4秒あまりで真ん中の箱の上のほうに当たります。真ん中と上の箱が押し出されて、山が崩れます。崩れ方は、毎回同じになるとは限りません。ボールが箱を素通りするなら、まずボールの形が物理ボディの子になっているかを見ます。R を押すと、積み直した状態から何度でも試せます。

仕上げに、D で右へ、W で奥へ歩いて、プレイヤーを宝箱の手前に立たせます。範囲に入ると宝箱の上に「開ける」が出て、離れると消えます。ボールが転がってきても出ません。

ポイントは2つです。

  • 当たるのは形のほう: 落ちる・積める・崩れるは、CollisionShape3D の形とその大きさで決まります
  • Area3D は相手を選ばない: 床もボールもプレイヤーも、Mask が合えば全部に反応します。反応させる相手は、グループかレイヤーで絞ります

プレイヤーをカメラの向きへ歩かせるなら、CharacterBody3D入門 が続きになります。

うまくいかないときは

症状原因直し方
速いボールが、薄い壁や箱を素通りする1回の物理の更新のあいだに、壁を通り越してしまうボールの Continuous CD(移動の途中も調べる設定)をオンにする。壁も薄くしすぎない
宝箱を RigidBody3D にしたら、ボールで宝箱ごと動き、判定の範囲も一緒に動く宝箱が物理で動く側になっている宝箱は StaticBody3D にして、Area3D をその子に置く
木箱(RigidBody3D)自身の body_entered をつないでも、ボールが当たったときに鳴らない物理ボディの接触は、既定では知らせない設定。数える接触の上限も0その木箱の Contact Monitor をオンにし、Max Contacts Reported を多めにする。面どうしの接触は相手1つで4点使うことがあり、積んだ箱は上下の箱だけで8点になるので、16ほど
起動した直後に、宝箱の前でもないのに「開ける」が出る範囲がプレイヤーの初期位置に重なっているArea3D の範囲か、プレイヤーの初期位置をずらす

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

  • 物理エンジンは2種類ある: Jolt と Godot Physics です。4.6 以降に作ったプロジェクトは Jolt が既定です。それより前に Godot Physics で作ったプロジェクトは自動では切り替わらず、プロジェクト設定の Physics > 3D で選び、エディタを再起動します。積んだ箱の落ち着き方や円柱の転がり方が違うので、崩れ方が記事と違うときは確かめます
  • 滑りやすさと弾み: PhysicsMaterial で変えます。Physics Material Override に新しく作り、Friction(摩擦)と Bounce(弾み)を調整します
  • 動く床は AnimatableBody3D: コードやアニメーションで動かす床に使います。考え方は 2Dの物理ボディ入門 と同じです

まとめ

  • 当たるのは形のほう: 見た目のメッシュとは別に、物理ボディの子に CollisionShape3D を置く。Visible Collision Shapes で確かめる
  • 形は動くかどうかで選ぶ: 動く物は箱・球・カプセル・円柱か Convex。Trimesh は動かないステージだけ
  • 大きさは形のサイズで: Scale は (1, 1, 1) のまま、Size や Radius を変える
  • RigidBody3D には力を渡す: apply_central_impulse() を1回。速さの変化はインパルス ÷ Mass
  • Area3D は相手を選ばない: body_entered で届いた相手を、グループかレイヤーで絞る

まずは今のシーンで Visible Collision Shapes をオンにしてみてください。見た目と当たりの形がずれている物が、直すところです。あなたのゲームで、前に立つと反応させたい物は何でしょうか。

次に読む次のカテゴリ「描画・エフェクト」へ
描画・エフェクト

Godot Engine Camera2D 実践テクニック集:スムーズ追従、画面振動、動的ズームを極める

この記事を読む
Godot このセクションのノート104