멈추지 않고 끈질기게

[Unity] Script Lifecycle 본문

Unity

[Unity] Script Lifecycle

sam0308 2022. 12. 16. 12:15

※ 해당 포스팅은 개인의 공부 정리용 글입니다. 틀린 내용이 있다면 추후 수정될 수 있습니다.

※ 해당 포스팅은 Unity 2021.3.15f1 버전을 기준으로 작성되었습니다.

 

 

유니티에서 C# 스크립트 생성 시 기본적으로 MonoBehaviour 클래스를 상속받으며,

유니티의 이벤트 함수들을 동일 이름으로 작성하여 유니티에서 자동으로 호출하도록 할 수 있습니다. 

하기 이미지는 유니티 공식 문서에 등록된 스크립트 라이프사이클의 플로우차트입니다. 

그림 1. Script lifecycle flowchart

(출처 : Unity Documentation)

 

스크립트 작성 시 자주 사용하는 함수들을 호출 순서대로 정리해보겠습니다.

 

Awake()

유니티의 라이프사이클에서 최상단에 위치하는 함수로, 가장 먼저 실행됩니다.

GetComponenet<T>() 함수를 통한 컴포넌트 변수 초기화 등 초기화 로직을 주로 이곳에 작성합니다.ㅇ

 

OnEnable()

해당 오브젝트 활성화 시 호출되는 함수입니다.

이미 씬에 배치된 활성화된 오브젝트라면 씬 로딩 후 Awake() 뒤에 바로 실행됩니다.

게임의 경우 성능 향상을 위해 오브젝트 풀링(Object Pooling)을 많이 사용하기 때문에,

오브젝트의 활성화/비활성화 빈도가 높아 자주 사용됩니다.

 

Start()

반복 호출 사이클에 들어가기 전에 1회 호출되는 함수입니다.

해당 함수 호출 이후에 물리 이벤트 처리, 게임 로직, 렌더링 등의

프레임마다 호출되는 반복 사이클이 시작됩니다.

 

FixedUpdate()

Physics Loop의 매 프레임마다 호출되는 함수입니다. 

중요한 점은 Game Loop의 매 프레임마다 호출되는 Update()와 주기가 다르다는 점입니다.

(GameLoop의 프레임은 순간 성능에 따라 크게 요동칠 수 있지만, Physics Loop는 일정 프레임을 유지) 

따라서 물리 연산에 관한 로직(Rigidbody 등)들은 해당 함수에 작성하는 것이 좋습니다.

 

Update()

Game Loop의 매 프레임마다 호출되는 함수입니다.

오브젝트들의 이동, 회전과 같은 매 프레임마다 부드럽게 실행되어야 하는 함수들과,

플레이어의 입력 대기 등 항상 체크되어야 하는 게임 로직들을 이곳에 작성합니다.

 

LateUpdate()

Update()와 마찬가지로 Game Loop의 매 프레임마다 호출되는 함수입니다.

단, 이름에서 유추할 수 있듯이 Update()보다 나중에 호출됩니다(상기 플로우차트 참고).

매 프레임마다 호출해야 하는 로직 중 Update()에서 갱신된 값을 이용하는 내용을 이곳에 작성하면 용이합니다. 

 

OnDisable()

해당 오브젝트 비활성화 시 호출되는 함수이며, 오브젝트 파괴 시에도 OnDestroy() 보다 먼저 호출됩니다.

게임의 경우 성능 향상을 위해 오브젝트 풀링(Object Pooling)을 많이 사용하기 때문에,

오브젝트의 활성화/비활성화 빈도가 높아 OnDestroy() 보다 자주 사용됩니다.

주로 해당 오브젝트의 활성화 된 이후 변경된 값들을 다시 초기화 하는 로직을 이곳에 작성합니다. 

 

OnDestroy()

해당 오브젝트를 Destroy() 함수 등으로 완전히 파괴했을 시 호출되는 함수입니다.

게임의 경우 성능 향상을 위해 오브젝트 풀링(Object Pooling)을 많이 사용하므로,

완전히 파괴하기 보다는 활성화/비활성화의 빈도가 높아 잘 사용하진 않습니다. 

 

 

유니티의 라이프사이클 순서를 제대로 이해하기 전, 유니티 입문 초기에 겪었던 실수가 있습니다.

public class Test : MonoBehaviour
{
    Rigidbody rigid;

    void Start()
    {
        rigid = GetComponent<Rigidbody>();
    }

    void OnEnable()
    {
        Debug.Log(rigid.velocity);
    }
}

상기 코드와 같이 Start()에서 초기화하는 변수를 OnEnable()에서 접근하였습니다.

결과는 물론 NullReferenceException. 이벤트 함수들의 호출 순서를 잘못 이해해서 발생한 이슈였습니다.

OnEnable() 함수가 처음부터 활성화 되어있는 오브젝트에서, 심지어 Start()보다 먼저 호출되는 점을 몰랐던 것입니다.

로그를 이용하여 Start()와 OnEnable()의 호출 순서를 알게 된 후 유니티 이벤트 함수들의 호출 순서를 검색하여 유니티 공식 문서에서 해당 플로우 차트를 발견하게 되었고, 그제서야 유니티의 이벤트 순서를 제대로 이해하게 되었습니다.

 

역시 무엇이든 기초가 중요한 법인 듯 합니다.