유니티의 이벤트 함수 중 가장 빈번하게 사용되는 Update 계열의 함수들에 대해 알아보자. 해당 스크립트 컴포넌트가 활성화되어있는 동안 주기적으로 반복 실행되는 Update 계열의 함수는 그 종류에 따라 반복되는 주기, 시기가 모두 다르다.
매 프레임 호출되는 기본적인 Update 함수로, 프레임마다 전체 시스템에서 수행되는 작업의 양이 매번 다르므로 Update가 호출되는 주기가 일정하지 않다.
Update에서 직전 프레임이 완료되는 데까지 걸린 시간 즉, 현재 프레임과 이번 프레임 사이 시간을 반환하는 Time.deltaTime을 출력하면 다음과 같이 매 프레임 사이 시간이 일정하지 않다는 것을 확인할 수 있다.
매 함수 호출 간격이 다른 Update와 달리 FixedUpdate는 함수 호출 간격이 일정하도록 보장된다. 따라서 매번 일정한 주기로 똑같은 연산을 처리해야 하는 물리 계산 및 업데이트, 또는 Ray 처리에 주로 사용되는 함수이다. Rigidbody 컴포넌트를 활용하는 코드의 실행은 FixedUpdate에서 이루어지는 것이 더 정확한 물리 계산이 가능하다. FixedUpdate 함수 자체도 Unity script lifecycle flowchart의 Physics 영역에 속한 것을 확인할 수 있다.
물리 계산에 유리하다는 특성은 FixedUpdate의 호출 간격이 일정하다는 것 덕분인데, 이는 Update가 매 프레임 실행되던 것에 비해 FixedUpdate는 프레임 속도에 관계없이 Fixed Timestep이라는 정해진 시간 간격에 따라 호출되기 때문이다. 상단 Edit 탭을 클릭하여 Project Settings의 Time에서 현재 프로젝트의 Fixed Timestep이 몇 초로 설정되어 있는지 확인할 수 있다.
Fixed Timestep은 임의로 변경할 수 있지만, 너무 작은 수치로 설정했을 때 과도하게 자주 호출되어 성능의 저하를 초래할 수 있는 점을 고려하여 적당한 시간을 설정하는 것이 중요하다. 기본값인 0.02로 설정해도 큰 문제는 없다.
따라서 FixedUpdate는 실행하는 환경의 프레임 속도가 낮을 경우 한 프레임에서 여러 번 호출되기도, 프레임 속도가 높을 경우 한 프레임 안에 아예 호출되지 않을 수도 있다.
이러한 FixedUpdate에서 Time.deltaTime을 호출하려 하면 프레임 사이 시간이 아닌 Fixed Timestep을 반환하는 것에 유의하자. 실제로 실행한 결과는 아래와 같다.
실제로 다음과 같이 활용할 수 있다.
/* PlayerController.cs */
void Move() // 필요한 내용만을 남기고 다른 코드는 삭제했다. 애니메이션 등에 대한 코드도 실제로는 추가돼있다.
{
Vector2 dirVec = new Vector2(hAxis, vAxis);
transform.Translate(dirVec * Time.deltaTime * playerStat.moveSpeed);
}
private void Update()
{
Move();
}
위처럼 캐릭터의 움직임을 구현하는 Move라는 함수를 만들었고, 이를 Update 함수에 구현하면 언뜻 보기엔 이상이 없는 것처럼 보이지만, 벽에 맞닿았을 때 해당 방향으로 계속 이동하려고 하면 충돌 처리가 주기적으로 이루어지지 않아 아래와 같이 떨림 현상이 발생한다.
충돌은 Rigidbody 컴포넌트에 의해 발생한다. 비록 이동 자체는 Transform 컴포넌트의 함수를 이용했지만, 충돌(물리적 요소)에서 비정상적인 현상이 발생하는 것이므로 FixedUpdate를 이용하였을 때 해결이 될 수 있으리라 기대할 수 있는 상황이다.
따라서 다음과 같이 FixedUpdate에 코드를 옮기고 실행해보았다.
/* PlayerController.cs */
...
private void FixedUpdate()
{
Move();
}
이와 같이 충돌이 정상적으로 일어나 떨림 현상이 해결된 것을 확인할 수 있다.
Update가 완전히 끝난 후 프레임당 한 번 호출되는 함수로, Update가 마무리된 후에 호출되기 때문에 3인칭 카메라에 주로 사용된다. 플레이어의 움직임을 Update에서 완료하고 이동한 위치에 따라 카메라의 위치를 LateUpdate에서 이동하는 식으로 구현할 때 사용된다.