「3秒後に敵を出したい」「1秒ごとに数字を減らしたい」「ポーズボタンでゲームを止めたい」。ゲームを作っていると、時間を扱う処理がたくさん出てきます。今回は、Updateでのタイマー、Invoke、コルーチン、そしてTime.timeScaleを使った一時停止をまとめてご紹介します!
目次
この記事で学べること
- Time.deltaTimeを足していくタイマーの作り方
- Invokeで「〇秒後に」メソッドを呼ぶ方法
- コルーチンで「待ってから続きをする」処理の書き方
- Time.timeScaleでゲームを一時停止する方法と、止まらない時間の扱い方
前提知識
- メソッドを作ろう:処理に名前を付けてまとめる
- よく使うUnity専用の関数とプロパティ:TimedBlockのサンプル
- スクリプトでシーンを切り替えよう:DelayedSceneLoaderのサンプル
時間を扱う3つの方法
| 方法 | 向いている場面 |
|---|---|
| Updateでタイマー | 残り時間の表示など、毎フレーム時間を見たいとき |
| Invoke | 「〇秒後に1回だけ」メソッドを呼びたいとき |
| コルーチン | 「待つ → 何かする → また待つ」のように、順番に進めたいとき |
どれを使っても出来ることは似ていますが、書きやすさが違います。順番に見ていきましょう。
Updateでタイマーを作る
6-9のTimedBlockでやったように、Time.deltaTimeを足していくと経過時間が分かります。
using UnityEngine;
public class TimeCountdownTimer : MonoBehaviour
{
[SerializeField] private float limitTime = 10f;
private float remainingTime;
private bool isFinished = false;
void Start()
{
remainingTime = limitTime;
}
void Update()
{
if (isFinished)
{
return;
}
remainingTime -= Time.deltaTime;
if (remainingTime <= 0f)
{
remainingTime = 0f;
isFinished = true;
Debug.Log("タイムアップ!");
}
}
}
- 残り時間を毎フレーム減らしていく
- 0になったらboolで「終わった」を覚えて、2回目以降は何もしない
- 残り時間を画面に表示したい場合は、9-4の記事のTimerDisplayと組み合わせます
Invoke:〇秒後にメソッドを呼ぶ
using UnityEngine;
public class TimeInvokeExample : MonoBehaviour
{
void Start()
{
// 2秒後にSpawnMessageを1回呼ぶ
Invoke(nameof(SpawnMessage), 2f);
// 1秒後から、0.5秒ごとにTickを呼び続ける
InvokeRepeating(nameof(Tick), 1f, 0.5f);
}
void SpawnMessage()
{
Debug.Log("2秒たちました!");
}
void Tick()
{
Debug.Log("チクタク");
}
void OnDisable()
{
// 予約していたInvokeを全部取り消す
CancelInvoke();
}
}
Invoke(メソッド名, 秒数):その秒数のあとに1回だけ呼ぶInvokeRepeating(メソッド名, 最初の待ち時間, 間隔):くり返し呼ぶCancelInvoke():予約を取り消す(CancelInvoke(nameof(Tick))のように1つだけ取り消すことも出来ます)- メソッド名は
nameof(メソッド名)で書きましょう。Invoke("SpawnMessage", 2f)のように文字列で書くと、つづりを間違えてもエラーにならず、何も起きないまま気づけません。nameofならつづりが違うとVS Codeで赤い波線が出ます - 引数のあるメソッドはInvokeでは呼べません
コルーチン:待ってから続きをする
「3、2、1、スタート!」のように、待つ → 何かする → また待つを順番に書きたいときは、コルーチンが便利です。
using System.Collections;
using UnityEngine;
public class TimeCoroutineCountdown : MonoBehaviour
{
void Start()
{
StartCoroutine(CountdownRoutine());
}
IEnumerator CountdownRoutine()
{
for (int i = 3; i > 0; i--)
{
Debug.Log(i);
yield return new WaitForSeconds(1f); // 1秒待つ
}
Debug.Log("スタート!");
}
}
コルーチンの書き方
using System.Collections;を一番上に書く(IEnumeratorを使うため)- メソッドの型を
IEnumeratorにする yield return new WaitForSeconds(秒数);の行で、そこで待ってから続きを実行する- 呼ぶときは
StartCoroutine(メソッド名());(普通のメソッドのようにCountdownRoutine();と呼ぶだけでは動きません)
よく使う待ち方
| 書き方 | 待つもの |
|---|---|
yield return new WaitForSeconds(1f); | 1秒(ゲームの時間) |
yield return new WaitForSecondsRealtime(1f); | 1秒(一時停止中でも進む時間) |
yield return null; | 次のフレームまで |
yield return new WaitUntil(() => 条件); | 条件がtrueになるまで |
コルーチンを止める
private Coroutine countdown;
void Start()
{
countdown = StartCoroutine(CountdownRoutine());
}
void StopCountdown()
{
if (countdown != null)
{
StopCoroutine(countdown);
countdown = null;
}
}
StartCoroutineの結果を変数に入れておくと、あとでStopCoroutineで止められます- オブジェクトが非表示になったり消えたりすると、そのオブジェクトで動いていたコルーチンも止まります
8-3の記事のDelayedSceneLoaderも、「少し待ってからシーンを切り替える」ためにコルーチンを使っていました。仕組みはこの記事と同じです。
スライムコルーチンを書いたのに、1回目の数字しか出てこない・・・



StartCoroutineで呼んでるかな?それと、再生中にオブジェクトを非表示にするとコルーチンも止まっちゃうから、そこも確認してみてね
Time.timeScaleで一時停止する
Time.timeScaleは、ゲームの時間の進む速さです。
Time.timeScale = 1f;:通常Time.timeScale = 0f;:止まる(一時停止)Time.timeScale = 0.5f;:半分の速さ(スローモーション)
using UnityEngine;
public class TimePauseSwitch : MonoBehaviour
{
private InputSystem_Actions inputActions;
private bool isPaused = false;
void Awake()
{
inputActions = new InputSystem_Actions();
}
void OnEnable()
{
inputActions.Enable();
}
void OnDisable()
{
inputActions.Disable();
// このスクリプトが無効になるときは、止めたままにしない
Time.timeScale = 1f;
}
void Update()
{
// UIのCancel(キーボードのEscキーなど)でポーズの切り替え
if (inputActions.UI.Cancel.WasPressedThisFrame())
{
isPaused = !isPaused;
Time.timeScale = isPaused ? 0f : 1f;
Debug.Log(isPaused ? "一時停止" : "再開");
}
}
}
Time.timeScale = 0f;にすると、次のものが止まります。
Time.deltaTimeが0になるので、それを使った移動やタイマー- 物理演算(Rigidbodyの動き)
WaitForSecondsで待っているコルーチン- Invoke
一方で、Update自体は呼ばれ続けます。だから上のスクリプトのように、止まっている間もキー入力で再開できます。
一時停止中も動かしたいもの
ポーズメニューのアニメーションなど、止まっていてほしくないものは、止まらない時間を使います。
| 止まる時間 | 止まらない時間 |
|---|---|
Time.deltaTime | Time.unscaledDeltaTime |
WaitForSeconds | WaitForSecondsRealtime |
よくあるエラーと対処法
エラー:The type or namespace name ‘IEnumerator’ could not be found
- 原因:
using System.Collections;を書いていない - 対処法:スクリプトの一番上に
using System.Collections;を足す
エラー:コルーチンが動かない(1行目で止まる、何も起きない)
- 原因:
StartCoroutine(...)ではなく、普通のメソッドのように呼んでいる。またはオブジェクトが非表示になっている - 対処法:
StartCoroutine(メソッド名());で呼ぶ。オブジェクトが有効になっているか確認する
エラー:Trying to Invoke method: ○○ couldn’t be called.
- 原因:Invokeに渡したメソッド名のつづりが違う(文字列で書いている)
- 対処法:
Invoke(nameof(メソッド名), 秒数)で書く
エラー:一時停止から戻れない・次のシーンが止まったまま
- 原因:
Time.timeScale = 0f;のまま、シーンを切り替えたり、再開の処理を通らなかった - 対処法:シーンを切り替える前や、ポーズを解除するときに
Time.timeScale = 1f;に戻す。timeScaleはシーンをまたいでもそのまま残ります
まとめ
- Updateでタイマー:
Time.deltaTimeを足す・引く - Invoke:〇秒後に1回(
nameofで書く)。くり返しはInvokeRepeating - コルーチン:
IEnumerator+yield return new WaitForSeconds()+StartCoroutine - Time.timeScale:0で一時停止。止まらない時間は
unscaledDeltaTimeとWaitForSecondsRealtime
コメント