Godotでスクリプトなしの脱出ゲームを作ってみた|TextureButton・Timer・ProgressBarを実演

Godot 4.7系を使い、鍵を探して2つの部屋から脱出する、制限時間つきの脱出ゲームを作りました。新しく使ったのはTextureButton、Timer、ProgressBarの3つです。これまでに使ったSignal、AnimationPlayer、AudioStreamPlayerと組み合わせ、今回もスクリプトは1行も書いていません。

きっかけは、調べられる場所すべてに文字のボタンを置いてみたことでした。「壺を調べる」「本を調べる」と並べていくと、部屋よりも文字のほうが目立ってしまい、どこを探せばいいのかかえって分かりにくくなります。気になった壺や本をそのままクリックできたほうが、探している感じが出るはずです。そこで、画像そのものを押せるようにし、さらに制限時間と残り時間の表示も加えてみました。

この記事も一般的な機能紹介ではなく、練習用の小さなシーンで1つずつノードを試してから、脱出ゲームへ組み込んだ記録です。制作の様子と完成版のプレイは動画にも残しています。

今回完成したゲーム

部屋の物をクリックして鍵を探し、正しい扉を選んで次の部屋へ進む、シンプルな脱出ゲームです。

  1. 中央の「スタート」を押すと、画面上部の時間バーが減り始める
  2. ルーム1(扉2つ・探索場所3つ)で、壺やクッション、本を調べて鍵を探す
  3. 鍵を取ると扉が押せるようになり、案内文が「鍵あり、ドアを選ぼう」に変わる
  4. 外れの扉を選ぶと、画面が暗転して同じ部屋へ戻される(鍵は持ったまま)
  5. 正しい扉でルーム2(扉3つ・探索場所3つ)へ進み、もう一度鍵を探す
  6. 正解の扉から外へ出られれば脱出成功。60秒を過ぎると時間切れで失敗
  7. 結果画面の「もう1度遊ぶ」で、部屋も残り時間も最初の状態に戻る

使用したノードと機能

今回新しく使ったノードは次の3つです。

  • TextureButton:画像そのものを押せるボタンにする
  • Timer:制限時間を数え、時間切れを合図する
  • ProgressBar:残り時間をバーの長さで見せる

このほか、これまでに使ったSignal、AnimationPlayer、AudioStreamPlayer、ColorRectも組み合わせています。

今回新しく使うTextureButton・Timer・ProgressBarの3つのノード

3つの小実験で新しいノードに触れる

3つをいきなり脱出ゲームへ入れるのは不安だったので、今回も練習用の短いシーンを作り、1つずつ動きを確かめてから本番へ進みました。

1. TextureButtonで壺を「調べられるもの」にする

シーンツリーで壺のTextureButtonを選ぶと、インスペクターのTexturesに状態ごとの画像を設定できます。Normalには普段の画像、Hoverにはマウスを重ねたときの画像を入れました。壺もクッションも、普段用と少し明るくした画像の2枚を用意しています。マウスを重ねて明るくなれば、遊ぶ人に「ここは調べられる」と伝えられます。

意外と手間取ったのが、押せる範囲の調整です。TextureButtonはControlの仲間なので、TransformのSizeでボタンの四角い範囲を画像に近づけます。ここが大きすぎると、壺の周りの何もないところまで押せてしまい、ちょっと変でした。枠の中の絵の見え方は、Offset TransformのScaleで調整しています。

壺の子には「壺を調べました。」と表示するLabelを置き、最初は隠しておきました。TextureButtonのpressedシグナルからLabelのshowを呼ぶように接続します。実行してマウスを重ねるとHover画像に切り替わり、クリックすると文字が出ました。これで壺が「調べられるもの」になりました。同じ仕組みをクッションにも使い、こちらも問題なく動いています。

TextureButtonの壺にマウスを重ねるとHover画像に変わり、クリックで「壺を調べました」と表示された

2. Timerで3秒後の合図を受け取る

シーンにTimerと結果表示用のLabelを置き、インスペクターでWait Timeを3秒、Autostartをオンにしました。Autostartがオンなので、実行と同時に数え始めます。

ノードタブのシグナルからtimeoutを選び、待ち時間が終わったらLabelのshowを呼ぶように接続しました。Labelは最初は隠しておきます。実行すると、3秒後に文字が表示されました。もう一度試しても、ちゃんと3秒で出ます。Timerそのものは画面に何も表示しませんが、「時間が来た」という合図を出してくれる係なのだと分かりました。

Timerの3秒後にtimeoutシグナルでLabelが表示された実行画面

3. ProgressBarで残り時間を見せる

次は、時間が減っていく様子を目に見えるようにします。画面上部に横長のProgressBarを置き、Min Valueを0、Max ValueとValueを100にしました。バーの上に出る割合の数字(Show Percentage)は隠しています。

ここで気づいたのは、ProgressBarは自分では減っていかないということです。Timerと自動でつながるわけでもありません。そこでAnimationPlayerに、Valueを100から0へ下げるアニメーションを用意し、Timerと同じ5秒で減るようにそろえました。

TimerはWait Timeを5秒、One Shotをオンにし、開始はボタンから行います。スタートボタンのpressedには3つの接続をしました。

  1. Timerのstartで5秒のカウントを始める
  2. 押し終えたスタートボタンをhideで隠す
  3. AnimationPlayerのplayでカウントダウンのアニメーションを再生する

Timerのtimeoutにも3つの接続をしています。

  1. ProgressBarのset_valueに0を渡し、時間切れの状態に確実にそろえる
  2. 隠しておいた「TIME UP」の文字をshowで表示する
  3. 動いているAnimationPlayerをpauseで止める

実行してスタートを押すと、バーが減り始め、5秒後にゲージが空になって時間切れの文字が出ました。1つのtimeoutから、時間切れに必要な動きを3つまとめて呼べるのは便利です。

画面上部のProgressBarがAnimationPlayerで減っていく様子

脱出ゲームへ組み込む

小実験で動きを確かめたあと、本番の脱出ゲームを組み立てました。スクリプトを使わない分、どのノードが何を担当するのかを分けておくことを意識しています。

探索場所はTextureButtonとAnimationPlayerで動かす

各部屋の探索場所(壺、クッション、床の本、布をかけた台など)は、すべてTextureButtonです。押したときに次の3つが起きるように接続しました。

  • 操作を止めるInputBlocker(後述)を表示する
  • AudioStreamPlayerで「調べた音」を鳴らす
  • 探索用のAnimationPlayerにアニメーション名を渡して再生する

鍵が隠れている場所のアニメーションでは、壺を動かすのと同時に、隠していた鍵を表示しています。何もない場所は、本を動かして戻すだけです。探索の動きは全部で6本になりましたが、再生役のAnimationPlayerを1つにまとめたので、あとから探しやすくなりました。

鍵を取ったら扉を押せるようにする

鍵もTextureButtonで、最初は非表示です。鍵のpressedには、鍵自身をhideで隠す、鍵の音を鳴らす、扉のset_disabledにfalseを渡して押せるようにする、案内Labelのset_textで「鍵あり、ドアを選ぼう」に書き換える、という接続をしました。

制限時間はTimerの60秒とProgressBarをそろえる

本番ではTimerのWait Timeを60秒にし、One Shotをオンにしました。時間バーのProgressBarもMin Valueを0、Max ValueとValueを60にし、AnimationPlayerで60秒かけて60から0へ減らします。Timerの60秒とバーの減り方をそろえておかないと、見た目と実際の残り時間がずれてしまいます。

timeoutには、時間切れで必要な処理をまとめて接続しました。InputBlockerを表示して追加のクリックを止め、途中の探索アニメーションと部屋移動のアニメーションを止め、時間バーを一時停止して0にそろえ、最後に失敗のアニメーションを再生する、という流れです。

逆に、正解の扉を押したときはTimerをstopし、時間バーも一時停止してから脱出のアニメーションを再生します。これを忘れると、脱出したあとに時間切れが来てしまいます。

見えない蓋で連打を防ぐ

作っているうちに必要になったのが、InputBlockerです。透明なColorRectをFull Rectで画面全体に広げ、Mouse FilterをStopにしました。扉が開く演出や探索の動きの最中にこれを表示すると、下のボタンにクリックが届かなくなり、連打や二重実行を防げます。

反対に、画面上部の青い帯や脱出後の背景のような飾りはMouse FilterをIgnoreにして、クリックの邪魔をしないようにしています。

アニメーションと音は役割ごとに分ける

AnimationPlayerは役割ごとに4つに分けました。

  • SearchPlayer:探索場所の動き
  • BarPlayer:残り時間バーの減り方
  • MovePlayer:部屋の移動と、正解・外れの扉の演出
  • FlowPlayer:開始・成功・失敗という、ゲーム全体の流れ

部屋を移動するときは、黒いColorRectで画面を暗くしている間に部屋を入れ替えます。こうすると、背景が一瞬で切り替わる不自然さを見せずに済みます。効果音も、探索・鍵・扉・足音・成功・失敗の6つのAudioStreamPlayerに分け、音量はどれも-12dBにそろえました。

結果画面の「もう1度遊ぶ」からも、スタートと同じ開始用のアニメーションを再生するようにしたので、初回も再挑戦も同じ初期状態から始められます。

実際に作って分かったこと

今回の制作で特に実感したのは、次の4点です。

1. 文字のボタンより「物そのもの」を押せるほうが探している感じが出る

全部に文字のボタンを置くと、部屋より文字が目立ってしまいました。TextureButtonで物そのものを押せるようにし、マウスを重ねたら明るくするだけで、どこを調べられるかが自然に伝わります。その代わり、押せる範囲を絵に合わせる調整は欠かせませんでした。

完成した脱出ゲームのルーム1。上部に残り時間バー、扉が2つ、調べられる物が並ぶ

2. Timerは数えるだけ、ProgressBarは見せるだけ

Timerは時間を数えて合図を出すだけ、ProgressBarは値を表示するだけで、どちらも勝手に連携してはくれません。時間切れのあとの処理はtimeoutの接続先に、バーの減り方はAnimationPlayerに任せる、と役割を分けて考えると整理しやすくなりました。

3. 操作を止める仕組みが意外と大事

演出の途中で扉や探索場所を連打されると、動きが重なっておかしくなります。透明なColorRectで「見えない蓋」をするだけで、こうしたトラブルをまとめて防げました。脱出したあとにTimerを止めるのも同じで、終わったものはきちんと止める必要があります。

4. スクリプトなしだと、ノードと接続がどんどん増える

スクリプトを使わなくても脱出ゲームは完成しましたが、ノードの数もSignalの接続もかなり多くなりました。こういう作業を簡単にするためにスクリプトがあるのかもしれません。次はそのあたりを確かめてみたいと思います。

今回使った素材のダウンロード

今回の動画で使った背景・ドア・鍵・探索物・効果音・配置参考画像を、練習用の素材集としてまとめました(完成プロジェクトではありません)。無料でご利用いただけます。

2D脱出ゲーム向け素材セット(G006)をダウンロード(zip・約32MB)

ZIPを展開し、中のassetsフォルダーを自分のGodotプロジェクトへコピーしてお使いください。ほかの背景イラストや効果音は、素材集ページにまとめています。

ゲーム開発素材集ページを見る

クレジット

今回の動画では、VOICEVOXのキャラクター「ずんだもん」「暁記ミタマ」のイラストと音声を使用しています。

VOICEVOX:ずんだもん
VOICEVOX:暁記ミタマ

まとめ

Godot 4.7系で、TextureButton、Timer、ProgressBarを使い、スクリプトなしで制限時間つきの脱出ゲームを作りました。

今回行ったことは次のとおりです。

  • 練習用シーンでTextureButton・Timer・ProgressBarを1つずつ試す
  • TextureButtonで、部屋の物そのものを調べられるようにする
  • Timerのtimeoutに、時間切れの処理をまとめて接続する
  • ProgressBarの値をAnimationPlayerで減らし、Timerと時間をそろえる
  • 透明なColorRectで、演出中のクリックを止める

前回までの「選ぶだけのゲーム」に、探す楽しさと、時間に追われるハラハラ感が加わりました。制作の全操作と完成版のプレイは、動画で確認できます。

関連Node解説

コメント