本文へスキップ
Godot基礎

GodotのTimer入門|5秒カウントダウンとやり直しを作る

Godot 4.5のTimerで残り秒数を表示し、ボタンで5秒へ戻す例です。one_shot、time_left、timeout、表示用の切り上げを図とコードで整理します。

公開日: 2026-10-27#Godot#GDScript#Timer#シグナル#初心者
ガイドキャラクター
Godot 4.5のTimerで残り秒数を表示し、ボタンで5秒へ戻す例です。one_shot、time_left、timeout、表示用の切り上げを図とコードで整理します。
学習者キャラクター
準備するものと、動作確認で見る結果を先に確認してから進めます。
GodotのTimer入門|5秒カウントダウンとやり直しを作るの手順と判断条件を示す説明図
仕組みを説明する模式図です。エディタのスクリーンショットではありません。小さい画面では横にスクロールできます。設定値と手順は本文で確認してください。

この記事で作るもの

「開始/やり直し」ボタンを押すと5秒から数え、最後に「終了」と表示する画面を作ります。途中でもう一度押すと、残り時間を5秒へ戻します。対象はGodot 4.5・GDScript・2DのUIです。

時間の計測はTimerノードへ任せ、Labelはtime_leftを読み取って表示します。_process()で自前の残り時間を減らす方式とは分けて考えます。Timerの公式資料

1. ノードと画面を作る

新しいシーンのルートをControlにしてCountdownDemoと名付け、countdown_demo.tscnへ保存します。ルートのレイアウトをFull Rectにし、次の親子関係を作ります。

CountdownDemo (Control)          ← CountdownDemo.gd
  Timer
  MarginContainer
    VBoxContainer
      TimeLabel (Label)
      RestartButton (Button)

MarginContainerのアンカーは左上のまま、Positionを(24, 24)、Sizeを(360, 160)にします。その子のVBoxContainerとUIの位置はコンテナが調整するので、手で座標をずらしません。

対象設定
TimerWait Time 5.0、One Shotオン、Autostartオフ
TimerPausedオフ、Ignore Time Scaleオフ、Process CallbackはIdle
TimeLabelText 未開始、文字サイズの例は28
RestartButtonText 開始/やり直し、Custom Minimum SizeのYを48
VBoxContainerTheme OverridesのConstants > Separationを16

文字サイズはTimeLabelのTheme Overrides > Font Sizes > Font Sizeで変えられます。この例は標準のEngine.time_scale = 1.0で試し、シーンの一時停止は使いません。

2. シグナルをコードで接続する

ルートへCountdownDemo.gdを付け、次のコードを保存します。エディターのシグナル一覧からの追加接続は行いません。pressedとtimeoutはコードから接続します。

extends Control

const DURATION_SECONDS: float = 5.0

@onready var timer: Timer = $Timer
@onready var time_label: Label = $MarginContainer/VBoxContainer/TimeLabel
@onready var restart_button: Button = $MarginContainer/VBoxContainer/RestartButton


func _ready() -> void:
    timer.stop()
    timer.one_shot = true
    restart_button.pressed.connect(_start_countdown)
    timer.timeout.connect(_on_timeout)
    time_label.text = "未開始"


func _start_countdown() -> void:
    timer.start(DURATION_SECONDS)
    _refresh_time_label()


func _process(_delta: float) -> void:
    if not timer.is_stopped():
        _refresh_time_label()


func _refresh_time_label() -> void:
    time_label.text = "残り: %d秒" % ceili(timer.time_left)


func _on_timeout() -> void:
    time_label.text = "終了"

@onreadyは、ノードの準備ができた段階で子ノードへの参照を取得するために使います。$の後ろはルートから見たノードのパスなので、名前と階層をそろえます。シグナルの考え方を先に確認したい場合はSignalの基本も参照できます。

3. 再開始・終了・表示を区別する

timer.start(5.0)は、停止中なら開始し、動作中なら5秒にリセットします。残り3秒から押しても8秒にはなりません。 この例は一時停止からの再開を扱うものではなく、毎回最初の5秒へ戻します。

one_shot = trueなので、時間切れでtimeoutを1回通知して停止します。コードでも同じ設定にして、繰り返し動作を防いでいます。_process()は停止中に表示を上書きしないため、「終了」がそのまま残ります。Timerの開始・停止と各プロパティ

ceili()は小数を切り上げて整数にする関数です。たとえば残り4.2秒は5秒と表示します。表示だけを丸め、Timer自身の計測値は変えていません。ceiliの公式資料

動作確認

このシーンを開き、F6で現在のシーンを実行します。

操作期待する結果
シーン開始直後未開始のままで、勝手に減らない
ボタンを押す残り: 5秒から表示が減る
残り3秒程度で押し直す5秒へ戻り、そこから数え直す
押し直した後、ボタンを押さずに待つ約5秒後に終了になる
終了後さらに待つ自動で次のカウントを始めない
終了後にボタンを押す再び5秒から始まる

画面表示の更新はフレームごとです。実時間の厳密な計測や、ネットワーク上の全端末で同じ締め切りを扱う例ではありません。

うまく動かないとき

  • ノードが見つからない:Timer、MarginContainer、VBoxContainer、TimeLabel、RestartButtonの大文字・小文字と階層を確認します。
  • 画面にボタンがない:Controlをルートにし、MarginContainerの位置・サイズ、ButtonのVisibleを確認します。
  • 最初から数え始める:TimerのAutostartや、別スクリプトのstart()、重複したシグナル接続を確認します。
  • 押しても時間が進まない:TimerのPaused、シーンの一時停止、Engine.time_scaleを確認します。start()はPausedを自動で解除しません。
  • 秒数の減り方が想像と違う:表示は切り上げです。また、Ignore Time ScaleがオフならTimerはEngine.time_scaleの影響を受けます。

まとめ

計測はTimer、残り秒数はtime_left、終了の通知はtimeoutへ分けます。途中のstart(5.0)は残り時間への加算ではなく、5秒からのやり直しです。シーン移動へつなぐ場合はボタンによるシーン切り替えへ進めます。

学習者キャラクター
今回の内容で覚えておくポイントを確認したいです。
ガイドキャラクター
計測はTimer、残り秒数はtime_left、終了の通知はtimeoutへ分けます。途中のstart(5.0)は残り時間への加算ではなく、5秒からのやり直しです。シーン移動へつなぐ場合はボタンによるシーン切り替えへ進めます。
この記事のまとめを案内するガイドキャラクター

この記事のまとめ

Godot 4.5のTimerで残り秒数を表示し、ボタンで5秒へ戻す例です。one_shot、time_left、timeout、表示用の切り上げを図とコードで整理します。