Time.deltaTime은 유니티를 사용하면 누구나 한 번쯤은 사용할 것입니다.
저 또한 많이 사용했지만 헷갈리는 부분이 많았습니다.
이번 글에서는 실험과 문서를 통해 Time.deltaTime에 대해서 알아보는 시간을 가지도록 하겠습니다.
출처 : 리틀 위치 아카데미아 (트리거)
https://www.sakugabooru.com/post/show/1118
혹시 애니메이션을 좋아하시나요?
저는 좋아합니다. 그중에서는 옛날 가이낙스와 트리거를 좋아합니다.
가이낙스, 트리거는 낮은 프레임으로 역동성 있는 연출을 해내는 점이 매력적입니다.
뜬금없는 애니메이션 이야기에 당황스러우시겠지만 Time.deltaTime은 프레임과 관련이 있어서 이렇게 말을 꺼내보았습니다.
애니메이션의 동작 방식은 정지된 그림을 빠르게 보여주어 움직인다고 착각하게 만드는 것입니다. (위의 예시로 올린 리틀 위치 아카데미아도 정지된 여러 그림이 모여서 움직임을 만들어냈습니다)
프레임이란 애니메이션을 구성하는 한 장의 그림을 말합니다.
초당 그림의 수를 FPS(Frames Per Second)라고 하는데 모든 장면을 높은 FPS로 만들기에는 예산의 제한이 있기에 장면에 따라 프레임의 수가 다르다고 합니다.
프레임이란 애니메이션에서만 쓰이는 단어가 아닙니다.
게임을 좋아한다면 한 번쯤은 FPS를 들어봤을 것입니다. 1인칭 총 게임(First Person Shooter)과 동일한 약어가 존재하기에 헷갈릴 수 있지만 FPS(Frames Per Second)에 대해서 말하는 것입니다.
게임에서의 FPS도 애니메이션과 동일하게 1초 동안 보이는 화면의 수입니다. 그렇다면 프레임도 동일하게 정지된 하나의 화면이겠죠.
위에 화면은 마인크래프트에서 FPS를 확인하는 장면입니다. 이외에도 여러 게임에서 모드나 설정으로 FPS를 확인할 수 있습니다.
출처 : https://docs.unity3d.com/kr/current/Manual/TimeFrameManagement.html
유니티에서는 '제한되지 않는 한' 가능한 가장 빠른 프레임 속도를 제공해 줍니다.
그렇다면 제한되는 경우도 있는 건가요?
베데스다의 옛날 게임의 경우에는 60프레임을 넘어가면 물리엔진에 오류가 생겼습니다.(저는 스카이림에서 아이템이 날아다니는 경험을 한 적이 있었습니다)
물론 모든 게임이 이러한 이유로 프레임 제한을 걸진 않습니다. 위의 적힌 내용처럼 기기의 수명 등의 이유로 프레임의 제한을 거는 경우가 있답니다.
여기서 알아두어야 할 것은 기기에 성능에 따라 가능한 가장 빠른 프레임 속도를 제공하기에 게임의 프레임은 일정하지 않다는 것입니다.
물론 저희가 게임을 플레이하며 한 번쯤은 경험해 봤을 것이기에 이미 알고 있을 내용이지만 앞으로 나올 Update와 연관해서 봐야 하기에 설명했습니다.
출처 : https://docs.unity3d.com/kr/2021.1/Manual/ExecutionOrder.html
유니티에서 Update는 프레임당 한 번 호출됩니다.
프레임을 설명하며 말했듯 프레임은 일정하지 않습니다.
그렇다면 Update에 이동과 관련한 코드를 넣으면 어떻게 될까요?

좋은 기기일수록 프레임이 높을 것이고 프레임이 높다면 Update를 더 자주 호출하기에 같은 시간 동안 더 많이 움직일 것입니다.
만약 멀티플레이 게임이었다면 다음날 서비스 종료가 되겠죠?
그렇다면 어떻게 해야 이러한 사태를 막아주는 걸까요?
출처 : https://docs.unity3d.com/kr/current/Manual/TimeFrameManagement.html
Time.deltaTime이란 마지막 프레임이 완료된 후 경과한 시간을 반환합니다.
Update는 프레임 당 한 번 호출된다는 점을 생각해 보면 Time.deltaTime은 Update의 간격이라고도 볼 수 있습니다.
이러한 점은 실제 계산을 통해서도 알 수 있습니다.
결과를 확인을 해보면 현재 Update의 시간과 이전 Update의 시간의 차이는 Time.deltaTime인 것을 알 수 있습니다.

FPS가 N일 경우 프레임 사이의 시간은 1/N이라고 볼 수 있습니다. 두 수를 곱할 경우 1이 되는 것을 볼 수 있습니다. 그렇다면 초당 프레임 수와 관계없이 동일한 처리가 되는 것입니다.
출처 : https://docs.unity3d.com/kr/current/Manual/ExecutionOrder.html
보통 물리 연산과 관련한 작업은 FixedUpdate를 사용합니다.
그런데 아는 분들은 아시겠지만 FixedUpdate는 고정된 주기로 호출됩니다.
그렇다면 프레임이 일정하지 않은 문제가 없기에 굳이 Time.deltaTime를 곱할 필요가 없지 않을까요?
맞습니다. 공식 문서에서도 곱할 필요가 없다고 적어두었습니다.
하지만 Update에서 쓰이는 단위와 FixedUpdate에서 쓰이는 단위를 일치 시키기 위해서는 Time.deltaTime을 곱해주는 것이 좋다고 생각합니다. (Update와 FixedUpdate에서 N의 값을 쓸 때 Update에서만 Time.deltaTime를 곱해주면 Update에서는 초당 N만큼 갈 것이고 FixedUpdate에서는 N*호출 횟수만큼 갈 것입니다. 그것이 위 예시의 맨 밑의 경우인 것입니다)
출처 : https://docs.unity3d.com/kr/current/ScriptReference/Time-deltaTime.html
참고로 Time.fixedDeltaTime도 존재합니다. 이는 FixedUpdate의 간격입니다. 하지만 굳이 FixedUpdate에서 Time.fixedDeltaTime를 쓸 필요가 없습니다. Time.deltaTime은 FixedUpdate에서 자동으로 Time.fixedDeltaTime를 반환해 줍니다.
코루틴에서는 Time.deltaTime은 무슨 값을 가질까요?
실험을 통해 알아봅시다.
간단한 실험입니다. Update에서의 Time.deltaTime의 값과 코루틴에서의 Time.deltaTime를 출력해주는 것 입니다.
결과는 두 값이 동일하다는 것입니다. 그렇다면 Time.deltaTime은 Update의 값을 반환해주는 걸까요?
WaitForFixedUpdate를 사용하는 경우를 확인해봅시다.
확인 결과 Time.fixedDeltaTime의 값이 나왔습니다.
코루틴이기에 FixedUpdate가 아님에도 Time.fixedDeltaTime의 간격이 나왔기에 저는 이러한 추측을 했습니다.
'Time.deltaTime은 yield return으로 생기는 간격에 맞게 값을 변경해 주는 것 아닐까?'
그렇다면 지금 상황에선 1초를 기다리기에 1이 나오는 게 맞지 않을까요?
추측이 틀렸습니다. Update의 Time.deltaTime하고 동일한 값이 나왔습니다.
지금까지 상황으로 판단할 수 있는 것은 Time.deltaTime의 경우 Time.deltaTime를 반환하는 경우와 Time.fixedDeltaTime를 반환하는 경우로 나뉘는 것 같습니다.
Time.fixedDeltaTime로 반환하는 경우는 공식 문서에는 FixedUpdate에 경우만 적어두었지만 코루틴의 WaitForFixedUpdate의 경우에도 적용되는 것을 보았습니다.
Time.fixedDeltaTime로 반환하는 기준은 무엇일까에 대해서 궁금했습니다.
출처 : https://docs.unity3d.com/kr/current/Manual/ExecutionOrder.html
제 생각에는 스크립트 라이프사이클 플로우차트에서 묶여있는 기준으로 반환하는 값이 바뀌지 않을까 싶었습니다. Physics에 해당하는 곳에서는 Time.deltaTime가 Time.fixedDeltaTime로 반환되는 것이라고 추측한 것입니다.
출처 : https://docs.unity3d.com/kr/current/Manual/ExecutionOrder.html
Update와 동일한 Time.deltaTime를 반환했던 경우도 Update와 같이 묶여있습니다.
출처 : https://docs.unity3d.com/kr/current/Manual/ExecutionOrder.html
물론 코루틴이 Update 함수가 반환된 후 실행되기에 저렇게 묶여있는 것입니다.
Physics에 묶여있는 이벤트 함수는 Time.fixedDeltaTime를 반환한다는 추측이 맞는지 확인하기 위해 Physics에 묶여있는 OnTriggerStay2D를 활용해서 Time.deltaTime를 확인해 보고자 합니다.
확인 결과 Time.fixedDeltaTime의 값을 반환하는 것을 볼 수 있습니다.
Physics에 해당하는 이벤트 함수는 Time.deltaTime를 사용할 때 Time.fixedDeltaTime을 반환받을 수 있다고 추측할 수 있습니다.
원래는 [Unity] 오브젝트의 이동을 작성할 때쯤 구상했던 글입니다.
WaitForFixedUpdate를 사용하자 Time.deltaTime이 Time.fixedDeltaTime의 값으로 반환되는 것을 보고 '과연 코루틴에선 Time.deltaTime이 어떻게 작동할까?'라는 호기심에서 시작한 글입니다.
아직 못 적은 내용이 있지만 하나의 글에 여러 주제를 담으면 중구난방일 거 같아서 이번에는 이 정도로 마무리하고자 합니다.