【Unity】TimeScaler (スローモーション) コンポーネントの作り方

Godot 4ゲーム制作 実践ドリル 100本ノック

新品価格
¥1,250から
(2025/12/13 21:27時点)

脱・初心者!Godot 4 ゲーム開発の「2歩目」

新品価格
¥831から
(2025/12/13 21:39時点)

Godot4ローグライク入門 ~ダンジョン自動生成~

新品価格
¥831から
(2025/12/13 21:44時点)

Godot4& GDScriptではじめる 2Dゲーム開発レシピ

新品価格
¥590から
(2025/12/13 21:46時点)

Unityを触り始めたばかりの頃は、つい何でもかんでも Update() に書いてしまいがちですよね。プレイヤー入力、敵AI、UI更新、デバッグ処理…すべてを1つの巨大スクリプトに押し込むと、数日後には「どこを触ればいいのか分からない」「ちょっと直しただけで別のところが壊れる」という状態になりやすいです。

特に「一時的なデバッグ機能(スローモーション、早送り、フレームスキップなど)」をメインのゲームロジックに直書きしてしまうと、本番ビルド前に削除し忘れたり、挙動が複雑になったりして危険です。

そこでこの記事では、「ゲーム全体の時間スケールをキー入力で変える」機能だけを切り出した、小さなデバッグ用コンポーネント 「TimeScaler」 を作っていきます。コンポーネントを分離しておけば、必要なシーンにだけポンと置くだけでスローモーションデバッグが使えるようになりますし、要らなくなったらコンポーネントを外すだけで安全に無効化できます。

【Unity】ワンキーでスローモーション&早送り!「TimeScaler」コンポーネント

以下が、Unity6(C#)で動作する「TimeScaler」コンポーネントのフルコードです。
ゲーム全体の Time.timeScale を、指定したキー入力で 0.1倍 / 1倍 / 2倍 に切り替えられるようにします。


using UnityEngine;

/// <summary>
/// デバッグ用の時間スケール変更コンポーネント。
/// 指定したキー入力でゲーム全体の速度を変更します。
/// - 低速(スローモーション)
/// - 通常速度
/// - 高速(早送り)
///
/// ※本番ビルドではオフにすることを推奨します。
/// </summary>
public class TimeScaler : MonoBehaviour
{
    // --- 設定項目(インスペクターから変更可能) ---

    [Header("時間スケール設定")]
    [Tooltip("スローモーション時の Time.timeScale 値(例: 0.1)")]
    [SerializeField] private float slowScale = 0.1f;

    [Tooltip("通常速度時の Time.timeScale 値(通常は 1.0)")]
    [SerializeField] private float normalScale = 1.0f;

    [Tooltip("早送り時の Time.timeScale 値(例: 2.0)")]
    [SerializeField] private float fastScale = 2.0f;

    [Header("キー設定")]
    [Tooltip("スローモーションに切り替えるキー")]
    [SerializeField] private KeyCode slowKey = KeyCode.Alpha1;

    [Tooltip("通常速度に戻すキー")]
    [SerializeField] private KeyCode normalKey = KeyCode.Alpha2;

    [Tooltip("早送りに切り替えるキー")]
    [SerializeField] private KeyCode fastKey = KeyCode.Alpha3;

    [Header("オプション")]
    [Tooltip("起動時に自動で通常速度にリセットするか")]
    [SerializeField] private bool resetOnStart = true;

    [Tooltip("エディタのコンソールにログを出すか(デバッグ用)")]
    [SerializeField] private bool logToConsole = true;

    // 現在のターゲットスケール(補間用)
    private float currentTargetScale;

    [Tooltip("時間スケールを滑らかに補間するか(true なら徐々に変化)")]
    [SerializeField] private bool smoothTransition = true;

    [Tooltip("補間スピード(大きいほど素早く切り替わる)")]
    [SerializeField] private float transitionSpeed = 10f;

    private void Awake()
    {
        // 起動時に現在の timeScale をターゲットとして保持
        currentTargetScale = Time.timeScale;
    }

    private void Start()
    {
        // 必要であれば、起動時に通常速度へリセット
        if (resetOnStart)
        {
            SetTimeScale(normalScale);
        }
    }

    private void Update()
    {
        // キー入力を監視して、ターゲットの時間スケールを切り替え
        HandleInput();

        // 実際の Time.timeScale を更新
        UpdateTimeScale();
    }

    /// <summary>
    /// キー入力を監視して currentTargetScale を変更する。
    /// </summary>
    private void HandleInput()
    {
        // スローモーション
        if (Input.GetKeyDown(slowKey))
        {
            SetTimeScale(slowScale);
        }

        // 通常速度
        if (Input.GetKeyDown(normalKey))
        {
            SetTimeScale(normalScale);
        }

        // 早送り
        if (Input.GetKeyDown(fastKey))
        {
            SetTimeScale(fastScale);
        }
    }

    /// <summary>
    /// 時間スケールの目標値を設定する。
    /// 実際の Time.timeScale 更新は UpdateTimeScale() で行う。
    /// </summary>
    /// <param name="newScale">変更したい時間スケール</param>
    private void SetTimeScale(float newScale)
    {
        // 0未満は危険なのでクランプしておく
        if (newScale < 0f)
        {
            newScale = 0f;
        }

        currentTargetScale = newScale;

        if (logToConsole)
        {
            Debug.Log($"[TimeScaler] Target timeScale = {currentTargetScale}");
        }

        // 補間を使わない場合は即座に反映
        if (!smoothTransition)
        {
            Time.timeScale = currentTargetScale;
        }
    }

    /// <summary>
    /// currentTargetScale に向かって Time.timeScale を更新する。
    /// </summary>
    private void UpdateTimeScale()
    {
        if (!smoothTransition)
        {
            // 補間を使わない場合は何もしない(SetTimeScale ですでに反映済み)
            return;
        }

        // 現在値からターゲット値へ、指数的に補間
        float current = Time.timeScale;
        float target = currentTargetScale;

        // 差がごく小さい場合は直接ターゲット値にスナップ
        if (Mathf.Approximately(current, target))
        {
            Time.timeScale = target;
            return;
        }

        float newScale = Mathf.Lerp(current, target, Time.unscaledDeltaTime * transitionSpeed);
        Time.timeScale = newScale;
    }

    /// <summary>
    /// エディタ上で値が変更されたときに呼ばれる。
    /// 不正な値を自動で補正しておく。
    /// </summary>
    private void OnValidate()
    {
        // マイナス値は許可しない
        slowScale = Mathf.Max(0f, slowScale);
        normalScale = Mathf.Max(0f, normalScale);
        fastScale = Mathf.Max(0f, fastScale);

        // 補間スピードも 0 以上に制限
        transitionSpeed = Mathf.Max(0f, transitionSpeed);
    }

    /// <summary>
    /// 他のスクリプトからも安全に時間スケールをリセットできるヘルパー。
    /// 例: ステージ開始時に必ず通常速度へ戻したい場合など。
    /// </summary>
    public void ResetToNormal()
    {
        SetTimeScale(normalScale);
    }
}

使い方の手順

  1. コンポーネントを作成する
    上記コードを TimeScaler.cs という名前で保存し、Unity プロジェクトの Assets フォルダ(任意のサブフォルダでもOK)に置きます。
  2. 空のゲームオブジェクトにアタッチ
    シーン内で右クリック → Create Empty で空の GameObject を作成し、名前を TimeScaler などに変更します。
    その GameObject に TimeScaler コンポーネントをドラッグ&ドロップでアタッチしましょう。
    (カメラやゲーム管理用オブジェクトに付けても構いませんが、「デバッグ系コンポーネント専用オブジェクト」を1つ作ってまとめておくと後で管理しやすいです)
  3. インスペクターでキーと倍率を設定
    • Slow Scale:スローモーション時の倍率(例: 0.1)
    • Normal Scale:通常速度の倍率(通常は 1.0)
    • Fast Scale:早送り時の倍率(例: 2.0)
    • Slow Key:スローモーションに切り替えるキー(初期値: 1 キー)
    • Normal Key:通常速度に戻すキー(初期値: 2 キー)
    • Fast Key:早送りに切り替えるキー(初期値: 3 キー)
    • Reset On Start:シーン開始時に強制的に通常速度へ戻すか
    • Log To Console:時間スケール変更時にコンソールへログを出すか
    • Smooth Transition:時間スケール変更を滑らかにするか
    • Transition Speed:滑らかにする場合の切り替えスピード

    デバッグ用途なら、とりあえず以下のような設定がおすすめです。

    • Slow Scale = 0.1
    • Normal Scale = 1.0
    • Fast Scale = 2.0
    • Smooth Transition = false(パキッと切り替わるように)
  4. 実行して動作を確認
    再生ボタンを押してゲームを実行し、設定したキーを押してみましょう。
    • スローモーションキー(デフォルト: 1) → 全体の動きが 0.1倍速になる
    • 通常速度キー(デフォルト: 2) → 1倍速に戻る
    • 早送りキー(デフォルト: 3) → 2倍速で進む

    具体的な使用例としては、例えば以下のようなシーンで使うと便利です。

    • プレイヤーの当たり判定:スローモーションにして、弾や敵との衝突タイミングを細かく確認する。
    • 敵AIの動き:早送りにして、長時間プレイしないと見えないパターンがちゃんと動くかを素早くチェックする。
    • 動く床やギミック:スローモーションで動かして、プレイヤーが落ちないか、アニメーションが破綻しないかを確認する。

    シーンごとに「TimeScaler」付きのオブジェクトをプレハブ化しておけば、新しいステージでもドラッグ&ドロップ1つで同じデバッグ環境を再現できます。

メリットと応用

この「TimeScaler」コンポーネントを使うメリットは、機能が完全に独立した小さな部品としてまとまっていることです。

  • プレイヤー操作スクリプトや敵AIの中に Time.timeScale のゴリ押しコードを書かなくて済む。
  • 「デバッグ用の時間操作」はこのコンポーネントだけを見れば挙動がすべて分かる。
  • 不要になったらコンポーネントを外すだけで、本番コードに一切ゴミが残らない。
  • シーンをまたいでも、同じプレハブを置くだけで共通のデバッグ環境を使い回せる。

レベルデザインの観点でも、時間スケールをいじれるとかなり便利です。

  • 「このジャンプ、ギリギリすぎない?」というときにスローモーションで挙動を確認し、コライダーや速度を微調整。
  • 長時間プレイしないと発生しないイベント(一定時間後に湧く敵など)を早送りでサクッと検証。
  • パーティクルやアニメーションのスピード感を、全体の時間スケールと合わせてチェック。

さらに、コンポーネント指向で作っているので、ちょっとした改造も簡単です。例えば「一時的に時間を止める(ポーズ)」機能を追加したい場合は、こんなメソッドを足すだけでもOKです。


    /// <summary>
    /// 一時停止トグル機能の例。
    /// もう一度呼ぶと元のスケールに戻す。
    /// (Pause キーなどから呼び出すことを想定)
    /// </summary>
    private float _beforePauseScale = 1f;
    private bool _isPaused = false;

    public void TogglePause()
    {
        if (_isPaused)
        {
            // ポーズ解除:元のスケールに戻す
            SetTimeScale(_beforePauseScale);
            _isPaused = false;
        }
        else
        {
            // ポーズ開始:現在のスケールを保存し、0 にする
            _beforePauseScale = Time.timeScale;
            SetTimeScale(0f);
            _isPaused = true;
        }
    }

上のように、小さな責務ごとにコンポーネントを分けておくと、「スローモーション」「早送り」「ポーズ」「リプレイ」など、デバッグ機能を段階的に育てていきやすくなります。巨大な God クラスを作るのではなく、こうした小さな部品を組み合わせていくスタイルを意識していきましょう。

Godot 4ゲーム制作 実践ドリル 100本ノック

新品価格
¥1,250から
(2025/12/13 21:27時点)

脱・初心者!Godot 4 ゲーム開発の「2歩目」

新品価格
¥831から
(2025/12/13 21:39時点)

Godot4ローグライク入門 ~ダンジョン自動生成~

新品価格
¥831から
(2025/12/13 21:44時点)

Godot4& GDScriptではじめる 2Dゲーム開発レシピ

新品価格
¥590から
(2025/12/13 21:46時点)

URLをコピーしました!