본문 바로가기

Unity/Articles

Unity: 호출하는 스코프에 따라 달라지는 값, Time.deltaTime

유니티 스크립팅은 게임오브젝트에 컴포넌트를 붙이고, 유니티 코어로부터 들어오는 이벤트를 기반으로 동작을 처리하며 행동을 디자인 합니다. 가장 많이 사용되는 예시로는 Awake, Start, Update, FixedUpdate 등이 있는데요. MonoBehaviour 클래스를 상속받고 이 함수를 구현하면, 유니티 코어가 인식하여 해당 함수를 실행시켜 줍니다. 본 아티클에서는 이 함수들 중, Update와 FixedUpdate에 대해서 얘기해 볼까 합니다.

 

Update

Update 함수는 매 프레임 호출됩니다. 게임의 타겟프레임이 60fps라면, 1초에 60번 호출될 것이라고 기대할 수 있습니다. 물론 이 Update 루프에서의 작업이 1초 / 60 의 수치인 0.0166667 초 보다 오래 걸렸다면 1초에 60번 호출 되지 않아 fps가 떨어질 수 있기도 합니다. 매 프레임 복잡도가 다른 작업을 수행하게 될 수도 있습니다. 이번 프레임에 계산했다면, 앞으로의 세 번의 프레임에서 계산을 스킵한다던가 하는 규칙을 생각해 볼 수 있습니다.

 

이처럼 게임의 환경에 따라 이전 Update 루프와 현재 사이의 시간이 달라질 수 있다면, 개발자는 이 수치를 계산에 반영하여 일정한 행동을 하도록 설계해야 합니다. 이런 용도로 사용되는 것이 deltaTime인데요, 이전 프레임으로부터 현재 프레임까지 얼마나 시간이 걸렸는지를 기준으로 시뮬레이션 된 시간 차이 값입니다. 어떤 물체가 A 속력으로 움직이고 있다면 이전 프레임에 비해 현재 프레임은 D 시간만큼 지났으므로 이전 위치보다 A * D 만큼 이동한 위치에 있어야 하는지를 게임 시간을 기준으로 계산할 수 있게 되는 식이죠.

 

Fixed Update

FixedUpdate는 프레임과 관계 없이 호출되는 주기의 함수인데요, 환경이나 게임의 성능에 영향을 받지 않고 일정한 주기로 호출될 것임이 보장되는 함수라 생각하기 쉽습니다. 하지만 이것은 틀렸습니다. 일반적인 환경에서는 무리없이 같은 주기로 함수가 호출 될 것입니다. 그러나 FixedUpdate에서도 부하가 심한 연산이 생길 수도 있죠. FixedUpdate의 기본 스텝 인터벌은 0.02초로 설정되어 1초에 50번 호출됩니다. 그런데 만약 수행해야 할 작업이 0.02를 초과하게 된다면 어떻게 될까요?

 

다음 스텝에 호출될 함수와 문제를 일으킬 것은 자명합니다. 프로젝트 설정에는 Maximum Allowed Timestep이라는 fixed time 관련 옵션이 있습니다. 이 수치는 fixedUpdate가 사용할 수 있는 최대 시간을 의미합니다. 이 수치를 기준으로 다음 FixedUpdate 호출이 수행되지 않을 수 있습니다. 게임의 설계에 따라, fixedUpdate가 생략되는 경우가 치명적이라 판단하여 생략되지 않도록 처리하고 싶을 수도 있습니다. 그런 이유로 fixed Step 시간과 maximum allowed 시간을 동일 하게 맞추면 될까요? 실제로 테스트 해 본다면, 최대 수치를 능가하는 부하가 걸리는 경우 유니티의 게임 타임이 느려집니다.

(유니티 코어 버전에 따라 상이할 수 있습니다.)

 

Delta Time

Update에서 Time.deltaTime을 사용했다면, FixedUpdate에서는 Time.fixedDeltaTime을 사용하면 됩니다. 이 수치는 거의 항상 같은 값을 리턴할 것입니다. fixedUpdate는 같은 주기로 호출될 것이라 기대할 수 있기 때문입니다. 조금 신기했던 부분은, 유니티의 Time.deltaTime getter는 어떤 함수의 스코프에서 사용되었는지에 따라 다른 값을 리턴한다는 점입니다.

 

https://docs.unity3d.com/ScriptReference/Time-deltaTime.html

 

Unity - Scripting API: Time.deltaTime

Success! Thank you for helping us improve the quality of Unity Documentation. Although we cannot accept all submissions, we do read each suggested change from our users and will make updates where applicable. Close

docs.unity3d.com

공식 문서의 본문에서 확인할 수 있듯, FixedUpdate에서 호출되는 경우 Time.fixedDeltaTime으로 동작합니다.

 

 

저는 이 사실을 처음 알게 되었을 때는 그런가 보다 싶었지만, 직접 사용을 하면서 이래저래 경험을 하다보니 조심스럽게 사용해야 하는 기능이라 판단이 되었습니다. FixedUpdate나 Update 양 쪽 모두에서 불리면서 델타타임 수치를 확인해야하는 경우에 설계 의도와 다르게 동작할 수도 있습니다. 만들어진 함수를 사용하는 개발자는 deltaTime을 원할 지 fixedDeltaTime을 원할 지 알 수 없기 때문입니다.

 

'설계자가 분명히 fixedDeltaTime 또는 deltaTime을 명시하여 설계하면 되지 않을까?' 하실 수도 있지만, 항상 fixedDeltaTime 값을 돌려주는 fixedDeltaTime과 다르게 deltaTime은 FixedUpdate 체인에서 호출되는 경우 유니티 코어가 fixedDeltaTime을 돌려줘 버리기 때문에 어느 한 쪽을 사용하는 선택지라는 것이 존재하지 않습니다.

 

유니티 공식문서나 포럼을 조금 찾아보았지만 이 델타 타임 밸류를 가져오는 API에 대해 적절히 분리가 되어있는지 히스토리를 찾지 못했습니다. 여전히 궁금합니다. 무언가 의도가 있어서 편향적인 방식의 값 제공 API를 만든건지, 만들어 놓고 보니 중간에 변경할 수가 없어 그대로 유지하는 것인지...

 

제가 생각하는 API는 3가지 였어야 했습니다.

 

Time::deltaTime

Time::fixedDeltaTime

Time::renderDeltaTime

 

deltaTime은 스코프에 따라 적절한 값을 돌려주고, FixedUpdate 내에서도 참조할 수 있는 렌더링 델타 타임 API가 있어야만 한다고 생각했지만, 유니티는 그렇지 않은 것 같네요. 유니티에게 궁금한 점 중 하나입니다.