はじめてのGodot 第8回(最終回): 音とリスタートで「ゲーム」に仕上げよう
前回までで、ゲームの中身は完成しました。最終回は音・スタート画面・リトライを付けて、人に渡せる「完成品」に仕上げます。
今回のゴール

- ゲームオーバーで効果音(爆発音)が鳴る
- スタートボタンを押してからゲームが始まる
- リトライボタンで何度でも遊べる
音素材を用意する
Kenneyには効果音素材もあります(CC0)。「Sci-fi Sounds」や「Impact Sounds」あたりから、爆発音っぽいもの(.ogg か .wav)をひとつダウンロードして、ファイルシステムにドラッグ&ドロップしてください。
爆発音を鳴らす
音を鳴らすのも、もちろんノードです。AudioStreamPlayer を使います。
Mainの子にAudioStreamPlayerを追加し、名前をExplosionSoundに。Streamに爆発音を設定(Autoplayはオフのまま)main.gdの_on_player_died()に1行追加:
func _on_player_died():
playing = false
$SpawnTimer.stop()
%ScoreLabel.hide()
$ExplosionSound.play()
%GameOverLabel.text = "GAME OVER\nSCORE: %.1f" % score
%GameOverLabel.show()
play() で好きなタイミングで再生できます。
スタート画面を作る
今はゲームが問答無用で始まります。「ボタンを押したら開始」に変えましょう。
HUDの子にLabelを追加 → 名前TitleLabel、Textにゲームタイトル(METEOR DODGEなど)、画面中央上寄りに大きく配置HUDの子にButtonを追加 → 名前StartButton、Textをスタートに、画面中央に配置- どちらも右クリック→「固有名でアクセス」で
%を付ける SpawnTimerの Autostart をオフに戻す(開始はボタンが合図になるため)StartButtonのpressed()シグナル(ボタンが押された)をMainに接続
main.gd を仕上げます。これが完成版の全文です。
extends Node2D
const METEOR_SCENE = preload("res://meteor.tscn")
var score = 0.0
var playing = false
func _ready():
$SpawnTimer.timeout.connect(_on_spawn_timer_timeout)
func _process(delta):
if playing:
score += delta
%ScoreLabel.text = "SCORE: %.1f" % score
func _on_spawn_timer_timeout():
var meteor = METEOR_SCENE.instantiate()
meteor.position = Vector2(randf_range(20, 460), -50)
meteor.speed = randf_range(200, 500)
add_child(meteor)
func _on_start_button_pressed():
%TitleLabel.hide()
%StartButton.hide()
playing = true
$SpawnTimer.start()
func _on_player_died():
playing = false
$SpawnTimer.stop()
%ScoreLabel.hide()
$ExplosionSound.play()
%GameOverLabel.text = "GAME OVER\nSCORE: %.1f" % score
%GameOverLabel.show()
%StartButton.text = "リトライ"
%StartButton.show()
ポイントは2つ。playing の初期値が false になったこと(スタート前はスコアが進まない)。そしてゲームオーバー時にスタートボタンを「リトライ」に変えて再表示していることです。
リトライを実装する
「リトライ」を押したときも _on_start_button_pressed() が呼ばれますが、死んだ宇宙船や降ってきた隕石が残ったままです。全部リセットする一番簡単な方法は、シーンを丸ごと読み込み直すことです。
_on_start_button_pressed() を少しだけ加工します。
func _on_start_button_pressed():
if %StartButton.text == "リトライ":
get_tree().reload_current_scene()
return
%TitleLabel.hide()
%StartButton.hide()
playing = true
$SpawnTimer.start()
get_tree().reload_current_scene() は「現在のシーンを最初から読み込み直す」命令です。ゲームを実行した直後の状態に完全に戻ります。return は「この関数をここで終わる」という命令です。
リロード後はタイトル画面に戻るので、もう一度スタートを押せば2周目です。「リトライで即ゲーム再開」にしたい人は、改造課題としてぜひ挑戦してみてください(ヒント: 起動直後かどうかをフラグで区別します)。
完成!
実行してみてください。タイトル → スタート → プレイ → 爆発音とともにGAME OVER → リトライ。ゲームが1本、完成しました。
第1回の自分を思い出してください。シーンとノードという言葉も知らなかったところから、あなたはここまで来ました。
連載で学んだことの全リスト
- Godotの構造: シーン(部品)とノード(1機能)、シーンの量産(
instantiate/add_child)、グループ - GDScript: 変数とフラグ、
if文、関数定義、文字列とフォーマット、_readyと_process、delta - ゲームの基本要素: 入力(
Input.get_vector)、当たり判定(Area2D)、時間管理(Timer)、UI(CanvasLayer)、音(AudioStreamPlayer) - Godot流の設計: シグナルで「叫ぶ側」と「聞く側」を分ける、%固有名、
queue_freeで後片付け
卒業課題 — 自分の手で改造しよう
ここからが本当のスタートです。お題を置いておきます。上から順に難しくなります。
- 難易度を調整する: スポーン間隔・速度・判定サイズを自分の好みに
- 時間とともに難しくする: スコアに応じてWait Timeを短くしてみよう
- ハイスコアを覚える: 変数をもうひとつ足すだけでできます
- 隕石を撃てるようにする: 弾も「量産する部品」です。第4〜5回の知識で作れます
- アイテムを追加する: 取るとスコアが増える星など。第6回のグループ判定が活きます
次のステップ
- 完成したゲームはブラウザで動く形に書き出して公開できます。Godotの「HTML5書き出し」を使えば、itch.ioなどに置いて誰でも遊べる形にできます
- 今回はタイトルもゲームも1つのシーンに収めましたが、規模が大きくなるとタイトル画面を独立したシーンにして
change_scene_to_file()で切り替えるのが一般的です(シーン遷移も今後のTips記事で扱います) - 連載で駆け足だったトピック(シグナル設計、%固有名、物理ボディの種類など)は、今後Tips記事として深掘りしていきます
完走おつかれさまでした。あなたはもう「Godotでゲームが作れる人」です。