MonoBehaviour
MonoBehaviour는 모든 Unity 스크립트의 베이스 클래스로 라이프사이클 훅과 Component 접근을 제공합니다. Awake·Start·Update·FixedUpdate·OnDestroy와 빈 Update 비용·AddComponent 규칙을 배우는 입문 가이드입니다.
상상해 보세요...
MonoBehaviour는 Unity와의 고용 계약과 같습니다. 서명(상속)하면 직원(스크립트)이 자동으로 정해진 회의에 초대됩니다: 킥오프(Awake), 첫날(Start), 일일 스탠드업(Update), 물리 동기화(FixedUpdate), 퇴사 면담(OnDestroy). 상속이 없으면 메서드를 정의해도 호출되지 않습니다.
개념 자세히
MonoBehaviour는
Behaviour → 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
Awake()
내부 초기화 · Start 이전
Start()
초기 설정 · 첫 프레임
Update()
매 프레임 로직 · Input, AI...
FixedUpdate()
Physics · 0.02초마다
LateUpdate()
모든 Update 이후 · Camera follow
OnEnable()
오브젝트가 활성화될 때
OnDisable()
오브젝트가 비활성화될 때
OnDestroy()
오브젝트가 파괴될 때
실습 단계
새 C# 스크립트 만들기
Assets → Create → C# Script. 컴파일 오류를 피하려면 파일명과 클래스명을 맞추세요.
내부 설정은 Awake
컴포넌트 참조 캐시(_rb = GetComponent<Rigidbody>())는 Awake. 여기서 다른 객체에 의존하지 마세요.
객체 간 설정은 Start
다른 객체가 필요할 때 Start(그들의 Awake는 이미 끝남).
Update vs FixedUpdate 분리
입력·AI → Update. 물리 힘(AddForce, velocity) → FixedUpdate로 글리치 방지.
OnDestroy에서 정리
OnDestroy에서 이벤트 구독 해제, Coroutine/타이머 정지로 누수 방지.
인터랙티브 시뮬레이터
Play Scene을 눌러 라이프사이클 메서드가 순서대로 호출되는 모습을 보세요. Disable·Destroy로 다음 단계도 시험하세요.
Lifecycle Timeline
Console
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>()