
이 글에는 인프런 파트너스 링크가 포함되어 있습니다. 이 링크를 통해 구매하시면 제가 수익을 받을 수 있어요. 🤗
들어가며
유니티를 처음 시작하면 Hierarchy 창에 뭔가를 만들고, Inspector 창에서 뭔가를 추가하죠. 근데 이게 정확히 뭘 하는 건지 모르고 따라만 하는 경우가 많습니다.
저도 처음엔 "그냥 오브젝트 만들고 스크립트 붙이면 되는 거 아니야?"라고 생각했는데, GameObject와 Component의 관계를 제대로 이해하고 나니 유니티가 왜 이렇게 설계되었는지 보이기 시작했습니다.
이 글은 유니티를 처음 시작하는 분들을 위한 글입니다. 지난 글에서 Update와 FixedUpdate의 차이를 알아봤는데요, 이번에는 더 근본적인 개념을 다뤄보겠습니다.
GameObject란?
기본 개념
GameObject는 유니티 씬(Scene)에 존재하는 모든 것의 기본 단위입니다. 플레이어, 적, 카메라, 조명, 빈 오브젝트... 뭐든 GameObject입니다.
// 코드로 GameObject 생성
GameObject player = new GameObject("Player");
GameObject enemy = new GameObject("Enemy");
빈 껍데기 비유
여기서 중요한 점: GameObject 자체는 아무것도 못합니다.
빈 껍데기, 빈 상자라고 생각하면 됩니다. 이름표만 붙어있는 빈 상자예요. 이 상자 안에 뭘 넣느냐에 따라 기능이 달라집니다.
GameObject "Player" = 빈 상자
└── 아무것도 없음 → 화면에 안 보임, 아무 기능 없음
그럼 이 빈 상자에 기능을 어떻게 넣을까요? 바로 Component입니다.
Component란?
기본 개념
Component는 GameObject에 기능을 부여하는 부품입니다. 레고 블록처럼 필요한 기능을 조립한다고 생각하면 됩니다.
GameObject "Player" = 빈 상자
├── Transform (위치/회전/크기) ← 기본 장착
├── MeshRenderer (화면에 보이게)
├── Rigidbody (물리 적용)
└── PlayerController (커스텀 스크립트)
모든 GameObject에는 Transform이 있다
유일하게 삭제할 수 없는 Component가 있습니다. 바로 Transform입니다.
// Transform은 항상 존재
transform.position = new Vector3(0, 0, 0); // 위치
transform.rotation = Quaternion.identity; // 회전
transform.localScale = Vector3.one; // 크기
왜 삭제가 안 될까요? GameObject가 씬의 어딘가에 존재하려면 최소한 "어디에 있는지"는 알아야 하니까요.
Component 조립 예시
화면에 보이는 3D 오브젝트 만들기
큐브를 하나 만든다고 가정해봅시다.
GameObject "Cube"
├── Transform → 어디에 있는지
├── MeshFilter → 어떤 모양인지 (큐브 메시)
├── MeshRenderer → 어떻게 그릴지 (머티리얼)
└── BoxCollider → 충돌 영역
유니티에서 3D Object > Cube를 만들면 이 Component들이 자동으로 붙습니다.
움직이는 플레이어 만들기
GameObject "Player"
├── Transform
├── MeshFilter + MeshRenderer (보이게)
├── Rigidbody → 물리 적용 (중력, 힘)
├── CapsuleCollider → 충돌 판정
└── PlayerController → 커스텀 이동 로직
눈에 안 보이는 트리거 만들기
GameObject "DeathZone"
├── Transform
└── BoxCollider (isTrigger = true) → 충돌 감지만
MeshRenderer가 없으면? 화면에 안 보입니다. 하지만 충돌 감지는 됩니다!
코드로 Component 다루기
Component 추가
// Rigidbody 컴포넌트 추가
Rigidbody rb = gameObject.AddComponent<Rigidbody>();
rb.mass = 2f;
rb.useGravity = true;
Component 가져오기
// 자기 자신의 Rigidbody 가져오기
Rigidbody rb = GetComponent<Rigidbody>();
// 자식 오브젝트에서 찾기
Animator anim = GetComponentInChildren<Animator>();
// 부모 오브젝트에서 찾기
Canvas canvas = GetComponentInParent<Canvas>();
Component 존재 여부 확인
// null 체크 필수!
Rigidbody rb = GetComponent<Rigidbody>();
if (rb != null)
{
rb.AddForce(Vector3.up * 10f);
}
// 또는 TryGetComponent 사용 (Unity 2019.2+)
if (TryGetComponent<Rigidbody>(out Rigidbody rb))
{
rb.AddForce(Vector3.up * 10f);
}
자주 쓰는 Component 정리
| Component | 역할 | 언제 쓰나요? |
|---|---|---|
Transform |
위치, 회전, 크기 | 모든 오브젝트 (자동) |
MeshRenderer |
3D 렌더링 | 화면에 보여야 할 때 |
SpriteRenderer |
2D 렌더링 | 2D 게임 |
Rigidbody |
물리 시뮬레이션 | 중력, 힘이 필요할 때 |
Collider |
충돌 판정 | 부딪힘 감지 |
AudioSource |
소리 재생 | 효과음, BGM |
Animator |
애니메이션 | 캐릭터 동작 |
Camera |
화면 촬영 | 플레이어 시점 |
Light |
조명 | 씬 밝히기 |
이 설계의 장점: 컴포지션
유니티의 이런 설계를 컴포지션(Composition)이라고 합니다. 상속(Inheritance)과 대비되는 개념이에요.
상속 방식의 문제
전통적인 상속 구조:
Entity
└── Character
├── Player
└── Enemy
├── FlyingEnemy
└── GroundEnemy
만약 "날 수 있는 플레이어"를 만들고 싶다면? 상속 구조가 꼬이기 시작합니다.
컴포지션 방식의 해결
컴포지션 구조:
Player = Transform + Rigidbody + PlayerInput + ...
FlyingEnemy = Transform + Rigidbody + FlyingBehavior + ...
FlyingPlayer = Transform + Rigidbody + PlayerInput + FlyingBehavior + ...
필요한 기능을 블록처럼 조립하면 됩니다. 훨씬 유연하죠!
흔한 실수
1. GetComponent를 Update에서 매번 호출
// ❌ 나쁜 예: 매 프레임 GetComponent 호출
void Update()
{
Rigidbody rb = GetComponent<Rigidbody>(); // 비용 발생!
rb.AddForce(Vector3.forward);
}
// ✅ 좋은 예: 캐싱해서 사용
private Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody>(); // 한 번만 호출
}
void Update()
{
rb.AddForce(Vector3.forward);
}
2. 없는 Component에 접근
// ❌ NullReferenceException 발생 가능
Rigidbody rb = GetComponent<Rigidbody>();
rb.AddForce(Vector3.up); // rb가 null이면 에러!
// ✅ null 체크 필수
if (rb != null)
{
rb.AddForce(Vector3.up);
}
마무리
정리하면:
- GameObject = 빈 컨테이너 (이름표만 있는 빈 상자)
- Component = 기능을 담당하는 부품 (레고 블록)
- Transform = 모든 GameObject에 필수 (위치/회전/크기)
- 컴포지션 = 필요한 기능을 조립하는 유니티의 설계 철학
다음 글에서는 Transform과 좌표계에 대해 더 자세히 알아보겠습니다. Transform이 단순히 위치만 저장하는 게 아니라, 부모-자식 관계와 로컬/월드 좌표계까지 다룹니다.
더 공부하고 싶다면?
이 글에서 다룬 내용을 영상으로 더 깊이 배우고 싶으시다면, 아래 강의를 추천드립니다:
완전 처음이라면:
- 레트로의 유니티 C# 게임 프로그래밍 에센스 - 유튜브 인기 강사 이제민님의 체계적인 기초 강의
체계적으로 MMORPG까지 도전하고 싶다면:
- Rookiss의 C#과 유니티로 만드는 MMORPG 게임 개발 시리즈 - 前 크래프톤/NC 개발자의 실무 노하우
Reference
'유니티 > 스크립트' 카테고리의 다른 글
| [간식의 유니티 기초] Update와 FixedUpdate, 도대체 뭐가 다른 건가요? (0) | 2026.01.31 |
|---|---|
| 유니티 Rest API 통신 UnityWebRequest (0) | 2021.07.01 |
| 유니티 특정 시간동안 조건을 유지할 경우 (0) | 2020.12.25 |
| [유니티] npc와 대화하기 UniRX (1) | 2020.12.24 |
| [유니티]공 이동거리 계산 프로그램 (0) | 2020.08.02 |