Version: 2020.3
ScriptableObject
Important Classes - Mathf

Important Classes - Time and Framerate Management

The Time Class

Unity’s Time class provides a number of important basic properties which allow you to work with time-related values in your project.

The descriptions for each member of Time script reference page are self explanatory, and that is the best place to learn about them.

Listed here is a small selection of examples to provide an idea of the common and typical uses:

Time.time returns the amount of time since your project started playing.

Time.deltaTime returns the amount of time that elapsed since the last frame completed.

Time.timeScale represents the rate at which time elapses. You can read this value, or set it to control how fast time passes, allowing you to create slow-motion effects.

For the full list of time-related properties, see the Time script reference page.

Update 関数を使用すると、定期的にスクリプトからの入力やその他のイベントをモニターして、適切な処置を取ることができます。例えば、Forward キーが押されるとキャラクターが動くとします。このような時系列のアクションを取り扱う場合、ゲームのフレームレートは一定ではなく、 Update 関数の呼び出しの時間的な間隔も一定ではないということに気を付けてください。

この例として、フレームごとに、徐々に前方にオブジェクトを動かす作業を考えて見ましょう。最初は、フレームごとに一定の距離ずつオブジェクトを移動しているように見えるかもしれません。

//C# script example
using UnityEngine;
using System.Collections;

public class ExampleScript : MonoBehaviour {
    public float distancePerFrame;
    
    void Update() {
        transform.Translate(0, 0, distancePerFrame); // this is incorrect
    }
}

しかし、フレーム時間が一定でないので、オブジェクトは不規則な速度で移動するように見えます。フレーム時間が 10 ミリ秒なら、オブジェクトは 1 秒に distancePerFrame の距離を 100 回前進します。しかし、フレーム時間が 25 ミリ秒に増加した場合 (例えば CPU 負荷のため) 1 秒に 40 回しか前進できず、進む距離が少なくなります。その解決方法は、フレーム時間に応じた移動の距離をスケーリングすることです。移動の距離は Time.deltaTime プロパティーから読み取り可能です。

//C# script example
using UnityEngine;
using System.Collections;

public class ExampleScript : MonoBehaviour {
    public float distancePerSecond;
    
    void Update() {
        transform.Translate(0, 0, distancePerSecond * Time.deltaTime);
    }
}

ここでの移動は distancePerFrame ではなく distancePerSecond で与えられていることに注意してください。フレームレートの変化に応じて移動距離が変わるため、オブジェクトの速度は一定になります。

Fixed Timestep (fixedDeltaTime)

Unlike the main frame update, Unity’s physics system does work to a fixed timestep, which is important for the accuracy and consistency of the simulation. At the start of the physics update, Unity performs as many physics updates as necessary to catch up with the current time.

If your game or app is running at a higher framerate than the fixed timestep value, it means each frame is less than the duration of a single fixed timesetp, so Unity will either perform one or zero fixed physics updates per frame. For example, if your fixed timestep value is 0.02, there should be 50 fixed updates per second. If your game or app then runs at approximately 60 frames per second, there will occasionally be a frame where no fixed update occurs - in approximately one in ten frames.

If your game or app is running at a lower framerate than the fixed timestep value, it means each frame duration is longer than a single fixed timesetp. To account for this, Unity will perform one or more fixed updates each frame, so that the physics simulation “catches up” with the amount of time elapsed since the last frame. For example, if your fixed timestep value is 0.01, there should be 100 fixed updates per second. If your game or app then runs at approximately 25 frames per second, Unity will perform approximately four fixed updates every frame to keep the physics simulation time up-to-date with the current frame time.

You can change the duration of the fixed timestep in the Time window, and you can read it from a script using the Time.fixedDeltaTime property. Note that a lower value for the timestep will result in more frequent physics updates and more precise simulation but at the cost of greater CPU load. You probably won’t need to change the default fixed timestep unless you are placing high demands on the physics engine that require extra high precision.

Unity’s Time Logic

The following flowchart illustrates the logic that Unity uses to count time in a single frame, and how the time, deltaTime, fixedDeltaTime, and maximumDeltaTime properties relate to each other.

Maximum Allowed Timestep (maximumDeltaTime)

When a very slow frame occurs, The Maximum Allowed Timestep (in the Time window) limits the value of deltaTime in the following frame to avoid undesirable side-effects from very large deltaTime values. This value is also accessible via scripting as Time.maximumDeltaTime.

For example, an application running at 60Hz with a maximumDeltaTime value of 0.333 that encounters a single very slow frame (2 seconds) would exhibit a behavior similar to that shown in the following table:

Frame unscaledTime time deltaTime smoothDeltaTime
1 0.000 3.000 0.014 0.014
2 0.014 3.015 0.014 0.014
3 0.028 3.028 0.014 0.014
4 (a) 0.042 3.043 0.014 0.014
5 2.062 (b) 3.376 (c) 0.333 (d) 0.078
6 2.082 3.396 0.020 0.066
7 2.096 3.410 0.014 0.056
8 2.110 3.424 0.014 0.048

The data above illustrates the effect of the maximum allowed timestep value (the maximumDeltaTime). It shows eight frames, numbered one to eight. During frame four in this example (a), there is a slow-down which causes the frame to take two seconds to complete, rather than around 25 milliseconds like the others. The effects of this are reflected in the values on the following frame. The pause is visible as increment of around 2 in the unscaledTime value (b), however the Time.time value only increments by 0.333 (c), because that is the value of maximum allowed timestep when this example was running. The deltaTime value for this frame is also clamped to the maximum allowed timestep (d).

The maximum allowed timestep value also affects the physics timekeeping. The fixed timestep keeps the physical simulation accurate in real time but it can cause problems in cases where the game makes heavy use of physics and the gameplay frame rate has also become low, for example due to a large number of objects in motion. The main frame update processing has to be “squeezed” in between the regular physics updates, and if there is a lot of processing to do then several physics updates might need to take place during a single frame to catch the physics simulation up with the current time. Since the frame time, positions of objects and other properties are frozen at the start of the frame, the graphics can get out of sync with the more frequently updated physics.

Limited CPU power means there is a limit to what the physics system can process, so Unity has an option to let you effectively slow down physics time to let the frame processing catch up if it falls behind. The maximum allowed timestep puts a limit on the amount of time Unity will spend processing physics and FixedUpdate calls during a given frame update.

If a frame update takes longer than Maximum Allowed Timestep to process, the physics engine will “stop time” and let the frame processing catch up. Once the frame update has finished, the physics resumes as though no time has passed since it was stopped. The result of this is that rigidbodies will not move perfectly in real time as they usually do but will be slowed slightly. However, the physics “clock” will still track them as though they were moving normally. The slowing of physics time is usually not noticeable and is often an acceptable trade-off against gameplay performance.

Time Scale

「bullet-time」のような特殊効果のために、ゲームの時間の経過を遅くして、アニメーションやスクリプトの応答を少ない割合で発生させることは、有効な場合があります。さらに、ゲームを中断するときのように、完全にゲーム時間を凍結したい場合があるかもしれません。Unity は、リアルタイムと関連づけてゲーム時間をどのように進行させるかについて制御する Time Scale プロパティーを持っています。スケールを 1.0 に設定すると、ゲームの時間はリアルタイムに一致します。2.0 の値では Unity で 2 倍の速さで時間が経過します (つまり、アクションは、高速化されます)。他方、0.5 の値ではゲームを半分の速度に遅くします。0 の値は時間を完全に「停止」します。タイムスケールは、実際に実行を遅くするわけではなく、単に Time.deltaTimeTime.fixedDeltaTime を通して Update と FixedUpdate 関数に知らせる時間ステップを変えているにすぎません。Update 関数は、ゲーム時間が遅くなるとき通常より頻繁に呼び出される傾向がありますが、単に、各フレームに伝えられる デルタタイム の処理が減らされます。他のスクリプト関数はタイムスケールから影響を受けません。ですから、例えば、ゲームが停止している場合は、正常なインタラクションで GUI を表示できます。

Time ウィンドウには、グローバルにタイムスケールを設定できるプロパティーがありますが、一般的に、Time.timeScale プロパティーを使用してスクリプトから値を設定すると、より便利です。

//C# script example
using UnityEngine;
using System.Collections;

public class ExampleScript : MonoBehaviour {
    void Pause() {
        Time.timeScale = 0;
    }
    
    void Resume() {
        Time.timeScale = 1;
    }
}

Capture Framerate

ゲームをビデオとして記録したいケースは時間管理の非常に特別なケースです。画面を保存する作業にはかなりの時間がかかるため、通常のゲーム中にこれを行おうとすると、ゲームの通常のフレームレートは大幅に削減されます。これではゲームの真の性能を反映しない動画になってしまいます。

Unity はこの問題を回避することができるCapture Framerate プロパティーを提供しています。プロパティーの値が 0 以外の値に設定されている場合、ゲームタイムは遅くなり、フレーム更新は正確な一定の間隔で行われます。フレーム間の間隔は、1/(Time.captureFramerate) に等しく、5.0 に値が設定される場合、更新が 1/5 秒ごとに発生します。フレームレートへの要求を効果的に削減すると、Update 関数の時間で、スクリーンショットを保存したり、他の操作を実行できます。

//C# script example
using UnityEngine;
using System.Collections;

public class ExampleScript : MonoBehaviour {
    // Capture frames as a screenshot sequence. Images are
    // stored as PNG files in a folder - these can be combined into
    // a movie using image utility software (eg, QuickTime Pro).
    // The folder to contain our screenshots.
    // If the folder exists we will append numbers to create an empty folder.
    string folder = "ScreenshotFolder";
    int frameRate = 25;
        
    void Start () {
        // Set the playback framerate (real time will not relate to game time after this).
        Time.captureFramerate = frameRate;
        
        // Create the folder
        System.IO.Directory.CreateDirectory(folder);
    }
    
    void Update () {
        // Append filename to folder name (format is '0005 shot.png"')
        string name = string.Format("{0}/{1:D04} shot.png", folder, Time.frameCount );
        
        // Capture the screenshot to the specified file.
        Application.CaptureScreenshot(name);
    }
}

一般的にこの技術を使用して動画を記録するのは非常に有効のようですが、著しく遅くなると、ゲームをプレイすることが難しくなります。テストプレーヤーの仕事を困難にしないよう十分なレコーディング時間を可能にするために Time.captureFramerate 値を試してみると良いでしょう。

ScriptableObject
Important Classes - Mathf