Quick Reference
GameObject는 씬의 계층 노드와 설정 묶음이고, Component는 그 노드에 붙는 기능이며, Transform은 모든 GameObject에 반드시 있는 좌표·부모 자식 Component입니다. API를 읽을 때 먼저 "오브젝트 전체", "한 Component", "좌표계" 중 무엇을 바꾸는지 구분합니다.
| 대상 | Inspector/상태 | 대표 API | 범위를 잘못 잡았을 때 |
|---|---|---|---|
GameObject | 이름, Tag, Layer, Active, Static, 계층 | SetActive, AddComponent, Destroy(gameObject) | 자식·다른 Component까지 멈추거나 삭제 |
Component | 해당 기능의 Inspector 값 | GetComponent, TryGetComponent, Destroy(component) | 오브젝트 전체를 바꾼다고 오해 |
Transform | local Position/Rotation/Scale, 부모 | position, localPosition, SetParent | 부모 기준 배치와 월드 좌표가 섞임 |
GameObject player = gameObject;
Rigidbody body = player.GetComponent<Rigidbody>();
Transform point = player.transform;
Destroy(body); // Rigidbody만 제거
// Destroy(player); // GameObject와 붙은 Component를 제거GameObject Inspector와 계층
GameObject Inspector의 위쪽에는 Name, Tag, Layer, 활성 checkbox, Static이 있고, 아래에는 붙어 있는 Component가 나열됩니다. Tag는 분류·조회 용도이고, Layer는 Camera culling·Physics collision matrix·raycast mask처럼 시스템별 필터에 쓰입니다. 같은 이름의 GameObject가 여러 개 있을 수 있으므로, 이름만으로 런타임 대상을 찾는 구조는 씬 변경에 취약합니다.
활성 checkbox는 activeSelf를 바꾸며, 부모가 비활성이면 자식의 activeInHierarchy는 false입니다. 이 차이는 SetActive 카드에서 별도로 다룹니다. Static도 하나의 성능 스위치가 아닙니다. Navigation, batching, occlusion 등 어떤 static flags를 적용할지 프로젝트의 bake·렌더링 정책에 맞춰 고릅니다. 움직이는 오브젝트에 정적 전용 bake 가정을 남기면 결과가 깨질 수 있습니다.
Component에는 한 GameObject에서 여러 개 붙을 수 있는 타입도 있고, 단 하나만 의미 있는 타입도 있습니다. Rigidbody, Collider, Renderer, 사용자 MonoBehaviour는 서로 다른 책임을 가질 수 있으므로, "Player"라는 GameObject를 한 덩어리로 다루기보다 그 안의 의존 Component를 명시하는 편이 안전합니다.
참조와 의존성
같은 GameObject의 필수 Component는 Awake에서 가져와 필드에 보관합니다. GetComponent<T>()는 없으면 null을 반환하므로, prefab 설정 오류를 예외가 터진 뒤에 발견하지 않도록 검사합니다.
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public sealed class PlayerMover : MonoBehaviour
{
private Rigidbody body;
private void Awake()
{
if (!TryGetComponent(out body))
{
Debug.LogError("PlayerMover requires a Rigidbody.", this);
enabled = false;
}
}
}RequireComponent는 이 script를 GameObject에 새로 추가할 때 필요한 Component를 자동 추가합니다. 컴파일 타임 검사가 아니며, 이미 존재하는 prefab·scene instance에 나중에 attribute를 추가해도 빠진 의존성을 자동 복구하지 않습니다. 그래서 기존 자산을 바꾼 뒤에는 prefab 검사나 Awake/OnValidate 검사를 같이 둡니다.
다른 GameObject나 child object가 의존 대상이라면 [SerializeField] 연결을 우선합니다. GetComponentInChildren은 계층을 탐색하므로 호출 위치·inactive 포함 여부를 의도적으로 정하고, 찾은 결과를 계속 사용할 때만 cache합니다.
Transform과 수명주기 경계
Transform은 Component지만 GameObject와 1:1로 항상 존재합니다. transform shortcut은 현재 MonoBehaviour가 붙은 GameObject의 Transform을 반환합니다. Transform은 부모-자식 관계를 가지므로 Inspector에서 보이는 값은 보통 local Position·Rotation·Scale이며, position 같은 world API와 같은 값이 아닙니다.
Destroy(this)는 현재 MonoBehaviour Component만, Destroy(gameObject)는 GameObject와 붙은 Component 전체를 제거합니다. enabled = false는 Behaviour 하나의 메시지 함수 갱신을 끄는 선택이고, gameObject.SetActive(false)는 GameObject와 실제 활성 자식의 실행 흐름을 끕니다. 화면만 숨길 것인지, 기능 하나만 멈출 것인지, 객체 수명 자체를 끝낼 것인지를 먼저 정합니다.
자주 틀리는 부분
| 증상 | 원인 | 확인과 수정 |
|---|---|---|
필수 Component가 없어서 NullReferenceException | 기존 prefab에 RequireComponent만 뒤늦게 추가 | prefab migration과 Awake/OnValidate 검사를 함께 수행 |
| 오브젝트를 지웠다고 생각했는데 script만 사라짐 | Destroy(this) 호출 | 목적에 따라 Component 또는 gameObject를 명시 |
| child 위치가 부모 이동 뒤 어긋남 | world/local API와 부모 관계 혼동 | Inspector local 값, parent, SetParent 인수를 함께 확인 |
| raycast가 대상에 닿지 않음 | GameObject Layer와 query mask/Physics Matrix가 불일치 | Layer index, mask, collision matrix를 모두 확인 |
| 비활성 자식 참조가 없음 | 기본 child 탐색은 inactive를 포함하지 않음 | 필요한 경우 GetComponentInChildren<T>(true)를 의도적으로 사용 |
참고 링크
3 sources