はじめに
この記事は、Godot 4.xで脱出ゲームを作る連載の第5回です。
- 第1回:環境構築とプロジェクト作成
- 第2回:Claude Code + godot-mcpのセットアップ
- 第3回:Claude CodeとMCPでスプラッシュ画面を実装する
- 第4回:Claude CodeとMCPでタイトル画面を実装してシーンを遷移する
- 第5回:背景の特定領域をタップしてフェード遷移する(今回)
前回(第4回)ではタイトル画面からメイン画面への遷移を実装しました。今回はメイン画面の背景に描かれた郵便受けをタップすると、フェードアウト→フェードインで別シーンに切り替わる仕組みを実装します。
この記事で作るもの
- 背景画像の特定領域だけに当たり判定を設ける(ホットスポット)
- タップ時にフェードアウトしてシーン遷移する
- 遷移先シーンでフェードインする
前提条件
- Claude Code + godot-mcpのセットアップ完了(第2回参照)
-
scenes/main.tscnとassets/images/bg_stage_001.pngが配置済み(第4回参照) - 遷移先で使用する
assets/images/bg_stage_002.pngが配置済み
Claude Code
下記プロンプトのみで実装できました(実装された)
プロンプト:
main.tscnでbg_stage_001.pngの左側の郵便受けの領域をタップしたら、post.tscnにフェードイン・フェードアウトで切
り替えてbg_stage_002.pngを表示
設計方針
脱出ゲームではシーン遷移のたびに「ブツ切り感」が出がちです。今回はフェードアウト→フェードインで自然に繋ぐ演出を加えます。
ただし、トランジション専用のシングルトン(Autoload)など大掛かりな仕組みは作りません。「出るシーンが自分をフェードアウト」「入るシーンが自分をフェードイン」 という最小限のパターンを各シーンに持たせるだけで、シンプルな行き来は十分に実現できます。
1. 当たり判定の仕組みを理解する
実装に入る前に、今回使う当たり判定の考え方を整理します。
Area2D + CollisionShape2D でも当たり判定は作れますが、今回はControlノードを使います。理由は座標系にあります。
背景画像(TextureRect)を原点(0, 0)基準で敷いていて、画像サイズとビューポートサイズがほぼ一致しているため、画像のピクセル座標をそのままUIノードの座標として使える構成になっています。Controlノードであれば offset_left などに画像のピクセル座標をそのまま指定でき、余計な座標変換を考えずに済みます。
また、ノードツリーの後方に配置されたノードほど入力判定が先に来るというGodotの仕様を活用します。TextureRect(背景)の後ろにControl(当たり判定)を追加することで、郵便受けの矩形範囲だけ入力を先取りできます。
2. main.tscnにホットスポットを追加する
2-1. Claude Codeへの指示
main.tscnのBgStage001(TextureRect)の後ろに、MailboxAreaという名前のControlノードを追加して。
郵便受けの位置(offset_left=280, offset_top=370, offset_right=540, offset_bottom=830)に配置し、
ホバー時に指カーソルが表示されるようにして。
2-2. 生成された差分
Update(escape-game-sample/scenes/main.tscn)
⎿ Added 7 lines
[node name="MailboxArea" type="Control" parent="."]
layout_mode = 0
offset_left = 280.0
offset_top = 370.0
offset_right = 540.0
offset_bottom = 830.0
mouse_default_cursor_shape = 2
2-3. ポイント解説
ノードの配置順が入力判定の優先順位になる
Godotはノードツリーの後方のノードほど入力を先に受け取ります。BgStage001(背景)の後ろにMailboxAreaを追加することで、郵便受けの範囲内のタップはMailboxAreaが先に受け取れます。
mouse_default_cursor_shape = 2
カーソル形状をCURSOR_POINTING_HAND(指カーソル)に設定します。郵便受けにカーソルを乗せると指カーソルに変わり、「ここはタップできる」ことを視覚的に伝えられます。
当たり判定の座標
今回の構成では背景画像のピクセル座標がそのままノードの座標になります。郵便受けが画像上のどの範囲にあるかをピクセル単位で確認し、offset_left/top/right/bottom にそのまま入力するだけです。
3. タップ検知とフェードアウトの実装
3-1. Claude Codeへの指示
scripts/main.gdを作成して。
MailboxAreaをタップしたら、シーン全体を0.4秒でフェードアウトしてからres://scenes/post.tscnに遷移して。
@exportでフェードアウト時間を調整できるようにして。
3-2. 生成されたスクリプト(main.gd)
extends Control
@export var fade_out_duration: float = 0.4
func _ready() -> void:
$MailboxArea.gui_input.connect(_on_mailbox_area_gui_input)
func _on_mailbox_area_gui_input(event: InputEvent) -> void:
if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
_go_to_post()
func _go_to_post() -> void:
var tween := create_tween()
tween.tween_property(self, "modulate:a", 0.0, fade_out_duration)
tween.tween_callback(_on_fade_out_complete)
func _on_fade_out_complete() -> void:
get_tree().change_scene_to_file("res://scenes/post.tscn")
3-3. ポイント解説
gui_input シグナルでタップを検知
Controlノードにはgui_inputシグナルがあり、そのノードの矩形範囲内でのマウス・タッチ入力を受け取れます。Area2Dのinput_eventと似た仕組みですが、Controlノードはビューポートの2D空間ではなくUI空間で動作するため、今回の構成に適しています。
タッチ入力もInputEventMouseButtonでカバーできる
Godotはデフォルトでタッチイベントをマウスイベントとしてもエミュレートします。InputEventMouseButtonの判定だけでタッチ端末にも対応できます。
modulate:aをルートノードに適用する
self(Mainノード)のmodulate:aを0にすることで、子ノード全体がまとめてフェードアウトします。スプラッシュ画面(第3回)でも同じパターンを使いましたが、ルートノードに適用することで個別ノードを列挙せずに済みます。
tween_callback で完了後の処理を繋ぐ
tween_callback() はTweenのステップとして「関数の呼び出し」を登録できます。フェードアウト完了直後にシーン遷移が実行されるため、アニメーションが終わる前に画面が切り替わる問題が起きません。
4. 遷移先シーン(post.tscn)の作成
4-1. Claude Codeへの指示
scenes/post.tscnを作成して。
bg_stage_002.pngをbg_stage_001.pngと同じようにフルスクリーン表示して。
シーン開始時に0.4秒でフェードインするようにして。
scripts/post.gdも作成して。
4-2. 生成されたシーン(post.tscn)
[gd_scene format=3]
[ext_resource type="Texture2D" path="res://assets/images/bg_stage_002.png" id="1_bg"]
[ext_resource type="Script" path="res://scripts/post.gd" id="2_post"]
[node name="Post" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("2_post")
[node name="BgStage002" type="TextureRect" parent="."]
layout_mode = 0
offset_right = 1920.0
offset_bottom = 1083.0
texture = ExtResource("1_bg")
expand_mode = 1
stretch_mode = 1
4-3. 生成されたスクリプト(post.gd)
extends Control
@export var fade_in_duration: float = 0.4
func _ready() -> void:
modulate.a = 0.0
var tween := create_tween()
tween.tween_property(self, "modulate:a", 1.0, fade_in_duration)
4-4. ポイント解説
フェードインの実装はスプラッシュ画面(第3回)で使ったパターンとまったく同じです。
modulate.a = 0.0 # 透明な状態からスタート
tween_property → 1.0 # 不透明まで補間
この「出るシーンでフェードアウト・入るシーンでフェードイン」というパターンを各シーンに持たせることで、トランジション専用のAutoloadを作らずにシンプルなフェード遷移が実現できます。
5. 動作確認
F5 でゲームを実行し、以下の流れで動作すれば成功です。
- タイトル画面から「Tap to Start」でメイン画面に遷移する
- 郵便受けの範囲にカーソルを乗せると指カーソルに変わる
- 郵便受けをクリック/タップすると画面がフェードアウトする
-
post.tscnがフェードインしながら表示される
うまく動かない場合
| 症状 | 確認ポイント |
|---|---|
| 郵便受けをタップしても反応しない |
MailboxAreaのoffset座標が郵便受けの範囲に合っているか。main.gdがMainノードにアタッチされているか |
| 指カーソルに変わらない |
mouse_default_cursor_shape = 2 が設定されているか |
| フェードせずにブツ切り遷移する |
main.gd の _go_to_post() 内で tween_callback が正しく設定されているか |
| post.tscnでフェードインしない |
post.gd の _ready() で modulate.a = 0.0 からスタートしているか |
成果物
↓
郵便受けにフェードして近接(post.tscn)
まとめ
今回はClaude Code + godot-mcpを使って以下を実装しました。
プロンプト1回だけでこの成果、お得な感じです!
| やったこと | ポイント |
|---|---|
| ホットスポット(当たり判定) |
TextureRectの後ろにControlを配置してノードツリー順で入力を先取り |
| 指カーソル |
mouse_default_cursor_shape = 2 で視覚的フィードバック |
| タップ検知 |
gui_inputシグナル + InputEventMouseButton
|
| フェードアウト→シーン遷移 |
tween_property + tween_callback で完了後に遷移 |
| フェードイン |
modulate.a = 0.0 からスタートしてtween_propertyで補間 |
| トランジション設計 | 各シーンが「自分のフェード」を持つ最小限パターン |
今回のフェードパターン(出るシーンでフェードアウト・入るシーンでフェードイン)は、連載全体を通して使い回せる汎用的な設計です。スプラッシュ画面(第3回)で初めて登場し、今回で本格的に活用しました。


