【Godot】GodotのCSG入門:ブロックで部屋を削り出し、歩ける3Dレベルを試作する

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

モデルが無くても、CSGの箱を足し引きして扉のある部屋を作り、歩いて寸法を確かめてからGridMapへ写す方法を解説します。

3Dのステージを作るときは、見た目を作り込む前に、キャラが通れる寸法を決めておくと作り直しが減ります。Godot の CSG なら、箱を足し引きして部屋の形だけをエディタの中で作り、その日のうちに歩いて確かめられます。

見た目から作ってあとでキャラを入れると、扉をくぐれなかったり段差で止まったりして、部屋ごと作り直すことになります。モデルを作り込んだあとほど、直す手間は大きくなります。

この記事では、CSGで扉の穴を削って歩ける部屋を作り、固まった寸法をGridMapのマスへ写す方法を解説します。

箱を組んだだけの部屋の扉を人形がくぐる「寸法を決める」と、同じ部屋をマスで組んだ「マスに写す」の2コマ

この記事でわかること

  • 試作で先に決めるのが、見た目ではなくキャラの通れる寸法であること
  • 箱を足し引きして扉の穴を開け、Use Collision で歩けるようにする方法
  • 段は登れず、斜面は登れる理由
  • 固まった寸法を GridMap のマスへ写す手順

動作確認環境: Godot 4.7

Sponsored

キャラが通れる寸法の決め方

Godotの3Dは、1ユニットが1メートルです。この前提があるので、部屋の大きさは「なんとなく大きい箱」ではなく、メートルで決められます。

基準になるのはキャラの太さと高さです。3Dのキャラの当たり判定は、たいてい縦長の丸い筒(カプセル)で持たせます。ここが決まらないと、扉の幅も天井の高さも決まりません。

半径0.4・高さ2.0のカプセルから、扉の幅1.6・壁の高さ3.0・登れない段が決まることを示す図

この記事では、次の数値で通します。部屋の見た目から決めるのではなく、カプセルから決めた値です。

  • キャラのカプセルは半径 0.4・高さ 2.0(高さは両端の丸みを含めた全長)。原点は中心なので、床に立たせるなら y = 1.0
  • 部屋の内側は 8 × 8。横切るのに数秒かかる広さ
  • 床は厚み 1.0。中心を y = -0.5 にして、上面を y = 0 にそろえる
  • 壁は厚み 0.4・高さ 3.0。中心は y = 1.5
  • 扉の開口は幅 1.6。カプセルの左右に 0.4 ずつの余裕
  • 登れない段は高さ 0.5。止まることを確かめるために置く
  • 登れる斜面は 3 mで 0.6 上がる約12度。45度までなら床として扱われる

CSGBox3D の原点は箱の中心です。厚み 1 の床の上面を y = 0 にそろえるには、中心を y = -0.5 に置きます。ここを間違えると、再生した瞬間にキャラが床へ半分埋まります。

CSGの足し引き(Operation)

CSGは、箱や円柱を足したり引いたりして形を作る仕組みです。モデリングソフトを開かずに、エディタの中だけで部屋の形が作れます。

合わせ方は Operation という欄で選びます。

  • Union: 親の形に足す。床や壁はこれ
  • Subtraction: 親の形から削る。扉の穴はこれ
  • Intersection: 重なっている部分だけ残す。この記事では使いません
大小2つの箱を Union で足す、Subtraction で削る、Intersection で重なりだけ残す3つの合わせ方

他のエンジンでいうと: エディタの中でレベルを試作する用途は、Unity の ProBuilder や Unreal Engine の Modeling Mode と同じ位置にあります。

大事なのは、この足し引きが CSG ノードどうしのつながりの中でしか効かないことです。あいだに普通の Node3D をはさむと、そこで切れて別の形になります。

もう1つは順番です。同じ親の下に並んだ子は、ツリーの上から順に合成されます。Subtraction で削ったあとに Union を置くと、重なっている範囲は戻ってきます。削ったつもりが埋まっている、というときはこの順番を見ます。

Use Collisionで当たり判定を作る

箱を置いただけでは、キャラは通り抜けます。見た目の形と当たり判定は別のものだからです。

CSGには、足し引きが終わったあとの形から当たり判定を作る Use Collision という欄があります。これをオンにすると、CollisionShape3D を1つも置かずに、削った穴ごと当たり判定になります。

Use Collision がオフだとカプセルが壁を通り抜け、オンだと壁で止まって扉の穴だけ通れる比較

付ける場所は、CSGツリーのいちばん上のノードです。床の箱や壁の箱に付けても、そこだけ独立した当たり判定にはなりません。部屋をまとめている CSGCombiner3D(形を持たず、子の足し引きをまとめるだけのノード)に1つ付ければ、その下の全部が当たるようになります。

逆に、同じツリーに入っていない兄弟は含まれません。あとで出てくる斜面のように、部屋とは別に置いた箱は、その箱自身の Use Collision をオンにします。

当たる相手を決める Collision Layer と Mask は、初期値のままで CharacterBody3D と噛み合います(Collision Layer と Mask の整理)。

扉の穴の削り方

穴は見えているのにそこで止まる、というのが試作でいちばん多いつまずきです。原因は削る箱の置き方に寄っています。

削る箱が壁と同じ厚みだと出入口に薄い敷居が残り、壁の内外と床の下へ突き出すときれいに抜ける断面の比較

削る箱は、壁の内側と外側へそれぞれ20cmほど突き出します。面をぴったりそろえると、同じ平面での足し引きになって、薄い板や三角が残ることがあります。見た目には開いているのに、そこだけ当たります。

底も同じです。床の上面と同じ高さで止めると敷居が残ることがあるので、5cmほど床へ食い込ませます。そのぶん床に浅い溝ができますが、削ったあとに外側の床を足せば埋まります。順番が効くのはこういうところです。

Sponsored

段差と斜面

床に高さ0.5の箱を置いて、その上に乗ろうとすると止まります。CharacterBody3D には、段差を自動で上る機能が用意されていないからです。

紛らわしいのが Floor Snap Length です。初期値は 0.1 ですが、これは床から離れないように下へ吸い寄せる長さで、段を上る高さとは別ものです。

カプセルが高さ0.5の垂直な段の手前で止まり、12度の斜面なら直立したまま0.6上まで登れる比較

一方、斜面は登れます。Floor Max Angle の初期値が45度で、それより浅い面は床として扱われるからです。垂直な0.5メートルの段では止まり、3メートルかけて0.6メートル上がる12度の坂なら登れます。

階段を確実に上がらせたいなら、見た目の段はそのままにして、当たりだけを斜面1枚にします。段の垂直な面が当たりに残っていると、そこで止まるからです。

GridMapでマスに写す

寸法が固まったら、同じ部屋を何度も並べたくなります。そこからが GridMap の出番です。

GridMap は、あらかじめ登録しておいたメッシュを、マス目に沿って置いていくノードです。2Dの TileMapLayer と役割の分かれ方が同じで、MeshLibrary が絵の具箱、GridMap が置く側にあたります。

2Dから来ると必ず引っかかるところが1つあります。

メッシュだけのタイルはカプセルがすり抜け、StaticBody3D と CollisionShape3D を付けたタイルには乗れる比較

MeshLibrary の項目は、メッシュだけでは当たり判定を持ちません。元になるシーンのルートに Node3D を置き、その子に項目ごとの MeshInstance3D を並べます。それぞれの MeshInstance3D の子に StaticBody3D(動かない当たりの本体)、その子に CollisionShape3D(その形)という順に重ね、CollisionShape3D へ形を割り当ててから書き出します。床のタイルなら形は BoxShape3D にします。書き出しは Scene → Export As... → MeshLibrary... で、.meshlib か .tres で保存します。CSG の部屋をそのまま書き出しても項目にはならないので、次の節の方法で焼いたメッシュか、別に作ったメッシュを使います。

置く側では、GridMap ノードを足してインスペクタの Mesh Library に書き出したファイルを割り当てます。GridMap を選ぶと、エディタ下部の GridMap ドックに項目の一覧が出ます。項目を選び、ドックの Paint を有効にしてから3Dビューのマスをクリックすると置けます。

もう2つ、先に知っておくと迷いません。

  • Cell Size: 初期値は (2, 2, 2) です。1メートルの箱をそのまま置くと、マスのあいだに隙間が空きます。タイルにするメッシュの大きさに合わせます(2メートル角の床タイルなら初期値のまま)
  • 開口はタイルで作る: GridMap に Subtraction はありません。扉は、開口を開けた壁のメッシュを1つの項目として用意して置きます。マスを空けるだけだと、開口の幅はマスの大きさになります
Sponsored

CSGを焼いて固める(Bake)

CSGは、置くたびに足し引きを計算し直します。部屋が数個なら気になりませんが、何十個も置くと、動かすたびにエディタが引っかかります。

固めたいときは、CSGのルートを選んで3Dビュー上部の CSG メニューを開きます。Bake Mesh Instance で見た目の MeshInstance3D を、Bake Collision Shape で当たりの形の CollisionShape3D を作れます。焼いた CollisionShape3D は StaticBody3D の子へ移し、元のCSGは外します。残すと当たりが二重になります。

試作から本番へ移すとき、手元に残すのは扉の幅、天井の高さ、歩ける斜面の角度という数値です。箱そのものは捨てて構いません。

実践:歩ける部屋を1つ組む

見下ろし型のダンジョン、三人称のアクション、一人称の探索 —— どのジャンルでも、最初に確かめるのは「通れるか」「止まるか」の2つです。部屋を1つだけ作って、その両方を画面で確かめます。

実践のシーンツリーと、Room と Ramp だけ Use Collision をオンにし、カメラを Orthogonal にする設定の図

① 置くもの

新しい3Dシーンを1つ作ります。角度はインスペクタの Rotation に度で入れ、すべてのノードの Scale は (1, 1, 1) のままにします。

  • ルートに Node3D を置いて Main にし、Main Scene に指定する(F5 で再生したときに聞かれたら、このシーンを選ぶ)
  • Main の子に CSGCombiner3D を置いて Room 。Use Collision をオンにする
  • Room の子に CSGBox3D を8つ、この順番で置く
名前SizePositionOperation
Floor(8, 1, 8)(0, -0.5, 0)Union
WallN(8.8, 3, 0.4)(0, 1.5, -4.2)Union
WallS(8.8, 3, 0.4)(0, 1.5, 4.2)Union
WallE(0.4, 3, 8.8)(4.2, 1.5, 0)Union
WallW(0.4, 3, 8.8)(-4.2, 1.5, 0)Union
DoorCut(1.6, 3.2, 0.8)(0, 1.55, -4.2)Subtraction
Porch(3, 1, 4)(0, -0.5, -5.6)Union
Step(1, 0.5, 1)(2.5, 0.25, 2.5)Union
  • Main の子に CSGBox3D を1つ置いて Ramp 。Size (2, 0.4, 3) 、Position (-2.5, 0.11, 1.5) 、Rotation の X に -12 。Use Collision をオンにする。低いほうの端が -Z 側(このカメラでは画面の上)になる
  • Main の子に CharacterBody3D を置いて Player 、Position (0, 1, 0) 。その子に CollisionShape3D(CapsuleShape3D ・半径 0.4 ・高さ 2.0)と MeshInstance3D(CapsuleMesh ・半径 0.35 ・高さ 1.9)を置く
  • Main の子に Camera3D を置き、Projection を Orthogonal(遠近の無い平行投影)、Size を 14(縦に映る範囲が14メートル)、Position (0, 18, -1.6) 、Rotation の X に -90
  • Main の子に DirectionalLight3D を置き、Rotation を (-60, -30, 0) にして、Shadow の Enabled をオンにする
  • Floor ・ 壁4枚 ・ Step ・ Ramp に、明るさの違う単色のマテリアルをそれぞれ割り当てる(インスペクタの Material に New StandardMaterial3D を作り、Albedo の Color を変える。StandardMaterial3D入門)。真上から見下ろすとどれも同じ向きの面になるので、色で分けないと見分けがつかない

壁の長さ8.8と中心の±4.2は、内側の8に壁の厚み0.4を両側へ足した値です。四隅を重ねて、隙間を作らないためです。DoorCut は壁の内外へ20cmずつはみ出し、底は床の上面より5cm下まで入っています。そのぶん床に浅い溝ができますが、あとに Porch を足しているので埋まります。順番を入れ替えると埋まりません。上端は壁の上まで抜いてあるので、真上から見ると切れ目になります。

Camera3D は真上から見下ろす向きです。壁が高さ3あるので、斜めから見ると扉の先が壁に隠れます。

② 組み立て

Player に付けるスクリプトは、歩けるかどうかを確かめるためだけのものです。

# player.gd(Player の CharacterBody3D)
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("ui_left", "ui_right", "ui_up", "ui_down")
	velocity.x = input.x * SPEED                 # 画面の左右
	velocity.z = input.y * SPEED                 # 上キーで -Z = 画面の上
	move_and_slide()

get_gravity() は、いまかかっている重力をベクトルで返します。入力は最初から用意されている ui_left などをそのまま使うので、インプットマップは触りません。矢印キーで動きます。

ジャンプもカメラ追従も入れていません。カメラの向きに合わせて歩く形は CharacterBody3D入門 にあります。

③ 動かして確かめる

真上から見た部屋で、中央に立つ、壁で止まる、扉を抜けて外の床に乗る、左の斜面は登り右の段で止まる4コマ

再生すると、真上から部屋を見下ろす画面になり、キャラは部屋の真ん中に立っています。ここで床に埋まったり上へ弾かれたりするなら、Floor と Player の Position と、カプセルの高さを①の値と見比べます。

矢印キーで壁へ向かうと、4枚ともカプセルの端が壁に触れたところで止まります。上キーで上の壁の切れ目へ進むと、敷居に引っかからずに抜けて、外の床に乗ります。切れ目の手前で止まるなら、DoorCut の Size と Position を表と見比べてください。

次に、中央から左へ2.5メートルほど寄ってから下キーを押します。左の斜面を登って、端で床へ降ります。いったん中央へ戻り、今度は右へ2.5メートル寄ってから下キーを押すと、右下の段の手前で止まります。ここが止まれば、高さ0.5の垂直な面は登れない、という確認になります。

ポイントは2つです。

  • 当たり判定はルートに1つ: Room の Use Collision が、8つの箱を足し引きした結果から当たりを作ります。Ramp は別のツリーなので自分で持ちます
  • 寸法は通れるかで決まる: 扉の幅1.6は、直径0.8のカプセルに左右0.4ずつの余裕を足した値です。狭めたいときは、この余裕から削ります

この部屋の寸法が決まり、部屋が2つ目に増えたら、GridMap に写します。2メートルのマスなら、幅1.6の開口を開けた2メートル幅の壁タイルを1つ作って置きます。

うまくいかないときは

症状原因直し方
GridMap に敷いた床の上面が、y = 0 より上に来るCell Center Y が既定でオンで、メッシュがマスの高さの中央に置かれる(Cell Size が2なら中心が1.0)Cell Center Y をオフにし、GridMap を床の厚みの半分(厚み1なら0.5)下げる
ツリーの並びを入れ替えたら、穴ではなく削る箱の形が出てきたいちばん上の子は Operation にかかわらず土台になる削る箱は、床や壁より下に並べる
項目を選んで3Dビューをクリックしても、マスに置けないGridMap ドックが Selection のままになっているドックの Paint を有効にしてからクリックする
焼いたあと元のCSGを非表示にしたのに、当たりが二重になる非表示にしても、CSGの Use Collision の当たりは残る元のCSGの Use Collision をオフにするか、ノードごと外す

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

  • 斜めから眺めるなら壁を低く: 真上ではなく斜めから見たいときは、手前の壁だけ高さを1メートルほどに下げると中が見えます
  • 明かりを詰めるのは寸法のあと: 太陽の向き、街灯や懐中電灯の置き方、影の側の明るさは 3Dライティング入門 で扱っています
Sponsored

まとめ

  • 決めるのは寸法: キャラのカプセルを先に決め、扉の幅と天井の高さをそこから出す。箱の原点は中心
  • 足し引きは順番で決まる: 同じ親の下では上から順に合成され、削ったあとの Union は戻す
  • Use Collision はルートに1つ: 足し引きが終わった形から当たりが作られる。削る箱には付けない
  • 段は登れない: 自動で段を上る機能は無い。登らせたいなら斜面かジャンプを足す
  • GridMapへ写すのは寸法が固まってから: MeshLibrary の項目は、当たり判定を自分で付けてから書き出す

まずは床1枚と壁1枚だけ置いて、Use Collision をオンにして歩いてみてください。あなたのゲームの最初の部屋は、何メートル四方になりそうですか。

次に読む学習パスの次の記事
3D

Godotの3Dライティング入門:3つのライトとWorldEnvironmentで、同じ広場を昼と夜に切り替える

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