Version: 2021.1
ScriptableObject
Important Classes - Mathf

Important Classes - Time and frame rate 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.

Frame rate management

The Update function allows you to monitor inputs and other events regularly from a script and take appropriate action. For example, you might move a character when the “forward” key is pressed. An important thing to remember when handling time-based actions like this is that the game’s frame rate is not constant and neither is the length of time between Update function calls.

그 예로 한번에 한 프레임씩 서서히 오브젝트를 전진시키는 일을 생각해 봅시다. 처음에는 각 프레임마다 고정 거리만큼 오브젝트를 옮기면 될 것처럼 보입니다.

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

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

그러나 프레임 시간이 일정하지 않기 때문에 오브젝트는 불규칙적인 속도로 움직이는 것처럼 보일 것입니다. 프레임 시간이 10ms이면 이 오브젝트는 distancePerFrame 에 의해 초당 100회 전진합니다. 그러나 프레임 시간이 (CPU 로드 등으로 인해) 25ms로 증가하면 이 오브젝트는 초당 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);
    }
}

Note that the movement is now given as distancePerSecond rather than distancePerFrame. As the frame rate changes, the size of the movement step will change accordingly and so the object’s speed will be constant.

Depending on your target platform, use either Application.targetFrameRate or QualitySettings.vSyncCount to set the frame rate of your application. For more information, see the Application.targetFrameRate API documentation.

Fixed Timestep

메인 프레임 업데이트와는 달리 Unity의 물리 시스템은 고정 타임스텝으로 작동하며 이 점은 시뮬레이션의 정확도와 일관성에 매우 중요합니다. 물리 업데이트를 시작할 때 Unity는 마지막 물리 업데이트가 끝난 시간에 고정 타임스텝 값을 추가함으로써 “알람”을 설정합니다. 그러고 나면 물리 시스템은 알람이 꺼질 때까지 계산을 수행합니다.

고정 타임스텝의 크기는 Time 창에서 변경할 수 있으며 스크립트에서 Time.fixedDeltaTime 프로퍼티를 사용하여 읽을 수 있습니다. 타임스텝 값이 낮으면 물리 업데이트가 더 자주 일어나고 시뮬레이션이 정밀해지지만 CPU 로드 비용이 커진다는 점에 유의해야 합니다. 물리 엔진에 요구하는 것이 많지 않은 이상은 고정 타임스텝을 기본값으로 두어도 무방합니다.

Maximum Allowed Timestep

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 (due to a large number of objects in play, say). 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 can take place during a single frame. 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.

물론 상당히 많은 CPU 파워를 사용할 수 있기는 하지만 Unity에서는 효과적으로 물리 시간을 늦추어 프레임 프로세싱이 따라잡을 수 있도록 하는 옵션을 제공합니다. (Time 창의) Maximum Allowed Timestep 설정은 주어진 프레임 업데이트 동안 Unity가 물리 프로세싱에 사용하는 시간 및 FixedUpdate 호출 수에 제한을 둡니다. 프레임 업데이트 처리가 Maximum Allowed Timestep 보다 오래 걸린다면 물리 엔진은 “시간을 멈추고” 프레임 프로세싱이 따라잡도록 합니다. 일단 프레임 업데이트가 끝나고 나면, 물리 엔진은 멈췄던 때로부터 시간이 흐르지 않은 것처럼 재개됩니다. 이렇게 하면 리지드바디는 보통 실시간으로 완벽하게 움직이던 것과는 달리 약간 느려지게 됩니다. 그러나 물리 "시계"는 리지드바디가 정상적으로 움직인 것처럼 계속 따라잡습니다. 물리 시간이 느려진 것은 보통 눈에 띄지 않으며 게임플레이 성능을 위해 감수할 만합니다.

Time Scale

“불릿 타임”과 같은 특수 효과를 만들기 위해서는 게임 시간의 흐름을 늦추어 애니메이션과 스크립트 반응이 더 적은 비율로 일어나도록 하는 편이 유용할 때가 있습니다. 그뿐만 아니라 때로는 게임이 일시정지했을 때처럼 게임 시간을 완전히 멈추고자 할 때도 있습니다. Unity에서는 Time Scale 프로퍼티를 통해 게임 시간이 현실 시간에 대비하여 흘러가는 속도를 조절할 수 있습니다. 이 스케일이 1.0으로 설정되어 있으면 게임 시간은 현실 시간과 동일합니다. 값이 2.0이 되면 Unity에서는 시간이 두 배 빨리 흘러갑니다(즉, 액션 스피드가 올라갑니다). 한편 값이 0.5이면 게임플레이 속도가 절반으로 줄어듭니다. 값이 0이면 시간이 완전히 “멈추게” 됩니다. 시간 스케일은 실제로 느리게 실행되도록 만드는 것이 아니라 Time.deltaTimeTime.fixedDeltaTime을 통해 Update 및 FixedUpdate 함수에 전해지는 타임 스텝만을 변경한다는 점에 유의해야 합니다. 게임 시간이 느려지면 Update 함수는 보통 경우보다 더 자주 호출되게 되지만, 각 프레임마다 전해지는 deltaTime 스텝은 단순히 줄어듭니다. 다른 스크립트 함수는 시간 스케일의 영향을 받지 않으므로 예를 들어, 게임이 일시정지 상태일 때 일반 상호작용을 하는 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

A very special case of time management is where you want to record gameplay as a video. Since the task of saving screen images takes considerable time, the usual frame rate of the game will be drastically reduced if you attempt to do this during normal gameplay. This will result in a video that doesn’t reflect the true performance of the game.

Fortunately, Unity provides a Capture Framerate property that lets you get around this problem. When the property’s value is set to anything other than zero, game time will be slowed and the frame updates will be issued at precise regular intervals. The interval between frames is equal to 1 / Time.captureFramerate, so if the value is set to 5.0 then updates occur every fifth of a second. With the demands on frame rate effectively reduced, you have time in the Update function to save screenshots or take other actions:

//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 frame rate (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