Unity Term Book
스크립팅 & 라이프사이클

MonoBehaviour

MonoBehaviour는 모든 Unity 스크립트의 베이스 클래스로 라이프사이클 훅과 Component 접근을 제공합니다. Awake·Start·Update·FixedUpdate·OnDestroy와 빈 Update 비용·AddComponent 규칙을 배우는 입문 가이드입니다.

상상해 보세요...

MonoBehaviour는 Unity와의 고용 계약과 같습니다. 서명(상속)하면 직원(스크립트)이 자동으로 정해진 회의에 초대됩니다: 킥오프(Awake), 첫날(Start), 일일 스탠드업(Update), 물리 동기화(FixedUpdate), 퇴사 면담(OnDestroy). 상속이 없으면 메서드를 정의해도 호출되지 않습니다.

개념 자세히

MonoBehaviourBehaviour → Component → Object를 상속합니다. 이 상속 덕분에 Unity가 reflection으로 magic methods(Awake, Start, Update…)를 호출합니다——override하거나 base를 호출하지 않습니다.

핵심 라이프사이클: Awake는 객체가 생성되면 즉시(비활성이어도), Start는 활성화된 뒤 첫 프레임, Update는 매 프레임, FixedUpdate는 Physics 타임스텝 (기본 0.02초)입니다.

성능:Update()도 reflection 호출 비용이 있습니다. 빈 Update는 삭제하세요. 객체 전체를 파괴하는 대신 enabled = false로 라이프사이클을 일시 정지하세요.

제한: 생성자( new MyScript())를 쓸 수 없습니다——AddComponent<T>()를 쓰세요. 스레드 세이프가 아닙니다——MonoBehaviour API는 메인 스레드에서만 동작합니다.

다이어그램: 상속 체인 & magic methods

Object
Component
Behaviour
MonoBehaviour
YourScript

Awake()

내부 초기화 · Start 이전

Start()

초기 설정 · 첫 프레임

Update()

매 프레임 로직 · Input, AI...

FixedUpdate()

Physics · 0.02초마다

LateUpdate()

모든 Update 이후 · Camera follow

OnEnable()

오브젝트가 활성화될 때

OnDisable()

오브젝트가 비활성화될 때

OnDestroy()

오브젝트가 파괴될 때

실습 단계

1

새 C# 스크립트 만들기

Assets → Create → C# Script. 컴파일 오류를 피하려면 파일명과 클래스명을 맞추세요.

2

내부 설정은 Awake

컴포넌트 참조 캐시(_rb = GetComponent<Rigidbody>())는 Awake. 여기서 다른 객체에 의존하지 마세요.

3

객체 간 설정은 Start

다른 객체가 필요할 때 Start(그들의 Awake는 이미 끝남).

4

Update vs FixedUpdate 분리

입력·AI → Update. 물리 힘(AddForce, velocity) → FixedUpdate로 글리치 방지.

5

OnDestroy에서 정리

OnDestroy에서 이벤트 구독 해제, Coroutine/타이머 정지로 누수 방지.

인터랙티브 시뮬레이터

Play Scene을 눌러 라이프사이클 메서드가 순서대로 호출되는 모습을 보세요. Disable·Destroy로 다음 단계도 시험하세요.

Lifecycle Timeline

Console

Play를 눌러 시작...

Frame: |State: Inactive|Play 대기 중...

코드 예제

기본

표준 MonoBehaviour 레이아웃과 각 라이프사이클 메서드의 역할.

using UnityEngine;

public class PlayerController : MonoBehaviour
{
  [SerializeField] private float speed = 5f;
  private Rigidbody _rb;
  private Vector3   _inputDir;

  void Awake()
  {
      // Cache component — no dependency on other scripts
      _rb = GetComponent<Rigidbody>();
  }

  void Start()
  {
      // Setup that needs GameManager.Awake to have finished
      GameManager.Instance.RegisterPlayer(this);
  }

  void Update()
  {
      // Read input every frame
      float h = Input.GetAxisRaw("Horizontal");
      float v = Input.GetAxisRaw("Vertical");
      _inputDir = new Vector3(h, 0, v).normalized;
  }

  void FixedUpdate()
  {
      // Physics move — do not use Time.deltaTime here
      _rb.MovePosition(_rb.position + _inputDir * speed * Time.fixedDeltaTime);
  }

  void OnDestroy()
  {
      GameManager.Instance.UnregisterPlayer(this);
  }
}

코드 예제

고급

최적화: 빈 Update 피하기; 이벤트 구독은 OnEnable/OnDisable.

using UnityEngine;
using System;

// Full lifecycle component — pairs well with an event system
public class HealthComponent : MonoBehaviour
{
  [SerializeField] private int maxHp = 100;
  private int _currentHp;

  public event Action<int,int> OnHealthChanged;  // (current, max)
  public event Action           OnDied;

  void Awake() => _currentHp = maxHp;

  void OnEnable()
  {
      // Subscribe when the component becomes active
      GameEvents.OnDamageDealt += TakeDamage;
  }

  void OnDisable()
  {
      // Unsubscribe immediately — avoid calls while disabled
      GameEvents.OnDamageDealt -= TakeDamage;
  }

  public void TakeDamage(int amount)
  {
      _currentHp = Mathf.Max(0, _currentHp - amount);
      OnHealthChanged?.Invoke(_currentHp, maxHp);
      if (_currentHp == 0) OnDied?.Invoke();
  }
}

📌 빠른 정리

  • Awake = 내부, Start = 객체 간, Update = 매 프레임
  • 물리 → Update가 아니라 FixedUpdate
  • 빈 Update()도 비용——안 쓰면 삭제
  • 구독/해제는 OnEnable/OnDisable

⚠️ 흔한 실수

  • ❌ Update() 안에서 GetComponent

    느림——매 프레임 검색

    ✅ Awake에서 캐시: _rb = GetComponent<Rigidbody>()

  • ❌ 생성자 사용: new PlayerCtrl()

    MonoBehaviour는 new 금지——Unity가 경고

    ✅ go.AddComponent<PlayerCtrl>()