핵심 정리
GameObject player = gameObject;
Transform tr = player.transform;
Rigidbody body = player.GetComponent<Rigidbody>();구조 이해
세 개념의 기본 관계
GameObject는 씬 안의 "존재 자체"이고, Component는 그 존재에 붙는 기능 단위입니다. Transform은 모든 GameObject가 기본으로 가지는 위치/회전/스케일 컴포넌트입니다. Rigidbody, Collider, AudioSource, Button, 사용자 스크립트는 모두 같은 컴포넌트 계열이지만, 붙는 대상과 책임이 다릅니다. 이 기본 mental model이 잡히면 GetComponent, [SerializeField], 프리팹, 인스펙터 연결, 활성화 상태 같은 개념이 훨씬 유기적으로 읽힙니다.
어떻게 읽어야 하는가
GameObject는 컨테이너이자 계층 노드입니다. 이름, 활성 상태, 태그, 레이어, 그리고 붙어 있는 컴포넌트들의 묶음이라고 보면 됩니다. Component는 기능 단위로, 같은 GameObject에 물리, 오디오, 렌더링, 사용자 로직이 함께 붙을 수 있는 이유도 이 컴포넌트 모델 덕분입니다.
Transform은 단순히 위치 값 하나가 아니라 parent-child 관계까지 포함합니다. 그래서 좌표계 문제를 볼 때는 "월드 좌표인가, 로컬 좌표인가, 어떤 부모 아래에 있는가"를 같이 봐야 합니다. MonoBehaviour는 사용자 스크립트도 컴포넌트라는 사실을 드러냅니다. this는 오브젝트 전체가 아니라 "현재 붙어 있는 컴포넌트"를 가리킨다는 감각이 중요합니다. Unity 코드를 읽을 때는 "이 메서드는 GameObject를 대상으로 하는가, 특정 Component를 대상으로 하는가, 아니면 Transform 공간을 다루는가"를 먼저 구분하면 혼란이 크게 줄어듭니다.
GetComponent 패턴과 코드 예제
컴포넌트를 가져올 때는 GetComponent<T>()를 사용합니다. Awake에서 캐싱해 두면 매 프레임 호출을 줄일 수 있습니다. Unity에서 "이 오브젝트에 어떤 컴포넌트가 붙어 있는가"로 생각하는 편이 자연스러운 이유가 바로 이 패턴입니다.
public class PlayerMover : MonoBehaviour
{
private Rigidbody body;
private void Awake()
{
body = GetComponent<Rigidbody>();
}
}자주 하는 실수
Destroy(this)와 Destroy(gameObject)는 전혀 다른 결과를 냅니다. Destroy(this)는 현재 컴포넌트만 제거하고, Destroy(gameObject)는 오브젝트 전체를 제거합니다. 마찬가지로 enabled = false는 현재 Behaviour 컴포넌트만 비활성화하고, gameObject.SetActive(false)는 오브젝트와 자식 전체의 활성 흐름을 중단합니다. 좌표도 마찬가지로 transform.position은 월드 좌표이고 transform.localPosition은 부모 기준 로컬 좌표입니다. Unity 입문자 버그 상당수는 이 두 쌍의 구분에서 생깁니다.
체크포인트
| 상황 | 적합한 선택 |
|---|---|
| 오브젝트 전체를 제거 | Destroy(gameObject) |
| 현재 스크립트 컴포넌트만 제거 | Destroy(this) |
| 특정 컴포넌트만 비활성화 | enabled = false |
| 오브젝트와 자식 전체 비활성화 | gameObject.SetActive(false) |
| 월드 좌표 vs 부모 기준 좌표 | transform.position vs transform.localPosition |
| 구분 | 무엇을 뜻하나 | 자주 하는 오해 |
|---|---|---|
GameObject | 씬 안의 존재와 계층 노드 | 기능도 GameObject 자체가 가진다고 생각함 |
Component | 기능 단위 (Rigidbody, Collider, 스크립트 등) | 오브젝트 전체를 지운다고 착각함 |
Transform | 모든 GameObject가 기본으로 가지는 좌표 컴포넌트 | 월드 좌표와 로컬 좌표를 섞어 씀 |
- 코드를 읽을 때 먼저 "오브젝트 전체를 다루는가, 특정 기능 컴포넌트를 다루는가"를 구분하면 버그 원인을 좁히기 쉽습니다.
GetComponent<T>()는 "이 오브젝트에 이 기능이 붙어 있는가"를 묻는 API라서, 참조가 없을 수 있다는 점까지 같이 생각해야 합니다.
주의할 점
Destroy(this)와 Destroy(gameObject)는 전혀 다른 결과를 냅니다. 컴포넌트를 끄고 싶은지, 오브젝트 전체를 지우고 싶은지 먼저 명확히 하세요.
// ❌ 오브젝트를 지우려 했는데 컴포넌트만 제거됨
Destroy(this); // PlayerMover 컴포넌트만 사라짐, GameObject는 남음
// ✅ 목적에 맞게 구분
Destroy(gameObject); // 오브젝트 전체 제거
enabled = false; // 이 MonoBehaviour만 비활성 (Update 등 중단)
gameObject.SetActive(false); // 오브젝트 + 자식 전체 비활성
// 좌표 혼동 예시
transform.position // 월드 좌표
transform.localPosition // 부모 기준 로컬 좌표 ← 부모 이동 시 값이 달라짐
// ❌ 붙어 있다고 가정하고 바로 사용
GetComponent<Rigidbody>().AddForce(Vector3.up);
// → Rigidbody가 없으면 NullReferenceException
// ✅ 필수 컴포넌트는 명시적으로 보장하거나 캐싱 시 확인
[RequireComponent(typeof(Rigidbody))]
public class PlayerMover : MonoBehaviour
{
private Rigidbody _body;
private void Awake() => _body = GetComponent<Rigidbody>();
}참고 링크
3 sources