유니티 이벤트 함수 중 Initialization 단계는 두 파트로 나눠지는데, 비록 나뉘어 있지만 크게 보았을 때 역할은 같은 함수들이므로 Initialization 단계의 함수들을 먼저 알아보고 다음 포스트에서 Editor 단계에 대해 알아보자. Initialization 단계에선 단어 그대로 프로그램의 초기화에 유용하게 사용할 수 있는 함수들을 포함한다.
Initialization 단계 두 파트의 차이로는 첫 번째 파트는 씬이 시작되었을 때 즉, 유니티 에디터에서 플레이 버튼을 누르면 가장 먼저 실행되는 Scene load에서 실행되는 단계이고, 두 번째 Initialization 파트는 씬 로드가 끝나고 플레이어가 보는 화면의 첫 번째 프레임이 실행되기 직전에 실행되는 단계이다.
아래는 Initialization 단계의 함수를 구현한 형태이다.
/* Test.cs */
/* 모든 이벤트 함수는 필요하지 않다면(함수 내부가 비어 있다면) 삭제하는 것이 성능적으로 좋다. */
private void Awake()
{
Debug.Log("Awake is executed.");
}
private void OnEnable()
{
Debug.Log("OnEnable is executed.");
}
private void Start()
{
Debug.Log("Start is executed.");
}
씬이 로드된 이후 모든 이벤트 함수를 통틀어 가장 처음에 호출되는 함수이다. 씬의 모든 게임 오브젝트가 초기화된 후 스크립트 컴포넌트의 인스턴스가 생성되면 Awake 함수가 호출된다. 아래 사진과 같이 컴포넌트가 Enable이어도 Awake는 호출된다. 이후 씬이 종료될 때까지 다시는 호출되지 않는다.
씬이 로드된 후 스크립트 컴포넌트가 Enable이 될 때마다 호출되는 함수이다. 따라서 씬이 로드될 때 이미 Enable이라면 Awake 직후에 바로 호출되고, 씬이 로드되는 순간에 컴포넌트가 Disable이 False라면 OnEnable은 호출되지 않는다.
씬 로드 후 스크립트 컴포넌트의 인스턴스가 생기고 활성화 상태일 때 처음 Update를 호출하기 직전에 Start 함수가 호출된다. 즉, Start가 호출된 후부터 Update가 반복된다. Enable일 때만 호출되기 때문에 OnEnable 함수와 실행 조건이 유사해 보이지만 OnEnable 함수는 스크립트가 Enable 상태가 될 때마다 호출되는 반면에 Start는 최초에만 한 번 호출되는 것이 차이라고 구분하면 된다.
이때 유의해야 할 것은 플레이 모드로 진입하는 시점에 비활성화되어 있던 스크립트 컴포넌트 인스턴스가 게임 중간에 활성화 된다면 활성화한 다음 프레임부터 Update가 호출된다는 것이다. 즉, Enable로 만든 다음 프레임에 Start 함수가 호출된다고 볼 수 있다.
이것이 크게 중요하지 않아 보일 수 있지만, Start 함수에서 Coroutine을 실행하는 등의 일부 작업에선 꽤 중요하게 작용할 수 있는 요소이다. 해당 내용은 추후 Coroutine에 대해 다룰 때 조금 더 자세하게 설명할 예정이다.
이처럼 플레이 모드에 진입하는 즉, 씬의 로드와 함께 스크립트 인스턴스가 생성된 이후 Awake - OnEnable - Start 순서로 함수가 호출되는 것을 확인할 수 있다. 이때 Test 스크립트 인스턴스가 활성화되어 있는 것을 볼 수 있는데, 그렇지 않다면 아래와 같이 컴포넌트가 최초로 활성화된 직후 프레임의 Update가 호출되기 전에 Start가 호출된다.
일반적으로 Initialization 단계의 함수들은 초기화에 이용한다고 하였다. 기본적인 프로그래밍을 위한 변수, 객체를 포함하여 게임 플레이에 사용될 다른 게임 오브젝트와 컴포넌트 등을 사용할 때마다 Find 함수나 GetComponent 함수를 호출하여 사용하는 것보다 초기에 미리 변수를 생성해놓고 캐싱하여 사용하는 것이 성능에 도움을 준다. 이러한 캐싱도 주로 Awake나 Start와 같은 이벤트 함수를 이용한다.
처음엔 Awake를 사용하든 Start를 사용하든 별다른 차이를 느끼지 못하므로 한 함수에 몰아서 초기화를 해줄 수도 있지만, 각 스크립트 인스턴스의 Awake 실행 순서는 랜덤하다는 것을 고려할 필요가 있다.
필자의 경우 기본적인 변수 초기화와 캐싱은 Awake에서 진행하고 캐싱해놓은 컴포넌트 변수를 활용하여 초기화가 필요한 경우 Start에 코드를 포함하고 있다. 캐싱한 스크립트 인스턴스의 초기화가 제대로 이루어지지 않았는데 해당 인스턴스를 사용하려고 할 때 원하지 않은 상황이 발생하는 것을 예방하기 위함이다.
쉽게 정리하자면 스크립트 간의 참조 관계는 Awake에서, 스크립트 간의 정보 공유는 Start에서 해주는 것이 바람직하다.