ひとりでのアプリ開発 - fineの備忘録 -

ひとりでアプリ開発をするなかで起こったことや学んだことを書き溜めていきます

Unity - Time.timeScale:Unity 内の時間経過を操作し、ポーズや倍速の機能を作る

初めに

 UnityEngine の timeScale という変数を変更することで、Unity 内の時間の経過を操作することができます。本記事では、timeScale の使い方や timeScale の影響をうけるものについてまとめます。



Time.timeScale

timeScale について

 Time.timeScale は

Unity 内の時間の経過をスケールする UnityEngine.Time 内の変数(float)

です。「Unity 内での時間と現実の時間の比の値」、すなわち「現実で1秒間経過した際に Unity 内で何秒経過するか」を表した数字になります。

(例)

timeScale の値 現実で1秒経過した際の Unity 内での経過時間
timeScale = 1 現実で1秒間経過すると、Unity 内でも1秒経過する
(現実の時間と Unity 内での時間が同じ)
timeScale = 0.5 現実で1秒間経過すると、Unity 内では 0,5 秒経過する
(Unity 内の時間は現実の時間の半分のスピードで進む)
timeScale = 2 現実で1秒間経過すると、Unity 内では 0,5 秒経過する
(Unity 内の時間は現実の倍のスピードで進む)

仕組み

 ドキュメントによると、timeScale は、実際に実行を遅くするわけではなく、単に Time.deltaTime と Time.fixedDeltaTime を通して Update と FixedUpdate 関数に知らせる時間ステップを変えることで処理をしているようです。

影響を受ける範囲

 timeScale は realtimeSinceStartup(ゲーム開始からのリアルタイム(秒))を除いてすべての時間とデルタ時間を測定する Time クラスの変数が影響します。

 Time クラスの変数はドキュメントにまとめてあります。
docs.unity3d.com

 当然、デルタ時間に依存する操作にも影響を与えるため、Rigidbody などの物理演算も影響をうけます。

※Transform はデルタ時間に依存していないため、影響を受けません。

Update と FixedUpdate での違い

 Update と FixedUpdate では、timeScale において、大きな違いがあります。それは

Update が呼び出される回数は timeScale を変えても変化しない
FixedUpdate が呼び出される回数は timeScale を変えると変化する

という点です。

上記で Rigidbody は timeScale の影響を受けることを説明しました。Rigidbody に関する記述は Update 内に書いても timeScale の影響を受けます。

コルーチン

 コルーチンの実行間隔はフレームごと(Update と同じ)であるため、基本的な扱いは Update と同じです。しかし、次の処理を行う場合は注意が必要です。

WaitForSeconds スケール化した時間を使用して、指定した秒数の間コルーチンの実行を待つ
WaitForSecondsRealtime スケール化されていない時間を使用して、指定した秒数の間コルーチンの実行を待つ
WaitForFixedUpdate FixedUpdate 関数が呼び出されるまで待つ

 WaitForseconds は timeScale の影響を受けるため、現実での時間を指定したい場合は、timeScale が 1 でない場合は、WaitForSecondsRealtime を使用しましょう。
 また、FixedUpdate もtimeScale の影響を受けるので、WaitForFixedUpdate も当然 timeScale の影響を受けます。

docs.unity3d.com
docs.unity3d.com
docs.unity3d.com

スクリプトから timeScale を変更する(ポーズ・倍速の実装)

 下のコードのように、Time.timeScale を変更できます。

using UnityEngine;

public class Example : MonoBehaviour
{
      //ポーズ
      void Pause()
      {
          Time.timeScale = 0.0f;
      }

      //倍速
      void Double()
      {
          Time.timeScale = 2.0f;
      }
}

 このスクリプトの関数をボタンなどを使って呼び出せば、ポーズや倍速ができます。

timeScale に依存しない時間を使いたい

 場合によっては、timeScale が 0 の場合でもアニメーションは動いてほしい、このオブジェクトの処理だけは続けてほしいなどtimeScale に依存しない時間を使いたい場合があります。その場合は、unscaledTime と unscaledDeltaTime を使います。

変数 説明
Time.unscaledTime ゲーム開始からの秒数 (読み取り専用)。フレームの timeScale に依存しない。
unscaledDeltaTime 最後のフレームから現在のフレームまでの秒数(読み取り専用)。フレームの timeScale に依存しない。

最後に

 timeScale は経過時間のスケールに影響を与える。timeScale = 0 にするとポーズを作ることができ、timeScale = 2 にすると倍速することができる。影響を受けるものと受けないものがあるので、timeScale を変更する場合は注意すべし。