Unity의 시간 클래스는 프로젝트에서 시간 관련 값으로 작업할 수 있는 여러 가지 중요한 기본 프로퍼티를 제공합니다.
Time 스크립트 레퍼런스 페이지의 각 멤버에 대한 설명은 쉽게 이해할 수 있으며, 그에 관해 배우기 가장 적합한 장소입니다.
다음은 일반적인 용도에 대한 아이디어를 제공하는 몇 가지 예입니다.
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.
시간 관련 프로퍼티에 대한 전체 리스트는 Time 스크립트 레퍼런스 페이지를 참조하십시오.
Update 함수를 사용하면 스크립트에서 규칙적으로 입력 및 기타 이벤트를 모니터링하고 적절한 조치를 취할 수 있습니다. 예를 들어, “전진” 키가 눌렸을 때 캐릭터를 움직일 수도 있습니다. 이와 같은 시간 기반 액션을 다룰 때 기억해야 할 중요한 점은 게임의 프레임 속도가 일정하지 않으며 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
}
}
그러나 프레임 시간이 일정하지 않기 때문에 오브젝트는 불규칙적인 속도로 움직이는 것처럼 보일 것입니다. 프레임 시간이 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);
}
}
이제 이동 거리가 distancePerFrame 이 아닌 distancePerSecond 로 주어진다는 점에 유의해야 합니다. 프레임 속도가 변화함에 따라 이동 단계의 크기 역시 맞추어 변하게 되며 따라서 이 오브젝트의 속력이 일정해집니다.
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.
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.
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.
“불릿 타임”과 같은 특수 효과를 만들기 위해서는 게임 시간의 흐름을 늦추어 애니메이션과 스크립트 반응이 더 적은 비율로 일어나도록 하는 편이 유용할 때가 있습니다. 그뿐만 아니라 때로는 게임이 일시정지했을 때처럼 게임 시간을 완전히 멈추고자 할 때도 있습니다. Unity에서는 Time Scale 프로퍼티를 통해 게임 시간이 현실 시간에 대비하여 흘러가는 속도를 조절할 수 있습니다. 이 스케일이 1.0으로 설정되어 있으면 게임 시간은 현실 시간과 동일합니다. 값이 2.0이 되면 Unity에서는 시간이 두 배 빨리 흘러갑니다(즉, 액션 스피드가 올라갑니다). 한편 값이 0.5이면 게임플레이 속도가 절반으로 줄어듭니다. 값이 0이면 시간이 완전히 “멈추게” 됩니다. 시간 스케일은 실제로 느리게 실행되도록 만드는 것이 아니라 Time.deltaTime 및 Time.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;
}
}
게임플레이를 비디오로 녹화하는 것은 시간 관리에 있어 아주 특수한 경우에 해당합니다. 화면 이미지를 저장하는 작업은 상당한 시간이 걸리기 때문에 일반 게임플레이 도중에 화면 녹화를 시도하면 평소의 게임 프레임 속도가 급격히 떨어지게 됩니다. 따라서 게임의 실제 성능을 반영하지 못하는 비디오가 만들어지게 됩니다.
다행히도 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 값을 바꿔가면서 실험해 보아야 합니다.