[Unity] 유니티 생명주기란?

kj0284
WeKlem
Published in
9 min readJun 15, 2023

--

안녕하세요 위클램의 박경준매니저입니다.

오늘은 유니티 생명주기에 대해 알아보겠습니다.

유니티생명주기란?

저희가 유니티로 게임을 만든다고 가정해봅시다.

게임을 만들 때에는 캐릭터, 몬스터, 장애물, 무기 등 여러가지 구성요소들이 있는데 이를 유니티에선 오브젝트(객체)로 구성되어있습니다.

게임이 진행되는 흐름, 그리고 그 흐름에 따라 오브젝트들이 할 역할들을 정해주는 것들을 유니티 생명주기라고 생각하면 되겠습니다.

객체 : 속성값과 행동을 가지고 있는 데이터
ex) 캐릭터 = [hp, mp, 능력치, 스킬], 무기 = [사거리, 내구도, 공격력]

여러 객체의 예시) 광원 오브젝트(왼쪽), 솔리드 큐브 오브젝트(오른쪽)

tip : 유니티에서의 객체는 코드에서 말하는 객체와는 다르므로 헷갈리지 않게 조심합시다!

먼저 Monobehavior란?

Monobehavior란 캐릭터, 몬스터, 장애물, 무기 등과 같은 오브젝트들이 있을 때 오브젝트들이 공통적으로 가지고있는 부모님이라 생각하면 되겠습니다.

보통 부모님들은 자식들에게 일을 시키듯이 Monobehavior가 모든 자식들에게 “~~해라”라는 명령(메세지)을 합니다. 그러면 자식들은 부모님이 시킨 일을 하겠죠?

Unity에서 이를 대입해보면 Monobehavior라는 부모님은 자식들 전체에게 명령을 내립니다. 이를 들은 자식들 중에 할 일이 있는 자식들은 일을 해야하겠죠. 아래 그림을 봅시다.

위 내용을 좀 더 개발자적인 말로 풀이하자면

Monobehavior라는 상위 클래스가 Update라는 함수를 Broadcasting으로 보내면 하위 클래스들은 Update 함수 메세지를 받아 각자의 클래스에 정의된 Update함수를 호출합니다.

(메세지로 받은 함수가 오브젝트 내에 없을 경우 실행하지 않습니다.)

Broadcasting : 보낸 사림이 전송한 데이터가 연결된 모두에게 전송되는 방식

생명주기 왜 알아야할까?

무엇이든 왜 공부해야하는지는 중요하죠.

결국 유니티는 스크립트라는 소스 파일을 통해 오브젝트들의 액션들을 시각화해서 보여주는 것이 주 목적이에요.

생명주기를 알고 적절한 생명주기에 내가 원하는 기능들을 넣으면 에러 발생 가능성을 줄이고 리소스(메모리)가 덜 드는 방향으로 개발을 할 수 있어요.

제대로 알아봅시다.

아래 그림은 Unity docs에 있는 유니티의 삶의 로드맵(Life Cycle)입니다.

출처 : https://docs.unity3d.com/kr/2021.3/Manual/ExecutionOrder.html

전체적인 흐름을 보면 크게

“시작 — 업데이트 — 삭제 및 종료” 이루어져있고 각 주기들은.

  • 시작 : Awake, Onenable, start
  • 업데이트 : FixedUpdate, Update, LateUpdate
  • 삭제 및 종료 : OnDisable, OnDesrtoy

와 같은 주요함수들과 세부적인 함수들이 있습니다.

위 플로우 차트를 제가 이해한대로 정리하면 다음과 같습니다.

구체적으로 각 주기의 함수들이 무슨 상황에 호출되는지 알아봅시다.

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

Editor

Reset

에디터에서 동작하는 방식으로 오브젝트를 생성 후 리셋버튼을 눌러줄 때 실행됩니다.

즉, 객체의 값을 초기화해줄 때 주로 사용됩니다.

public class Me : MonoBehaviour
{
public int hp;
public int mp;
void Reset() {
hp = 10;
mp = 20;
}
}

위 코드에선 리셋버튼을 누를 때마다 hp, mp 변수가 설정한 값으로 초기화가 됩니다.

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

Initialization

Awake : 스크립트가 실행될 때 한번만 호출되는 함수

Awake는 Start보다 먼저 실행되기에 초기화 순서를 고려해줄 수 있으며, 오브젝트가 비활성화 상태로 생성되더라도 호출되기 때문에 Start와 구분됩니다.

private void Awake() {
//초기화
}

OnEnable : 스크립트가 활성화되어 있고, 오브젝트가 활성화될 때마다 호출되는 함수

private void OnEnable() {
//오브젝트가 활성화 될 때마다 호출
}

Awake, OnEnable 함수는 씬이 시작되면 씬의 오브젝트에 대해서 한 번씩 호출됩니다.

Start : 초기화 단계에서 가작 마지막에 호출되는 함수

private void Start() {
//1프레임이 시작되기 전에 호출
}

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

Physics

FixedUpdates : 일정한 주기로 호출되는 Update형식의 함수

일정한 주기의 디폴트는 0.02초이지만 프로젝트 세팅에서 수정이 가능합니다.

물리 계산을 위해 주로 사용되며 물리계산이 달라지면 안되기 때문에 별도의 Timer를 사용합니다,

→ Update 함수와는 독립된 기능을 수행합니다.

OnTrigger 함수 & OnCollision 함수

충돌된 순간, 충돌 중, 충돌 후를 구분하여 함수들의 기능을 넣어줄 수 있습니다.

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

Input Event

OnMouse 함수 : 마우스 입력으로 호출되는 함수.

마우스를 눌렀을 때, 눌렀다가 땠을 때, 마우스를 누르고 있을 때 호출됩니다.

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

Gamelogic

Update 함수 : 스크립트가 활성화 되어 있을 때 프레임마다 호출

실질적인 게임 로직처리를 이 함수에서 하게 됩니다.

⇒ 환경에 따라 성능차이로 프레임이 오차가 있을 수 있기 때문에 물리적인 부분은 FixedUpdate에서 따로 수행합니다.

private void Update(){
//프레임 당 실행할 로직
}

코루틴을 사용하는 방법도 있습니다.

코루틴(Coroutine) : 실행을 일시정지하고 제어권을 유니티에 넘겼다가 다음 프레임에 정지했던 지점부터 다시 코드를 실행할 수 있는 메서드

⇒ HTTP전송, asset 로딩 같은 완료될 때까지 기다려야하는 긴 비동기 작업을 처리해야하는 경우 코루틴을 사용하는 것이 좋습니다.

  • yield Null : Update 함수가 호출된 후 실행되며 코루틴 함수에서 한 프레임을 대기할 때 사용
  • yield WaitForSeconds : Update함수가 호출된 후 지정된 시간 만큼 지연 후 실행
  • yield WWW : www를 이용하여 다운로두 후 실행
  • yield StartCoroutine : 해당 코루틴을 실행하고 완료까지 대기

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

LateUpdate 함수 : Update 함수를 실행한 후 프레임마다 호출

오브젝트를 따라가는 카메라의 경우 오브젝트를 추적할 수 있도록 LateUpdate에서 실행하는 것이 유용합니다.

private void LateUpdate() {
}

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

Scene Rendering

  • OnPreCull: 카메라가 씬에 어떤 오브젝트를 카메라에 표시할지 결정(컬링)하기 직전에 호출
  • OnBecameVisible/OnBecameInvisible: 오브젝트가 카메라에 표시되거나/표시되지 않을 때 호출
  • OnWillRenderObject: 오브젝트가 표시되면 각 카메라에 한 번 호출
  • OnPreRender: 카메라가 씬 렌더링을 시작하기 전에 호출
  • OnRenderObject: 모든 일반 씬 렌더링이 처리된 후 호출
  • OnPostRender: 카메라가 씬 렌더링을 마친 후 호출
  • OnRenderImage: 씬 렌더링이 완료된 후 호출되어 이미지의 포스트 프로세싱이 가능

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

Gizmo Rendering

OnDrawGizmos 함수 : 씬 뷰에 기즈모를 그리는 함수

기즈모란? 개발에 필요한 정보를 시각적으로 노출시켜 개발을 용이하게 함

기즈모의 example

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

GUI Rendering

OnGUI 함수: 설정된 GUI이벤트를 따라서 프레임마다 호출

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

End of Frame

yield WaitForEndOfFrame: 하나의 프레임이 완전히 종료가 되면 호출

  • Update, 렌더링이 끝나면 호출됩니다.

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

Decommissioning

OnApplicationQuit : 해당 어플리케이션이 종료될 경우 호출

OnDisable : 오브젝트가 비활성화되었을 경우 호출

Pausing 단계에서 비활성화 되었을 경우에도 호출됩니다.

OnDestroy : 오브젝트가 파괴되는 경우 호출

마무리

다시 유니티 생명주기가 왜 중요한지에 대해 복기하고 갑시다.

제가 생각하는 유니티의 생명주기를 알아야하는 이유는 크게 두 가지입니다.

  1. 내가 원하는 시기에 화면(씬)을 전환하거나, 오브젝트들의 기능을 개발할 수 있다.
  2. 생명주기에 맞는 개발을 통해 리소스를 절약해 쾌적한 사용자 경험을 제공할 수 있다.

물론 처음엔 이해하기 어렵겠지만 개발하면서 참고하면 더 효율적인 개발에 도움이 되지 않을까라고 생각합니다.

이상으로 유니티 생명 주기에 관한 포스팅을 마치겠습니다

다들 LGTM(Looks Good To Me)하길 바래요🙂

--

--