본문 바로가기

[Unreal5] 언리얼 블루프린트 VS C++ 각각의 장점!

Kwonriver 2022. 12. 20.
728x90

 

안녕하세요 Kwonriver입니다.

언리얼에서 제공하는 블루프린트와 C++의 차대해 알아보겠습니다.

 

언리얼 블루프린트와 C++


언리얼 블루프린트

  • 빠른 변경 : 매 번 빌드를 새로 해야하는 C++과 달리 블루프린트는 변경점을 즉각적으로 적용할 수 있다. 새로운 클래스를 생성하고 변수, 함수를 추가하는 작업에서 대부분의 경우 C++ 보다 빠르기 때문에 프로토타입 제작에 알맞다.
  • 유연한 편집 : 개발에 익숙하지 않은 초보자, 기획자, 아티스트도 쉽게 생성과 편집이 가능해 프로그래머의 손을 타지 않고도 빠르게 변경이 가능하다.
  • 원활한 흐름 : 게임의 흐름을 한 눈에 파악하기 편리하다. 딜레이 및 비동기 노드는 C++ 델리게이트보다 흐름을 파악하는데 훨씬 유리하고 빠르다.

 

C++

  • 높은 퍼포먼스 : 일반적으로 블루프린트보다 훨씬 높은 성능을 발휘한다. 동일한 게임을 블루프린트, C++ 각각 만들었을 때 C++로 구현한 게임이 훨씬 원활하고 빠르다.
  • 광범위한 접근 : 개발자가 직접 정의한 클래스, 함수, 변수들은 다른 모든 시스템에서 접근이 가능합니다. 또한 블루프린트보다 훨씬 많은 엔진 함수 기능에 접근이 가능하다. 이외에도 데이터 저장과 관련한 훨씬 구체적인 함수 기능을 사용할 수 있다.
  • 네트워크 리플리케이션 : 블루프린트의 리플리케이션은 매우 간단하고 고유환 일회성 액터에 한정되어 사용되도록 설계되었기 때문에 사용에 제한이 있다. 대역폭, 타이밍 등을 제어해야하는 경우에는 C++만 가능하다.
  • 쉬운 버전 관리 : C++ 코드와 데이터, 커스텀 솔루션 등의 정보는 모두 텍스트로 저장되기 때문에 여러 브랜치에서 동시 작업 및 관리가 쉽다.

블루프린트와 C++ 사이의 가장 큰 차이는 바로 퍼포먼스입니다. 그러나 모든 상황에서 C++로 구현하는 것이 유리한 것은 아닙니다. 현재의 블루프린트는 한 노드에서 1회 함수를 호출하는 것 자체는 C++과 큰 차이가 나지 않지만 블루프린트 클래스 내에 루프가 많거나 중첩 매크로가 많다면 C++이 훨씬 유리합니다. 또한 블루프린트의 Tick은 매우 느리기 때문에 매 프레임마다 반복적인 작업을 해야하는 경우라면 C++로 변경하는 것이 훨씬 유리합니다. 

 

아래는 언리얼 공식 문서에서 제시하는 프로젝트가 커지기 시작할 때 유념할 사항입니다.

  • 비싼 블루프린트로의 형변환 금지 : 블루프린트 클래스를 형변환 할 때마다 해당 블루프린트의 로드 종속성이 생기기 때문에 최대한 형변환을 피하는 것이 좋습니다. BP_A가 스태틱 메시 4개와 사운드 20개를 참조하는 경우에 BP_B를 BP_A 로 형변환하는데 실패하였다 하더라도 BP_B를 로드할 때 마다 스태틱 메시 4개와 사운드 20개를 로드합니다. 이런 이유 때문에 네이티브 베이스 클래스 또는 최소한의 블루프린트 베이스 클래스에 중요 함수와 변수만 정의하고 비싼 블루프린트를 자손 클래스로 만드는 것이 유리합니다.
  • 순환 블루프린트 레퍼런스 금지 : 순환 레퍼런스(서로를 참조하는 것)는 C++의 경우 헤더 파일이 분리되어 있어 문제가 없지만 블루프린트에서 과도한 순환 레퍼런스는 에디터 로드 및 컴파일 시간을 악화시킬 수 있습니다. 
  • C++ 클래스에서 에셋 레퍼런스 금지 : C++ 생성자에서 FObjectFinder, FClassFinder를 사용한 에셋 레퍼런스를 피하는 것이 좋습니다. 위 방식을 사용하면 프로젝트 시작 시 로드되는데 레퍼런스가 실제 필요치 않은 경우 로드 시간 및 메모리 이슈가 발생합니다. 일반적으로 특정 스태틱 메시 레퍼런스를 만드는 것보다 Game Data(게임 데이터)에셋 또는 블루프린트 유형을 조금 생성한 뒤 에셋 매니저나 구성 파일을 사용하여 로드하는 것이 좋습니다.
  • 스트링으로 에셋 레퍼런스 금지 : LoadObject 같은 함수를 사용하면 디스크의 특정 에셋을 수동 로드할 수 있어 C++ 클래스에서 에셋을 로드할 때 발생하는 이슈를 피할 수 있습니다. 그러나 이 레퍼런스는 쿠커가 추적하지 못하기 때문에 패키지 게임에서 문제가 생길 수 있습니다. 따라서 LoadObject 대신 FSoftObjectPath, TSoftObjectPtr 유형을 사용하고 ini 또는 블루프린트에서 설정한 뒤, 요청 시 로드 또는 비동기 로드를 통해 로드하는 것이 좋습니다.
  • 사용자 구조체 및 열거형 주의 : 사용자 구조체/열거형은 C++에서 사용할 수 없고 수동으로 변경할 수 없습니다. 따라서 중요한 열거형과 구조체는 C++에서 구현하는 것이 유리하며 둘 이상의 블루프린트에서 사용되는 구조체/열거형이라면 네이티브 C++로 구현하는 것이 좋습니다.
  • 네트워크 아키텍처 고려 : 일반적으로 프로토타입은 네트워킹을 고려하지 않고 만들기 때문에 리팩토링을 진행할 때 어떤 액터가 어떤 데이터를 리플리케이트할 지 고려해야 합니다. 반복처리를 어렵게 만드는 부분에 대한 처리를 잘 진행해야 리플리케이트되는 데이터의 원활한 흐름을 만들 수 있습니다.
  • 비동기 로드 고려 : 게임이 커지거나 리소스가 많아지면 에셋을 필요할 때만 로드하도록 하여야합니다. 하드 레퍼런스를 소프트 레퍼런스 또는 PrimaryAssetId로 변환해야 하는 시점이 발생하는데 AssetManager는 에셋 비동기 로드를 손쉽게 해주는 함수를 여럿 제공합니다.
728x90