유니티에서 일반적으로 게임을 정지 할 때에는 TimeScale을 0으로 조정한다.
그런데 사실 이것은 실제로 게임을 정지시키지는 못한다.
TimeScale을 0으로 만들어도, Update는 계속해서 호출된다.
그럼 TimeScale이 하는 역할이 무엇이냐?
실제 프레임타임에 대한 값과 DeltaTime에 대한 Scale 값을 조정하는 값이다.
예를 들어, 현재 프레임을 그리는 데에 0.01초가 들었다고 가정하자.
그러면 우리는 일반적으로 DeltaTime이 0.01초라고 생각한다.
하지만 실제로는 여기에 TimeScale값이 곱해져서 호출된다.
현재 TimeScale이 10이라면, DeltaTime은 0.01 * 10 = 0.1 초 인 것이다.
그래서 어떤 오브젝트가 Speed * DeltaTime만큼 이동한다면 TimeScale이 10일 때 10배만큼 더 빠르게 이동하게 된다.
이 성질을 이용해서 TimeScale이 0일때는 DeltaTime이 곱해진 모든 오브젝트가 정지하므로, 게임이 정지한 것 "처럼" 보이게 된다. 일반적으로 게임을 정지 할 때에 이 값을 조정하는 이유다.
TimeScale의 영향은 물리 연산에도 적용된다. (FixedDeltaTime 및 FixedUpdate) 이 두 가지에는 TimeScale을 사용할 때와 조금 다른 처리를 해주어야 한다.
FixedDeltaTime은 TimeScale값에 영향을 받는다. 마찬가지로 FixedUpdate 역시 영향을 받는다(FixedUpdate는 FixedDeltaTime마다 호출된다)예를 들면 FixedDeltaTime이 1이고, TimeScale이 0.5이면, FixedUpdate는 2초마다 호출된다.
그렇다면 게임을 멈출 때에는 TimeScale을 0으로 만들면 된다. 그러면 FixedDeltaTime은 사실 상 무한대에 가까워지므로 게임이 멈추는 효과가 난다.
하지만 게임을 느리게 하거나 빠르게 했을 때 문제가 있다.
FixedDeltaTime의 기본값은 0.02다. 초당 50번 호출된다는 뜻이다.
그런데 TimeScale이 0.1이면 초당 5번만 호출될 것이다.
그러면 물리 연산에 있어서 문제가 발생하지 않을 수 없다. 너무 빠른 오브젝트가 지나가는 경우 물리 연산이 무시될 가능성이 높아지고, FixedUpdate를 통해 이동하는 오브젝트의 경우 끊김이 발생한다.
그래서 Unity에서는 TimeScale을 조작할 때에 FixedDeltaTime도 조작할 것을 권장한다.
즉, 원래의 TimeStep마다 FixedUpdate가 호출되도록 하는 것이다.
단, 여기서 몇 가지 주의 점이 있는데,
TimeScale이 0이 될 때에는 곱해주면 안된다는 것(그 경우 물리 연산에 CPU가 무한정 할당되어 게임이 멈추다시피 한다),
그 외에 경우에는 FixedDeltaTime값을 되돌릴 때에 FixedTime이나 FixedDeltaTime을 이용하지 말 것(이미 변경된 값이기 때문에 의미가 없다.)
되돌리기 전에 FixedDeltaTime값을 저장해두거나, 지정된 값을 사용하고 있다면 해당 값에 Time.TimeScale값을 곱해주도록 하면 된다.
정리하자면,
게임을 멈출 때
Time.TimeScale = 0f;
게임을 느리게 하거나 빠르게 할 때,
public void SetTimeScale(float scale)
{
Time.TimeScale = scale;
Time.FixedDeltaTime = 0.02f * Time.TimeScale;
}
와 같이 사용하면 된다.