언리얼 엔진 프로젝트는 블루프린트 또는 C++ 중에서 하나만 선택하여 제작할 수도 있지만, 대부분의 프로젝트는 이 둘을 적절히 조합하여 각각의 장점을 활용하게 됩니다. 그렇다면 프로젝트에 가장 적합한 블루프린트와 C++의 조합은 어떻게 결정할 수 있을까요? 이 문서에서는 이와 같은 질문의 해답을 도출하는 방법을 살펴봅니다.
프로그래밍 vs. 스크립팅
블루프린트와 C++ 중에서 무엇을 사용하는 것이 가장 좋을지 파악하려면 먼저 프로그래밍과 스크립팅의 차이점을 이해해야 합니다.
- 프로그래밍: 시스템을 정의하는 인스트럭션을 가리킵니다.
- 스크립팅: 기존 시스템과 인터페이싱하여 행동을 정의하는 인스트럭션을 가리킵니다.
예를 들어 프로그래밍으로는 가속 및 스티어링과 같은 베이스 함수 기능을 처리하는 비히클 시스템을 정의할 수 있고, 스크립팅으로는 이것이 자동차와 선박 중 어떤 것에 속하는지 구체적인 비히클 타입을 정의할 수 있습니다.
이 같은 맥락에서 C++는 프로그래밍 언어이고, 블루프린트는 스크립팅 언어라고 할 수 있습니다. 하지만 C++를 통해서도 행동을 정의할 수 있고, 블루프린트로도 시스템을 정의할 수 있으므로 딱 잘라 구분하기는 어렵습니다. 또한 프로젝트에서는 프로그래밍과 스크립팅의 경계가 모호한 경우가 있으므로 상황에 따라 최적의 구분 방식 또한 달라집니다.
블루프린트는 노출된 언리얼 엔진의 함수 기능과 인터페이싱함으로써 스크립팅 언어로 작동합니다. 마찬가지로, 커스텀 함수 기능을 블루프린트에 노출시킬 수도 있습니다. 자세한 내용은 블루프린트와 C++의 조합을 참고하세요.
블루프린트와 C++ 비교
모든 프로젝트와 팀의 상황은 다를 수밖에 없기 때문에 블루프린트 와 C++ 중에서 어떤 것을 사용할지에 대한 '정답'은 존재하지 않지만, 우선 각각의 장점을 고려한 후에 결정을 하는 것이 권장됩니다.
블루프린트의 장점
- 스크립팅: 블루프린트는 행동을 보다 손쉽게 정의할 수 있습니다.
- 빠른 반복작업: 블루프린트는 프로토타이핑에 탁월하며, 이는 블루프린트 클래스를 더 빠르게 생성, 수정, 컴파일 및 테스트할 수 있기 때문입니다.
- 폭 넓은 접근성: 블루프린트에서는 데이터플로가 시각적으로 표현되므로 한층 더 쉽게 이해하고 사용할 수 있으며, 이는 시각적으로 파악할 수 있는 것을 중요하게 생각하는 프로그래머부터 디자이너 및 아티스트처럼 프로그래머가 아닌 사용자도 손쉽게 접근할 수 있게 해주는 역할을 합니다.
- 향상된 검색 기능: 블루프린트를 사용하면 보다 쉽게 API와 에셋 레퍼런스를 검색하고 포함시킬 수 있습니다.
- 안전한 메모리 모델: 블루프린트는 크래시를 방지할 수 있는 안전한 메모리 모델을 갖추고 있습니다.
C++의 장점
- 프로그래밍: C++는 새로운 시스템을 보다 쉽게 빌드할 수 있습니다.
- 더 빠른 런타임 퍼포먼스: C++는 한층 뛰어난 퍼포먼스를 제공하지만 그 중요성은 상황에 따라 다를 수 있습니다. 자세한 내용은 아래 퍼포먼스 고려 사항 섹션을 참고하세요.
- 폭넓은 액세스: C++를 사용하면 언리얼 엔진의 로우 레벨 함수 기능에 액세스할 수 있습니다.
- 폭넓은 확장성: C++를 사용하면 외부 시스템 및 라이브러리를 생성하고 인터페이싱할 수 있습니다.
- 강력한 제어: C++는 시스템, 리소스 및 복잡한 알고리즘에 대한 로우 레벨 제어를 제공합니다.
- 원활한 협업: C++는 텍스트로 저장되기 때문에 프로젝트 간에 비교, 병합 및 공유하기가 한층 더 쉽습니다. 하지만 블루프린트에서는 언리얼 비교 툴을 사용할 수 있습니다.
- 뛰어난 유연성: 대규모 C++ 파일은 대규모 블루프린트 그래프와 비교하여 보다 쉽게 수정할 수 있습니다.
- 탁월한 디버깅: C++에서는 블루프린트 디버거보다 강력한 디버깅 툴을 제공합니다.
퍼포먼스 고려 사항
기본적으로는 C++가 블루프린트보다 뛰어난 퍼포먼스를 제공하는데, 그 이유는 다음과 같습니다.
- C++는 CPU에서 직접 실행되는 머신 코드로 컴파일됩니다.
- 블루프린트는 가상 머신에서 실행되는 바이트코드로 컴파일됩니다.
즉, 블루프린트에서는 스크립트 실행 오버헤드가 추가됩니다. 하지만 블루프린트와 C++ 간의 퍼포먼스에서의 차이는 일반적으로 미미하며, 상황에 따라 달라질 수 있습니다. 다음 예시는 그 영향이 가장 큰 것으로 예상할 수 있는 상황입니다.
- 코어, 로우 레벨 인프라스트럭처
- I/O 또는 프로세스 리소스를 많이 사용하는 타이트한 루프
- 대규모 데이터 세트를 처리하는 시스템
- 인스턴스가 많은 틱 종속 클래스
- 멀티 스레드의 이점을 얻을 수 있는 상황(블루프린트는 멀티 스레드를 지원하지 않음)
블루프린트에서 퍼포먼스를 향상하려면 틱 대신 타이머 또는 델리게이트를 사용하여 작업을 스케줄링해야 합니다.
블루프린트 사용 시 퍼포먼스 문제가 발생한 경우에는 블루프린트를 C++로 변환하기 전에 언리얼 인사이트로 프로젝트를 프로파일링하여 병목 현상이 가장 심각한 구간을 최적화하는 것이 좋습니다.
블루프린트와 C++의 조합
블루프린트와 C++을 조합하는 최적의 접근법은 C++를 기반으로 하여 그 위에 블루프린트 클래스를 빌드하는 것입니다. 즉, 실질적으로는 C++를 블루프린트에서 사용할 수 있도록 노출시키는 것입니다.
C++를 블루프린트에 노출시키는 방법은 다음과 같습니다.
- C++ 클래스를 확장하는 블루프린트 클래스를 생성한 다음
UPROPERTY(BlueprintReadWrite)
또는UFUNCTION(BlueprintCallable)
같은 메타데이터 지정자를 사용하여 특정 엘리먼트를 노출합니다. UBlueprintFunctionLibrary
를 확장하는 C++ 클래스를 생성하여 클래스의 스태틱 함수를 노출합니다.
일반적이지는 않지만 블루프린트를 C++에 노출해야 하는 경우가 있는데, 이렇게 하려면 다음과 같은 방법을 사용하면 됩니다.
UFUNCTION(BlueprintImplementableEvent)
지정자를 사용하여 블루프린트에서 구현해야 하는 순수 가상 함수를 정의합니다.UFUNCTION(BlueprintNativeEvent)
지정자를 사용하여 블루프린트에서 선택적으로 오버라이드할 수 있는 가상 함수를 정의합니다.- 유저 인터페이스를 생성하는 경우에는
UPROPERTY(meta=(BindWidget))
를 사용하여 블루프린트에서 생성된 UserWidget에 액세스할 수 있습니다.
이러한 방법에 대한 자세한 내용은 다음 페이지를 참고하세요.
- C++와 블루프린트: 블루프린트로 확장 가능한 C++ 클래스를 생성하는 방법을 자세한 예시를 통해 보여줍니다.
- 블루프린트에 C++ 노출하기: 블루프린트 친화적인 API를 작성할 때 사용할 수 있는 팁과 트릭을 제공합니다.
- 블루프린트에 게임플레이 엘리먼트 노출하기: 블루프린트에 게임플레이 엘리먼트를 노출하는 방법을 보여주는 게임플레이 프로그래머를 위한 기술 가이드입니다.
- 블루프린트 함수 라이브러리:
UBlueprintFunctionLibrary
를 사용하는 방법을 살펴봅니다. - 라이라 샘플 게임: 위에서 다룬 각각의 방법을 예시를 통해 확인할 수 있는 라이라 프로젝트를 살펴봅니다.
블루프린트를 C++로 변환하기
블루프린트를 C++로 변환하려면 블루프린트 헤더 뷰를 사용하여 블루프린트 클래스 또는 구조체에 대한 C++ 헤더 파일을 생성하는 것부터 시작하면 됩니다. 이렇게 생성되는 .h
파일에는 블루프린트의 모든 변수와 함수 선언이 포함되어 있지만, 함수 구현은 일치하는 .cpp
파일로 수동으로 변환해야 합니다.
블루프린트를 C++로 변환한 다음 새 C++ 클래스를 사용하려면 레퍼런스를 업데이트해야 할 수도 있습니다. 이로 인해 업데이트가 너무 많이 필요해지는 경우에는 코어 리디렉션을 사용하여 레퍼런스를 자동으로 리매핑하는 것도 고려해 볼 수 있습니다.