
게임은 사람이 동시에 즐기는 경우가 많아 서버와 네트워크 지식도 중요합니다. 과정 후반에는 여러 명이 접속하는 간단한 멀티플레이 기능을 구현해 보며 클라이언트…
기능을 부품으로 나눠 붙이는 방식
자동차를 생각해 보세요. 엔진, 바퀴, 핸들, 라디오는 각각 독립된 부품입니다. 트럭에는 큰 엔진을, 경차에는 작은 엔진을 달고, 라디오는 필요하면 달고 아니면 뺍니다. 부품을 바꿔 끼우는 것만으로 다양한 차를 만들 수 있습니다.
게임 오브젝트도 같은 방식으로 만듭니다. 오브젝트 자체는 이름과 위치만 가진 빈 껍데기에 가깝고, 실제 기능은 붙어 있는 컴포넌트들이 담당합니다. 화면에 보이게 하는 컴포넌트, 물리 충돌을 처리하는 컴포넌트, 소리를 내는 컴포넌트, 그리고 내가 직접 만든 스크립트 컴포넌트가 모여 하나의 캐릭터가 됩니다.
Unity에서 오브젝트를 선택하면 인스펙터 창에 Transform, Mesh Renderer, Collider 같은 항목이 줄지어 보입니다. 이것이 모두 컴포넌트입니다. Unreal Engine에서도 액터에 스태틱 메시 컴포넌트, 캡슐 콜리전 컴포넌트, 무브먼트 컴포넌트 등을 붙여 기능을 구성합니다.
상속만으로 만들 때 생기는 문제
객체지향 프로그래밍을 처음 배우면 상속으로 구조를 짜는 경우가 많습니다. '캐릭터'라는 부모 클래스를 만들고, 그 아래 '플레이어'와 '적'을 두고, 적 아래 '날아다니는 적'과 '걸어 다니는 적'을 두는 식입니다. 처음에는 깔끔해 보입니다.
그런데 기획이 추가되면 문제가 드러납니다. '날아다니면서 땅에도 내려와 걷는 적'은 어디에 넣어야 할까요? '공격은 못 하지만 체력이 있어 부서지는 상자'는 캐릭터의 자식으로 둬야 할까요? 상속 나무는 한 갈래로만 내려가기 때문에, 여러 성질이 섞인 대상을 표현하기 어렵습니다. 억지로 끼워 넣다 보면 부모 클래스에 온갖 기능이 몰려 아무도 손대기 싫은 거대한 코드가 됩니다.
컴포넌트 방식에서는 이 고민이 단순해집니다. 날다가 걷는 적은 비행 컴포넌트와 보행 컴포넌트를 둘 다 붙이면 되고, 부서지는 상자는 체력 컴포넌트만 붙이면 됩니다. 이런 설계 원칙을 흔히 '상속보다 조합'이라고 표현합니다.
컴포넌트로 나눈 예시
| 오브젝트 | 붙이는 컴포넌트 |
|---|---|
| 플레이어 | 입력 처리, 이동, 체력, 공격, 인벤토리, 카메라 추적 |
| 근접 적 | AI 판단, 이동, 체력, 공격, 아이템 드롭 |
| 포탑 | AI 판단, 회전, 공격, 체력 |
| 부서지는 상자 | 체력, 아이템 드롭, 파괴 이펙트 |
| 회복 아이템 | 획득 판정, 효과 적용, 회전 연출 |
표를 보면 체력 컴포넌트가 플레이어, 적, 포탑, 상자에 모두 쓰입니다. 체력 코드는 한 번만 작성하고 여러 곳에 붙여 쓰는 셈입니다. 체력 회복 버그를 고치면 모든 오브젝트에서 동시에 고쳐집니다. 기획자가 '상자도 불에 타서 체력이 줄게 해 주세요'라고 요청해도 새 코드를 많이 쓸 필요가 없습니다.
컴포넌트에는 조절할 수 있는 값을 열어 두는 것이 좋습니다. 체력 컴포넌트라면 최대 체력, 무적 시간, 사망 시 동작을 에디터에서 바꿀 수 있게 하면, 기획자가 코드 없이 상자와 보스의 차이를 만들 수 있습니다. 같은 부품이 값만 달리해 전혀 다른 느낌을 내는 것이 이 방식의 큰 장점입니다.
컴포넌트를 나누는 기준
컴포넌트를 너무 크게 만들면 상속의 문제가 다시 생기고, 너무 작게 쪼개면 서로 연결하는 코드가 많아져 복잡해집니다. 처음 설계할 때는 다음 질문을 기준으로 삼으면 도움이 됩니다.
- 이 기능을 다른 종류의 오브젝트에도 붙일 일이 있는가
- 이 기능 하나를 빼도 나머지가 돌아가는가
- 컴포넌트 이름을 한 단어나 짧은 구로 설명할 수 있는가
- 고칠 때 이 파일만 열면 되는가
예를 들어 '플레이어 컨트롤러'라는 컴포넌트에 이동, 점프, 공격, 체력, UI 갱신까지 다 들어 있다면 너무 큰 것입니다. 반대로 '점프 높이 계산'과 '점프 입력 확인'을 따로 나눈 것은 지나치게 잘게 쪼갠 경우일 수 있습니다.
처음 배울 때 헷갈리는 점
컴포넌트끼리 어떻게 대화하느냐가 가장 먼저 부딪히는 문제입니다. 공격 컴포넌트가 적의 체력 컴포넌트를 깎으려면 그 컴포넌트를 찾아야 합니다. 같은 오브젝트 안에서 컴포넌트를 찾는 기능은 Unity의 GetComponent처럼 엔진이 제공하지만, 매 프레임 찾으면 느려질 수 있으니 시작할 때 한 번 찾아 저장해 두는 것이 일반적입니다.
또 서로를 너무 많이 직접 참조하면 부품을 갈아 끼우는 장점이 사라집니다. 체력 컴포넌트가 UI, 사운드, 이펙트 컴포넌트를 모두 알고 있다면 결국 하나로 묶인 것과 다르지 않습니다. 이럴 때 이벤트로 '체력이 바뀌었다'는 신호만 보내고, 관심 있는 컴포넌트가 듣게 하면 연결이 느슨해집니다.
엔티티 컴포넌트 시스템(ECS)이라는 이름도 자주 보게 됩니다. 이름은 비슷하지만 데이터와 처리 로직을 더 철저히 분리해 대량의 오브젝트를 빠르게 처리하는 구조로, 지금 설명한 일반적인 컴포넌트 방식과는 조금 다릅니다. 처음에는 기본 컴포넌트 구조부터 익히는 것이 순서입니다.
내 프로젝트를 컴포넌트로 다시 나눠 보기
이미 만들어 본 작은 게임이 있다면, 가장 긴 스크립트 하나를 골라 기능별로 쪼개 보는 연습이 효과적입니다. 쪼갠 컴포넌트 중 하나를 다른 오브젝트에 붙여 그대로 동작하는지 확인해 보세요. 수정 없이 붙여서 돌아간다면 잘 나눈 것입니다.
블루프린트와 C++을 오가는 Unreal Engine 프로젝트에서는 이 설계 감각이 특히 중요해집니다. 액터와 컴포넌트를 어떻게 나눠 쓰는지 실제 프로젝트로 익히고 싶다면, SBS아카데미게임학원 언리얼엔진(Unreal) 과정 상담에서 수업 프로젝트의 구성을 들어 보고 나에게 맞는 시작점을 찾아보세요.
자주 묻는 질문
컴포넌트 패턴을 쓰면 상속은 안 쓰나요?
함께 씁니다. 엔진의 컴포넌트 자체가 상속으로 만들어지고, 비슷한 컴포넌트끼리 공통 부모를 두는 경우도 많습니다. 다만 오브젝트의 기능을 구성할 때는 조합을 우선합니다.
컴포넌트가 많아지면 성능이 떨어지나요?
컴포넌트 수보다 각 컴포넌트가 매 프레임 무엇을 하느냐가 더 중요합니다. 할 일이 없는 프레임에는 업데이트를 건너뛰도록 만드는 것이 좋습니다.
가까운 캠퍼스에서 게임프로그래밍 알아보기
사는 곳과 가까운 캠퍼스를 고르면 수업 내용, 오시는 길, 상담 신청을 한 번에 볼 수 있습니다.