[Unity] MonoBehaviour와 라이프 사이클

요구르트·2025년 4월 25일

Unity

목록 보기
6/7

유니티에서 스크립트를 새로 만들면 아래와 같이 생성될 겁니다.

using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

처음 스크립트를 만들면, Start와 Update라는 함수가 기본적으로 생성되어 있습니다.
이번 포스트에서는 Monobehaviour와 Start/Update, 추가로 기본적인 유니티 내부 이벤트에 대해 작성해 보도록 하겠습니다.

MonoBehaviour

MonoBehaviour는 에디터에서 게임 오브젝트에 스크립트를 연결할 수 있는 프레임워크를 제공하고, Start 및 Update 등과 같은 이벤트에 대한 연결을 제공하는 클래스입니다. (참고 자료)

위 코드에서 봤듯이, 유니티 내에서 스크립트를 새로 생성하면 기본적으로 상속되어 있습니다.

Unity 6의 경우에는 Create>Scripting>MonoBehaviour Script를 선택하거나, Create>MonoBehaviour Script를 선택하여 MonoBehaviour가 상속된 스크립트를 생성할 수 있습니다.

1. 생명 주기 메서드

생명 주기 메서드는 아까 말한 Start와 Update같은 메서드들을 말합니다.
이 외에도 다양한 메서드가 있어 하나씩 간단하게 설명해 보도록 하겠습니다.

Awake - 가장 먼저 호출됨. 비활성화 오브젝트에도 실행됨.
Start - Awake보다 늦게 호출됨. 한 번만 실행함.
OnEnable - 오브젝트가 활성화 될 때마다 호출됨.
OnDisable - 오브젝트가 비활성화 될 때마다 호출됨.
OnDestroy - 오브젝트가 삭제될 때 호출됨.

FixedUpdate - 고정된 시간 간격마다 호출됨. 물리 연산에서 사용함.
Update - 매 프레임마다 호출됨.
LateUpdate - 모든 Update 후에 호출됨. 카메라 따라가기 기능을 만들 때 사용함.

// OnMouse~는 collider가 필요합니다.
OnMouseDown - 마우스를 클릭했을 때 호출됨.
OnMouseUp - 마우스 클릭을 뗐을 때 호출됨.
OnMouseEnter - 마우스가 오브젝트에 들어왔을 때 호출됨.
OnMouseExit - 마우스가 오브젝트에게서 벗어났을 때 호출됨.
OnMouseOver - 마우스가 오브젝트 안에 있을 때마다 호출됨.
OnMouseDrag - 마우스가 오브젝트를 드래그하고 있을 때마다 호출됨.

// OnTrigger~는 Collider가 필요하며, Collider>isTrigger를 켜야 합니다.
OnTriggerEnter - 트리거 콜라이더에 진입했을 때 호출됨.
OnTriggerStay - 트리거 콜라이더에 닿았을 때마다 호출됨.
OnTriggerExit - 트리거 콜라이더에게서 벗어났을 때 호출됨.
OnCollisionEnter - 콜라이더 충돌에 진입했을 때 호출됨.
OnCollisionStay - 콜라이더와 충돌 중일 때마다 호출됨.
OnCollisionExit - 콜라이더 충돌이 종료됐을 때 호출됨.

StartCoroutine - 코루틴 실행
StopCoroutine - 특정 코루틴 중지
StopAllCoroutines - 모든 코루틴 중지

OnApplicationQuit - 애플리케이션 종료 직전에 호출됨.
OnApplicationPause - 애플리케이션이 일시정지/재게했을 때 호출됨.
OnApplicationFocus - 애플리케이션의 포커스를 받을 때/잃을 때 호출됨.

이 외에도 엄청나게 종류가 많지만, 주로 사용하는 메서드를 모아봤습니다.
아래 사진은 각 함수들간의 호출 주기를 표현한 사진이며, 사진 밑에는 헷갈릴 수 있는 메서드의 자세한 설명을 작성하였습니다.

1.1 Awake와 Start, Enable의 차이?

Awake와 Start는 처음 실행하였을 때 딱 한번 호출된다는 공통적인 특징을 가지고 있으며, Enable은 오브젝트가 활성화 될 때마다 호출됩니다.
각 메서드의 차이점은 어떤 것이 있으며, 언제 쓰는 게 좋은지 알아보도록 합시다.

1.1.1 호출 위치

위에서도 간단히 언급했듯이, Awake는 제일 먼저 호출되는 메서드입니다. Start는 Awake, OnEnable이 호출된 다음 호출됩니다.
사진으로 보면 다음과 같습니다.

사진에 보면 Awake가 1등, OnEnable이 2등, Start가 그 다음입니다. (Reset은 에디터용)
따라서 먼저 세팅해줘야 할 것은 Awake에, 다 세팅이 된 이후에 세팅해 줘야 할 것은 Start 메서드에 작성해 주시면 됩니다.

1.1.2 스크립트 활성화 여부

유니티 내에서는 스크립트의 활성화 여부를 변경할 수 있습니다. Awake는 스크립트 활성화 여부와 관계 없이 씬이 로드될 때 호출되며, Start와 Enable의 경우에는 스크립트가 활성화 되어있을 때에만 호출됩니다.
아래 사진은 유니티 Inspector 화면의 일부입니다.

여기서 체크를 꺼주게 되면 스크립트가 비활성화됩니다. 그러나 오브젝트를 비활성화 되었을 경우에는 Awake가 실행되지 않습니다. 또한 오브젝트를 비활성화 한 후 다시 활성화해도, Awake가 실행되지 않는다는 점도 알고계시면 좋을 것 같습니다.

1.1.3 결론

Awake는 내부를 세팅해야 할 때,
Start는 내부 세팅이 끝난 후에 호출해야 하는 상황일 때 (외부 호출을 해야할 때),
OnEnable은 UI 등 활성화 할 때마다 다시 해야 할 일이 있을 때 사용하면 됩니다.

1.2 FixedUpdate/Update/LateUpdate의 차이?

Update는 총 종류가 세 가지 있습니다. 고정된 간격마다 호출되는 FixedUpdate, 1프레임마다 호출되는 Update, 모든 Update가 호출된 후 호출되는 LateUpdate가 있습니다.
각 메서드마다의 차이점을 알아보도록 합시다.

1.2.1 호출 위치

Update들은 Fixed->Update->Late 순으로 호출됩니다.
사진으로 보면 다음과 같습니다.

FixedUpdate는 물리 처리 구간에서 맨 처음 실행되며, Update와 LateUpdate는 GameLogic의 시작/끝에서 실행됩니다.

1.2.2 호출 주기

Update와 LateUpdate는 매 프레임마다 호출됩니다. 그렇다면 FixedUpdate의 경우에는 언제 호출이 되는 걸까요?
정답은 저희가 정할 수 있습니다. 유니티 내에서 FixedUpdate의 주기를 설정할 수 있습니다.
아래 사진은 유니티 상단 바에 있는 Edit>Project Settings>Time 항목입니다.

Fixed Timestep을 수정하면 FixedUpdate의 주기를 바꿀 수 있습니다. 기본 값은 0.02이며, 최대 값은 10, 최소 값은 0.0001입니다.
값을 수정할 경우, 아래 값들도 변경될 수 있으니 신중히 변경하시길 바랍니다.

1.2.3 결론

FixedUpdate는 플레이어같은 물리적 연산이 필요할 때,
Update는 키보드/마우스 입력 등 인풋 등을 처리할 때,
LateUpdate는 플레이어를 따라오는 카메라처럼 무언가를 따라가는 기능을 만들 때 사용하면 됩니다.

1.3 OnTrigger~와 OnCollision의 차이?

유니티 내에 있는 콜라이더들은 isTrigger라는 변수를 포함하고 있습니다.

이 isTrigger를 켰을 때에는(true) OnTrigger가, isTrigger를 껐을 때에는(false) OnCollision이 실행된다고 보시면 됩니다.

1.3.1 OnCollision

OnCollision은 콜라이더끼리 서로 통과하지 않고, 딱 부딪히기만 합니다. 게임으로 예를 들면, 플레이어가 바닥 밑으로 들어가지 않고 바닥 위에 서있는 것 처럼 충돌하는 것처럼요.
주로 플레이어-바닥 사이의 관계처럼 서로 통과하면 안되는 오브젝트는 isTrigger를 false로 해줍니다.

1.3.2 OnTrigger

OnTrigger는 콜라이더끼리 서로 통과할 수 있습니다. 주로 2D상에서 플레이어-아이템 사이의 관계처럼 서로 간섭할 수 없는 오브젝트는 isTrigger를 true로 해줍니다.

1.3.3 Collider와 Rigidbody의 관계

OnTrigger~ 이벤트와 OnCollision~ 이벤트가 정상적으로 작동하기 위해선, 충돌하는 오브젝트들 중 하나는 Rigidbody 컴포넌트가 들어가 있어야 합니다.

Rigidbody를 간단하게 설명하자면, 물리적인 상호작용을 가능하게 하는 컴포넌트라고 생각하시면 됩니다. 중력이나 충돌, 힘 같은 물리 법칙을 적용하게 해줍니다.
가능하다면 Rigidbody에 관한 포스트도 작성해 보도록 하겠습니다.

1.4 오브젝트간의 Awake 호출 순서?

이제 각 메서드간의 호출 주기는 대충 감이 잡히셨을 겁니다.
그렇다면 만약 두 오브젝트에서 어떤 오브젝트가 먼저 Awake, Start, Update 등이 호출될까요?

정답은 "랜덤"입니다. 누가 호출될지 저희는 예측할 수 없습니다. Awake에서 외부 호출을 하면 안되는 이유가 바로 이것 때문이죠.

아래는 예제 코드입니다.

public class PlayerScript : MonoBehaviour
{
    public RigidScript anotherScript;

    void Awake()
    {
        anotherScript.AddForce();
    }
}

public class RigidScript : MonoBehaviour
{
    private Rigidbody2D rigidCompo;
    private void Awake()
    {
        rigidCompo = GetComponent<Rigidbody2D>();
    }
    public void AddForce()
        => rigidCompo.AddForceY(5f, ForceMode2D.Impulse);
}

위 스크립트를 보면, PlayerScript라는 스크립트에서 RigidScript의 AddForce 메서드를 Awake 메서드에서 호출하고 있습니다.
그리고 RigidScript 또한 Awake에서 rigidCompo를 할당해 주고 있죠.

여기서 문제가 되는 점은, Awake의 호출이 랜덤이기 때문에 PlayerScript에서 에러가 날 수 있다는 것입니다.
왜냐하면 PlayerScript에서 AddForce를 호출할 때, rigidCompo가 아직 Awake에서 할당이 되어있지 않을 수도 있기 때문입니다.
따라서 Awake가 모두 끝난 후인 Start 메서드에서 외부 호출을 해야 하는 이유입니다.

단, 스크립트의 순서를 바꿀 수 있는 방법이 2가지 존재합니다.

먼저, Project Settings에서 스크립트의 순서를 바꾸는 방법이 있습니다.

위 사진을 보시면 스크립트 옆에 -1000, -110 등 숫자가 여러개 있을 겁니다.
기본적으로 모든 스크립트는 0에서 시작되며, 숫자가 작아질수록 "이 스크립트를 빨리 실행하겠다"라고 설정할 수 있습니다.
아래 플러스를 눌러 스크립트를 선택하고, 숫자를 변경하면 스크립트의 순서를 변경할 수 있습니다.

두번째로는, 위 사진에서 했던 것을 코드 상에서 바꾸는 방법이 있습니다.

[DefaultExecutionOrder(-1000)]
public class Player : MonoBehaviour
{
	// Do Something...
}

바로 클래스 위에 [DefaultExecutionOrder()]를 작성해 주는 겁니다.
기본적인 내용은 위와 같으며, 소괄호 안에는 위에 있던 -1000, -110 등 숫자를 적어주시면 됩니다.

하지만 이것은 코드에서 바로 바꿔주는 것이기 때문에 성능이 그리 좋지는 않습니다. 되도록이면 Project Settings에서 수정하시는 것을 권장드립니다.

결론

유니티 상에서 생명 주기 메서드는 상당히 중요합니다. 이에 대한 지식을 접하지 않고 처음에 코드를 짜다보면 NullReference라는 에러가 자주 나는 것을 알 수 있습니다. 공식 문서를 참고하시면 유니티 생명 주기 메서드에 좀 더 세부적인 정보를 확인할 수 있으니 관심이 있으신 분들은 아래 링크를 참고해 주세요.
https://docs.unity3d.com/kr/2019.4/Manual/ExecutionOrder.html

다음 유니티 포스트에서는 유니티의 TimeScale에 대해 작성해 보도록 하겠습니다.

profile
경기게임마이스터고 4기

0개의 댓글