작성일 :


게임 개발에 있어서 로직의 흐름을 제어하는 것은 굉장히 중요한 일이다.

Unity 엔진에서는 “Order of Execution for Event Functions” 라는 개념이 있다.

지난 글 Unity 의 Update, FixedUpdate 그리고 LateUpdate - soo:bak 에 이어서,

이번 글에서는 객체의 초기화 및 시작 동작 등과 관련된 메서드 들을 다뤄보고자 한다.


Awake()

Awake() 메서드는 MonoBehavior 에서 제공하는 기본 이벤트 메서드로, 인스턴스 객체가 Load 됐을 때 호출된다.

가장 큰 특징은 인스턴스 객체에 대해서 가장 먼저 호출된다는 점, 그리고 단 한번만 호출된다는 점이다.

OnEnable() 메서드, Start() 메서드보다 먼저 호출되기 때문에 다른 컴포넌트나 리소스에 대한 참조를 설정하는 초기화 로직에 주로 사용된다.


특징

  • Awake() 메서드 내의 로직은 경량화되어야 한다.

    게임의 시작 시점에서 너무 많은 연산이나 처리가 발생하면, 로딩 시간이 길어지게 되며 성능 문제로 이어질 수 있다.

  • 여러 객체에서 Awake()메서드를 호출하는 경우, 호출 순서는 무작위이다.

    따라서, 한 객체에서 다른 객체의 Awake() 메서드가 이미 호출된 상태를 가정해서는 안된다.

    즉, 만약 두 개의 객체가 서로를 참조할 필요가 있는 경우, 둘 중 하나는 Start() 메서드 내에서 참조를 수행하는 것이 더 안전하다.

  • 메모리 관리 문제

    Awake() 메서드에서 리소스 (텍스처, 사운드, 프리팹 등) 를 불러올 때, 해당 리소스들은 적절한 시점에 해제되어야 한다.
    (Destroy(), Resources.UnloadUnusedAssets() 등의 메서드 사용)

    만약, 일시적으로만 필요한 리소스를 Awake() 에서 불러올 경우, 해당 리소스는 게임 동안 계속 메모리에 남게 되므로, 필요 이상의 메모리 사용 문제를 일으킨다.

활용 사례

  • 객체 내의 다른 컴포넌트 참조 설정

    객체에 여러 컴포넌트들이 존재할 경우, Awake() 메서드 내에서 GetComponent<>() 메서드를 통하여 참조를 설정하는 것이 일반적이다.

  • 싱글톤 패턴 구현

    전체 게임 내에서 단 하나의 인스턴스 객체만 유지되어야 하는 객체를 생성할 때, Awake() 메서드 내에서 싱글톤 패턴으로 로직을 처리한다.



OnEnable()

OnEnable() 메서드 또한 MonoBehavior 에서 제공하는 기본 이벤트 메서드로, 인스턴스 객체가 ‘활성화’ 될 때 호출된다.

즉, OnEnable() 메서드는 객체의 활성화 및 비활성화 과정 중에서 중요한 역할을 한다.
(객체의 비활성화 시점에서는 OnDisable() 메서드가 호출된다.)


특징

  • 객체가 활성화된 상태로 씬이 로드되면, OnEnable() 메서드는 Awake() 메서드 다음, Start() 메서드 이전 시점에 호출된다.

    즉, OnEnable() 메서드 내에서 Start() 메서드가 이미 호출된 상태를 가정해서는 안된다.

  • OnEnable() 메서드는 객체가 활성화될 때마다 호출되므로, 무거운 연산이나 긴 시간이 소요되는 로직을 포함시키면 게임 성능에 부정적인 영향을 미친다.

    따라서, OnEnable() 메서드 내의 로직은 간결하게 유지해야 하며, 필요한 처리만 수행하고 불필요한 연산이나 호출은 최소화하도록 신경을 쓰는 것이 중요하다.


활용 사례

  • 이벤트 리스너 등록 및 해제

    이벤트 기반의 프로그래밍에서, OnEnable() 메서드 내에서 이벤트 리스너를 등록하고, OnDisable() 메서드 내에서 해당 리스너를 해제하는 패턴이 자주 사용된다.

    이러한 패턴으로 불필요한 메모리 사용을 줄일 수 있으며, 객체가 비활성화된 상태에서 원치 않는 이벤트 호출을 방지할 수 있다.

  • 게임 상태의 일시적 변화

    특정 객체가 활성화되는 시점에서 게임의 상태나 UI 를 변경해야 하는 경우, OnEnable() 내에서 간단히 해당 로직을 처리할 수 있다.

  • 자원의 동적 로딩 및 해제

    OnEnable() 메서드를 활용해서 객체가 활성화될 때 필요한 리소스를 동적으로 불러오고, OnDisable() 메서드 내에서 해당 리소스를 해제하는 패턴으로 메모리 관리 및 성능 최적화를 하는 방법도 있다.



Start()

Start() 메서드 또한 MonoBehavior 에서 제공하는 기본 이벤트 메서드이며,

객체가 ‘활성화된 후’ Update() 메서드에서의 ‘첫 번째 프레임이 업데이트 되기 전’ 에 한 번만 호출된다.

즉, 어떤 객체가 활성화된 상태로 인스턴스화 되는 상황이라면, Awake() -> OnEnable() -> Start() 순서로 호출되는 것이다.

또한, Awake() 메서드와 마찬가지로 객체에 대해서 한 번만 호출되기 때문에 Start() 메서드 역시 객체의 초기화 작업에 주로 사용된다.


특징

  • Awake() 메서드에서의 초기화 작업과 Start() 메서드에서의 초기화 작업의 비교

    • Awake() 메서드에서는 주로 다음과 같은 초기화를 진행한다.

      • 다른 객체들과 독립적인 초기화 작업
      • 다른 객체들에 의존하지 않는 자체 변수나 컴포넌트의 초기화

      예시

      • 자기 자신의 Rigidbody 컴포넌트 참조, 초기 속도 설정 등
    • Start() 메서드에서는 주로 다음과 같은 초기화를 진행한다.

      • 다른 객체의 Awake() 메서드에서 설정된 값에 의존하는 초기화 작업
      • 다른 객체의 컴포넌트나 변수를 참조해야 하는 초기화

      예시

      • 플레이어 객체의 초기 위치에 따른 카메라 위치 조정 등 다른 객체의 상태나 변수를 기반으로하는 초기화
  • Awake(), OnEnable() 메서드들에서 수행한 초기화를 기반으로 추가적인 작업을 수행하는 것에 적합

  • 게임 로직을 시작하기 전의 마지막 설정 작업에 적합

  • Start() 메서드 내에서의 초기화 작업 중 무거운 연산은 가능한 최소화하거나, 별도로 분산시키는 것이 적합




활용 사례

  • 게임 로직의 초기 설정
    게임 내의 캐릭터, 아이템, 환경 등의 초기 상태 설정 등은 Start() 메서드 내에서 진행하는 것이 적합하다.

    예시

    • 플레이어의 초기 위치 정의
    • 스테이지의 시작 상태 등을 정의
    • 초기 애니메이션 및 사운드 트리거
  • 의존성 설정
    씬 내의 다른 객체에 대한 참조 설정은 Start() 메서드 내에서 진행하여 객체 간의 상호작용이나 데이터 공유 등을 구현할 수 있다.


결론

이렇게 Awake(), OnEnable(), Start() 메서드 모두 객체의 초기 단계에서 다양한 초기화 및 설정 작업을 지원하는 메서드이지만, 각각의 목적이 모두 다르다.

게임의 효율성과 안정성을 높이기 위해 각각의 특징을 잘 이해하고 사용하는 것이 중요하다.