Component
Component는 GameObject에 부착되는 독립 빌딩 블록입니다. 각 컴포넌트가 한 조각의 동작을 정의하므로 Composition over Inheritance로 게임을 구성합니다. GetComponent 캐시·스크립트 분리·인터페이스 결합을 배우는 입문 가이드입니다.
상상해 보세요...
Component는 레이싱카의 업그레이드 모듈과 같습니다. 섀시(GameObject)만으로는 아무것도 못 하지만, 엔진(Rigidbody)·바퀴(Collider)·조향(Script)·라이트(Light)를 붙이면 완전한 동작이 됩니다. 각 모듈은 독립적입니다——라이트를 빼도 엔진은 계속 돕니다.
개념 자세히
Component는 Unity 아키텍처의 핵심입니다. 거대한 상속 트리 대신, Unity는 작고 독립적인 컴포넌트를 조합하는 방식을 권장합니다—— Composition over Inheritance.
모든 Component는 UnityEngine.Component를 상속하므로
gameObject(호스트 객체)와 transform에 접근할 수 있습니다.
참조 가져오기: GetComponent<T>(). 자식 검색:
GetComponentInChildren<T>(). 부모 검색:
GetComponentInParent<T>().
핵심 스킬:
큰 스크립트를 여러 작은 Component로 언제 나눌지 아는 것입니다.
500줄 PlayerController 대신 → PlayerMovement,
PlayerCombat, PlayerHealth로 분리하세요.
Composition vs Inheritance
❌ Inheritance (복잡함)
✅ Composition (Unity)
실습 단계
Inspector에서 Component 부착
GO 선택 → Add Component → 이름으로 검색(Rigidbody, Audio Source…).
Awake()에서 GetComponent로 캐시
_rb = GetComponent<Rigidbody>();를 프라이빗 필드에 저장합니다.
Component 활성화 / 비활성화
component.enabled = false/true — 제거하지 않고 잠시 끌 뿐입니다.
Interface로 느슨하게 연결
스크립트 간 하드 의존을 피하세요 — IDamageable, IInteractable…
인터랙티브 시뮬레이터
Component를 켜고 끄며 캐릭터 동작이 어떻게 바뀌는지 확인하세요. 현재 조합 설명을 지켜보세요.
GameObject "Player"에 컴포넌트 토글
현재 행동
코드 예제
기본using UnityEngine;
public class ComponentBasics : MonoBehaviour
{
// Cache: fetch the component once, not every frame
private Rigidbody _rb;
private Collider _col;
private Renderer _renderer;
void Awake()
{
_rb = GetComponent<Rigidbody>();
_col = GetComponent<Collider>();
_renderer = GetComponent<Renderer>();
}
void Start()
{
// Null-check before use (safe)
if (_rb != null) _rb.mass = 2f;
_renderer.enabled = false; // hide the object
_col.enabled = false; // disable collisions
}
public void MakeInvincible()
{
// Disable the AI script (do not remove the component)
EnemyAI ai = GetComponent<EnemyAI>();
if (ai != null) ai.enabled = false;
}
}코드 예제
고급using UnityEngine;
// Interface: a contract for any component that can take damage
public interface IDamageable
{
void TakeDamage(int amount);
}
// Health component: only manages HP, knows nothing about combat
public class Health : MonoBehaviour, IDamageable
{
[SerializeField] private int maxHP = 100;
private int _currentHP;
void Awake() => _currentHP = maxHP;
public void TakeDamage(int amount)
{
_currentHP -= amount;
if (_currentHP <= 0) Destroy(gameObject);
}
}
// Bullet component: deals damage without knowing Health exists
public class Bullet : MonoBehaviour
{
[SerializeField] private int damage = 25;
void OnCollisionEnter(Collision col)
{
// Ask: does this object implement IDamageable? → loose coupling
col.gameObject.GetComponent<IDamageable>()?.TakeDamage(damage);
Destroy(gameObject);
}
}📌 빠른 정리
- ▸Component = GameObject에 붙는 독립 모듈
- ▸깊은 상속보다 Composition(작은 컴포넌트 여러 개)을 선호
- ▸항상
Awake()에서 프라이빗 필드에 캐시 - ▸Interface로 컴포넌트가 직접 의존 없이 대화하게 함
⚠️ 흔한 실수
❌ 한 스크립트가 너무 많은 일을 함
이동·HP·무기·UI까지 담당하는 500줄 스크립트
✅ PlayerMovement, PlayerHealth, PlayerWeapon으로 분리
❌ Update() 안에서 GetComponent<>() 호출
컴포넌트가 없으면 NullReferenceException
✅ Awake()에서 캐시하고 사용 전 null 체크