[Unity] 유니티 생명 주기(Unity Life Cycle)
유니티에서 스크립트는 사전에 지정한 순서대로 여러 개의 이벤트 함수가 실행된다.
이때 이 이벤트 함수들은 MonoBehaviour에 속해 있는 이벤트들이다.
스크립트는 에디터상에서 존재하는 오브젝트에 하나의 컴포넌트로 추가하여 프레임워크를 실행할 수 있는데,
여기서 말하는 프레임워크가 유니티 생명 주기(Unity Life Cycle)가 된다.
MonoBehaviour란?
유니티에서 게임 오브젝트를 제어하기 위해서는 MonoBehaviour라는 클래스를 상속한 스크립트의 컴포넌트를 추가해야만 한다.
MonoBehaviour는 유니티에서 제공되는 기본 클래스로써,
모든 스크립트는 처음 생성 시 default로 Monobehaviour에 파생되어 있다.
그렇기 때문에 여러 이벤트 함수들을 정의하여 사용할 수 있다.
생명 주기 실행 순서
라이프사이클 플로우차트(LifeCycle FlowChart)
플로우 차트에 나와있는 이벤트들의 대부분은 MonoBehaviour를 통해 이벤트 발생 시의 로직을 추가할 수 있고,
그 외의 'Internal animation update'에 속해 있는 이벤트와 같은 경우 StateMachineBehaviour를 통해 추가가 가능하다.
플로우 차트중 회색 바탕으로 이루어진 이벤트들의 경우는 애니메이션을 처리할 때 호출되는 내부 함수이며,
직접 호출할 수 없는 이벤트이다.
또한 위에서 아래로 흐르면서 화살표로 표시된 부분들이 있다.
화살표로 표시된 부분 밑의 이벤트부터 그 다음 화살표로 표시된 부분 위의 이벤트까지 각 오브젝트별로 호출된다.
예를 들어 A와 B의 객체가 있다면 다음과 같은 호출을 가진다.
- A의 Awake, OnEnable 호출
- B의 Awake, OnEnable 호출
- A의 Reset 호출
- B의 Reset 호출
- A의 Start 호출
- B의 Start 호출
- ...
초기화 (Initialization)
유니티 생명 주기에서의 초기화는 3단계에 걸쳐서 이루어지며, 프로그램 시작 시 시작 프레임에서 한 번만 호출된다.
- Awake : 인스턴스화 된 직후에 호출
- OnEnable : 오브젝트 활성화 직후 호출
- Start : 첫 번째 프레임 업데이트 전에 호출
이 3가지의 초기화 함수는 게임 오브젝트가 시작하는 동안 비활성화 상태인 경우 호출되지 않는다.
에디터 (Editor)
- Reset : 오브젝트에 컴포넌트를 처음 연결하거나, Reset 커맨드를 사용할 때 호출된다.
업데이트 (Update)
프로그램이 시작되고 매 프레임마다 혹은 주기적으로 계속 호출되는 이벤트들이다.
- FixedUpdate : 신뢰할 수 있는 타이머를 통해 일정 시간마다 주기적으로 호출
- Update : 한 프레임당 한 번 호출
- LateUpdate : Update가 끝난 이후, 한 프레임당 한 번 호출
FixedUpdate는 다른 Update들과 다르게 일정 시간을 주기로 호출되기 때문에,
프레임 속도에 따라 한 프레임당 여러 번 호출 혹은 한 프레임 사이에 호출되지 않을 수 있다.
물리 (Physics)
OnTrigger, OnCollision 등은 물리적 충돌과 관련 있는 함수들로
Enter, Stay, Exit로 나뉘며 기본적으로 FixedUpdate와 같은 주기로 충돌 검사와 호출이 이루어진다.
입력 이벤트 (Input Events)
OnMouseEnter, Exit, Over, Down 등의 이벤트들은 마우스와 오브젝트가 상호작용하는 함수들로
Update 함수와 비슷하게 매 프레임마다 상호작용을 체크하여 그에 대응하는 함수를 호출한다.
애니메이션 (Animation)
플로우차트에서 애니메이션 업데이트는 Physics와 Game Logic 두 부분에 나타나 있는 것을 알 수 있다.
그 이유는 프레임에 따른 업데이트와 물리 연산이 필요하여 일정 시간에 따른 업데이트로 나누기 때문이다.
- OnStateMachineEnter/Exit : State Machine Update 단계 동안 컨트롤러의 상태 머신이 엔트리/종료 상태를 전환할 때 호출
- Fire Animation Events : 애니메이션 클립에 있는 모든 애니메이션 이벤트들을 호출
- StateMachineBehaviour callbacks : OnStateEnter/Update/Exit, 최대 3개의 활성 상태를 가지며, 각 조건이 만족될 때 정의된 콜백을 호출
- OnAnimatorMove : Update 프레임마다 Animator 정보가 갱신될 시에 호출
- OnStateMove : OnAnimatorMove가 호출된 직후 호출
- OnAnimatorIK : Update 프레임마다 IK 정보가 갱신될 시에 호출
- OnStateIK : OnAnimatorIK가 호출된 직후 호출
여기까진 오버라이딩을 통해 정의가 가능한 이벤트들이며,
이후는 따로 함수를 호출할 수 없고 Unity가 애니메이션을 처리할 때 호출되는 내부 함수이다.
- WriteProperties : 애니메이션을 통해 변경된 프로퍼티를 씬에 적용할 때 호출
- State Machine Update : 애니메이터 모드에 따라 주기적으로 호출
- ProcessGraph : 모든 애니메이션 그래프를 평가할 때 호출
- ProcessAnimation : 애니메이션 그래프의 결과를 블렌딩할 때 호출
- WriteTransforms : 모든 애니메이션화된 트랜스폼을 워커 스레드에서 씬에 작성할 때 호출
상태 머신 평가는 보통 멀티 스레드이지만, 특정 콜백(OnStateMachineEnter, OnStateMachineExit)을 추가하면 멀티스레딩이 비활성화된다.
렌더링 (Rendering)
LateUpdate가 끝난 이후에 호출되는 함수들이다.
- OnPreCull : 카메라가 씬을 컬링하기 전에 호출
- OnBecameVisible/Invisible : 오브젝트가 카메라에 표시되거나/되지 않을 때 호출
- OnWillRenderObject : 오브젝트가 표시되면 각 카메라에 한 번 호출
- OnPreRender : 카메라가 씬 렌더링을 시작하기 전에 호출
- OnRenderObject : 모든 일반 씬 렌더링이 처리된 후 호출
- OnRenderImage : 씬 레더링이 완료된 후 호출
- OnGUI : GUI 이벤트에 따라 프레임당 여러 번 호출
- OnDrawGizmos : 시각화 목적을 위한 기즈모를 그릴 때 호출
코루틴 (Coroutine)
일반적으로 Update 함수가 반환된 이후에 실행되며,
YieldInstruction이 완료될 때까지 다수의 프레임으로 나누어 호출된다.
자세한 설명은 아래 포스팅을 참고하자.
[Unity] Coroutine
Unity에서 Coroutine은 단일 프레임 내에서 작업을 수행하지 않고 다수 프레임에서 작업을 수행할 수 있다.그로 인해 비동기적 처리 방식을 위한 코드를 구현할 때는 Coroutine을 많이 사용하기도 한다
lms0408.tistory.com
- yield WaitForSeconds : 지정한 시간이 지난 후, 모든 Update 함수가 프레임에 호출된 후 계속해서 호출
- yield WaitForFixedUpdate : 모든 FixedUpdate가 모든 스크립트에 호출된 후 계속해서 호출
- yield WWW : www 다운로드가 완료된 후 계속해서 호출
- yield StartCoroutine : 해당 코루틴이 완료되기까지 기다렸다 계속해서 호출
- yield WaitForEndOfFrame : 한 프레임에서 호출되는 모든 이벤트가 끝난 이후 계속해서 호출
일시 정지 (Pausing)
- OnApplicationPause : 프로그램이 일시정지 혹은 재개 될 때 호출
해제 (Decommissioning)
- OnApplicationQuit : 프로그램이 종료될 때 한번 호출
- OnDisable : 오브젝트가 비활성화 혹은 씬이 종료될 때 한번 호출
- OnDestroy : 씬이 종료될 때 한번 호출
반복 구간 (Loop)
유니티 생명 주기 플로우 차트를 보면 부분적으로 반복을 하고있다고 표시한 부분들이 있다.
ex) (FixedUpdate ~ yieldWaitForFixedUpdate), (OnGUI) 등
기본적으로 FixedUpdate부터 OnApplicationQuit까지 한 프레임을 기준으로 이루어진 생명 주기이다.
그러나 한 프레임에 여러 번 혹은 한 번도 호출되지 않는 이벤트의 경우 따로 Loop의 형태로 표시한다.
마무리
코드를 작성하다보면 객체의 초기화 순서에 차이로 오류가 발생하는 경우가 발생한다.
코드를 작성하고 그 흐름을 알기 위해선 생명 주기에 대한 이해는 필수이다.
참고 문서 : https://docs.unity3d.com/kr/2019.4/Manual/ExecutionOrder.html#FirstSceneLoad
: https://docs.unity3d.com/kr/2020.3/Manual/class-MonoBehaviour.html