Level Blueprint vs C++ 스크립트
레벨 전용 연출은 Level Blueprint에, 재사용할 게임 로직은 C++에 배치하는 선택 기준을 세웁니다.
이전 절에서 우리는 언리얼 엔진 씬을 구성하는 주요 시각적 요소들(빛, 카메라, 메시)에 대해 알아보았습니다.
이제 이러한 요소들이 배치된 레벨(Level) 내에서 게임 로직이 어떻게 구현되는지, 특히 레벨 블루프린트(Level Blueprint)와 C++ 스크립트가 어떤 역할을 하고 언제 무엇을 사용해야 하는지에 대해 비교 분석해 보겠습니다.
이 두 가지 방법은 언리얼 엔진에서 게임플레이를 구현하는 핵심적인 경로이며, 각각의 장단점을 이해하는 것은 효율적인 개발 워크플로우를 구축하는 데 필수적입니다.
레벨 블루프린트 (Level Blueprint)란?
레벨 블루프린트는 현재 열려 있는 특정 레벨(맵) 내에서만 동작하는 전용 블루프린트입니다.
해당 레벨의 LevelScriptActor와 함께 동작합니다. 스트리밍에서는 여러 레벨이 함께 로드될 수 있으며, 같은 레벨을 유지하는 동안 다른 구역에 갔다고 곧바로 파괴되는 것은 아닙니다.
레벨 블루프린트 특징 및 장점
- 레벨 고유 로직: 특정 레벨에서만 필요한 이벤트나 상호작용을 구현하는 데 최적화되어 있습니다. 예를 들어, 특정 지점에 도달했을 때 문이 열리거나, 레벨 시작 시 컷씬이 재생되는 등의 일회성 이벤트에 적합합니다.
- 쉬운 참조: 레벨에 배치된 액터들을 직접 참조하여 해당 액터의 속성을 변경하거나 함수를 호출하는 것이 매우 쉽습니다. 월드 아웃라이너의 배치된 액터를 그래프로 끌어오거나, 액터 선택 후 그래프의 참조 생성 메뉴를 사용합니다.
- 시각적 스크립팅: 블루프린트의 시각적 노드 기반 프로그래밍 방식 덕분에 프로그래밍 경험이 적은 아티스트나 디자이너도 게임 로직 구현에 참여하기 용이합니다.
- 빠른 프로토타이핑: 복잡한 컴파일 과정 없이 즉시 변경 사항을 확인하고 테스트할 수 있어, 아이디어를 빠르게 구현하고 반복 작업하는 데 유리합니다.
레벨 블루프린트 한계
- 재사용성 부족: 레벨 블루프린트의 로직은 해당 레벨에 종속되므로, 복사로 재사용하면 유지보수가 어려워집니다. 공통 부분은 Blueprint Class·컴포넌트·함수 라이브러리 또는 C++로 분리할 수 있습니다.
- 복잡성 증가: 로직이 복잡해지거나 노드가 많아지면 시각적으로 관리하기 어렵습니다. 실행 비용은 노드 개수만으로 판단하지 말고 호출 빈도와 실제 작업을 측정합니다.
- 버전 관리 어려움: 텍스트 기반이 아니므로 버전 관리 시스템(Git, Perforce 등)에서 충돌(Conflict) 해결이 어렵습니다.
- 성능 제한: C++ 코드에 비해 런타임 성능이 떨어질 수 있습니다 (하지만 대부분의 게임 로직에서는 큰 문제가 되지 않습니다).
언제 레벨 블루프린트를 사용할까요?
- 레벨 전용 이벤트: 레벨 시작/종료 시의 이벤트, 특정 트리거 볼륨 진입 시의 이벤트 등.
- 특정 씬 액터 상호작용: 레벨에 고정된 문, 엘리베이터, 퍼즐 요소 등 특정 액터에 대한 직접적인 제어.
- 간단한 환경 스크립트: 날씨 변화, 배경 음악 전환 등 레벨의 분위기 연출.
- 빠른 테스트 및 프로토타이핑: 특정 기능을 C++로 구현하기 전에 빠르게 테스트해보고 싶을 때.
C++ 스크립트
C++ 스크립트는 우리가 지금까지 배우고 있는 방식으로, AActor나 UActorComponent와 같은 클래스를 C++로 직접 정의하여 게임 로직을 구현하는 방식입니다.
C++ 클래스 코드는 Source의 헤더·소스에 있고, 이를 상속한 Blueprint 에셋은 Content의 .uasset으로 저장됩니다. 인스턴스 생성 방식은 Actor·Component 등 부모 타입에 따라 다릅니다.
C++ 스크립트 특징 및 장점
- 높은 재사용성: C++ 클래스는 레벨에 구애받지 않고 재사용 가능한 독립적인 단위입니다. 한 번 만든 C++ 클래스는 여러 레벨의 다양한 액터에서 인스턴스를 생성하여 사용할 수 있습니다.
- 성능 우위: 컴파일된 코드로 실행되므로, 복잡한 연산이나 빈번하게 호출되는 로직에서 블루프린트 VM의 반복 실행 비용을 줄일 수 있습니다. 실제 병목이 렌더링·I/O 등 다른 곳에 있다면 언어 변경만으로 해결되지 않습니다.
- 강력한 제어: 엔진의 깊숙한 부분까지 접근하여 커스터마이징하고 제어할 수 있습니다.
- 구조화된 코드: 엄격한 타입 체크와 명확한 문법 덕분에 대규모 프로젝트에서 코드의 구조와 규칙을 강력하게 강제하고, 유지보수성을 높일 수 있습니다.
- 버전 관리 용이: 텍스트 기반의 코드이므로 버전 관리 시스템에서 충돌 해결이 비교적 용이합니다.
- 블루프린트 확장:
UCLASS,UPROPERTY,UFUNCTION매크로를 통해 블루프린트로 기능을 노출하고 확장할 수 있으므로, C++의 장점과 블루프린트의 유연성을 동시에 취할 수 있습니다.
C++ 스크립트 한계
- 느린 이터레이션: 코드를 수정할 때마다 컴파일 과정을 거쳐야 하므로, 작은 변경에도 시간이 소요됩니다.
- 높은 학습 곡선: C++ 언어 자체의 복잡성과 언리얼 엔진의 방대한 API에 대한 이해가 필요합니다.
- 비개발자 접근성: 프로그래밍 지식이 없는 팀원들이 직접 수정하기 어렵습니다.
언제 C++ 스크립트를 사용할까요?
- 핵심 게임플레이 시스템: 캐릭터의 이동, 공격 시스템, 인벤토리, AI 로직, 충돌 처리 등 게임의 핵심 메커니즘.
- 재사용 가능한 컴포넌트: 여러 액터에 부착하여 특정 기능을 제공하는 컴포넌트 (예: 체력 컴포넌트, 인터랙션 컴포넌트).
- 성능이 중요한 로직: 물리 시뮬레이션, 복잡한 수학적 계산, 실시간 데이터 처리 등.
- 엔진 기능 확장: 언리얼 엔진의 기존 기능을 오버라이드하거나 새로운 기능을 추가할 때.
- 대규모 프로젝트: 코드의 구조와 규칙을 명확히 하고, 팀원 간의 협업 및 유지보수성을 높여야 할 때.
반복되는 기능이 생겼을 때는 레벨 전용 참조와 재사용할 규칙을 먼저 분리합니다. 재사용 가능성은 구현 언어만으로 결정되지 않습니다.
레벨 블루프린트와 C++ 스크립트의 조화
언리얼 엔진 개발에서 가장 이상적인 워크플로우는 C++와 블루프린트의 장점을 결합하여 사용하는 하이브리드 접근 방식입니다.
- C++: 게임의 핵심 엔진 로직, 기반 시스템, 성능이 중요한 부분, 그리고 재사용성이 높은 유틸리티 함수나 클래스를 구현하는 데 사용합니다. C++로 만든 클래스는
UPROPERTY와UFUNCTION을 통해 블루프린트로 노출시킵니다. - 블루프린트: C++로 만들어진 기반 위에 게임 콘텐츠, 특정 레벨의 고유한 이벤트, 디자이너나 아티스트가 직접 조정해야 하는 데이터 및 로직, 그리고 빠른 프로토타이핑에 사용합니다. C++ 클래스를 상속받아 기능을 확장하거나, 레벨 블루프린트에서 C++ 액터들을 제어하는 방식입니다.
캐릭터 이동 시스템: ACharacter 클래스에서 UCharacterMovementComponent를 활용하여 C++로 기본적인 걷기, 뛰기, 점프 등의 이동 로직을 구현합니다.
공격 시스템: UWeaponComponent를 C++로 만들고, 발사 로직이나 대미지 계산 등 핵심 기능을 구현합니다.
UI 상호작용: APlayerController에서 C++로 UI 위젯을 생성하고 초기화하는 로직을 정의하고, 위젯 내의 버튼 클릭 이벤트 등은 블루프린트에서 처리합니다.
특정 레벨의 퍼즐: C++로 UInteractableComponent를 만들어 상호작용 인터페이스를 제공하고, 레벨 블루프린트에서 해당 컴포넌트를 가진 액터들을 직접 참조하여 퍼즐의 순서나 결과 로직을 구현합니다.
이러한 방식으로 개발하면, 견고하고 성능 좋은 기반 위에 유연하고 빠르게 콘텐츠를 추가하고 변경할 수 있습니다.
구현 위치를 정할 때 다음 질문을 확인합니다.
- 특정 레벨의 배치 참조와 연출 순서에 종속되는가?
- 여러 인스턴스에서 같은 규칙이 반복되어 공통 클래스·컴포넌트로 뺄 수 있는가?
- 측정된 병목이 있는가, 아니면 편집 편의 때문에 바꾸려는가?
- 디자이너가 조정할 값과 호출할 함수를 어디까지 공개할 것인가?