나만의 작은 도서관
[TIL][C++] 250804 MMO 서버 개발 72일차: 블루프린트 클래스 vs C++ 클래스, 블루프린트는 왜 성능이 떨어질까? - 노드 해석 비용(오버헤드 발생), 그럼 블루프린트의 용도는 무엇인가? 그저 C++이 무서운 겁쟁이들의 쉼터일까? 본문
Today I Learn
[TIL][C++] 250804 MMO 서버 개발 72일차: 블루프린트 클래스 vs C++ 클래스, 블루프린트는 왜 성능이 떨어질까? - 노드 해석 비용(오버헤드 발생), 그럼 블루프린트의 용도는 무엇인가? 그저 C++이 무서운 겁쟁이들의 쉼터일까?
pledge24 2025. 8. 5. 01:11주의사항: 해당 글은 일기와 같은 기록용으로, 다듬지 않은 날것 그대로인 글입니다.
블루프린트 클래스 vs C++ 클래스
- 언리얼에서 특정 기능을 구현할 때 사용하는 방식으로 1) 블루프린트와 2) C++ 이 있다. 이 둘은 상호보완적인 관계를 가지고 있긴 하지만, 블루프린트 Only, C++ Only 방식으로 게임 개발을 할 수 있기 때문에 한쪽을 쓰지 않는다고 문제가 되는 경우는 크게 없다.
- 문제는 이러한 경향 때문에 오히려 헷갈린다는 것이다. 한쪽으로만 개발을 할 수 있는데 왜 하나만 남겨두지 않고 둘 다 있는 것일까? 섞어서 쓰는 경우에는 어떤 이유 때문인가?
블루프린트 클래스
- C++에 대해서는 크게 할 말이 없으니, 블루프린트에 대해서 알아보자. 블루프린트, 정확히 블루프린트 클래스는 Unity의 프리팹(prefab)과 같은 역할을 한다. 프리팹은 게임 오브젝트의 세팅을 저장해 두고, 필요할 때마다 맵에 배치하거나, 다른 스크립트의 입력으로 사용할 때 활용되는데, 블루프린트도 그러한 역할을 맡는다는 것이다.
프리팹과 다른 블루프린트 클래스의 특성: 일부 로직을 소스 코드에서 빼두는 게 가능
- 하지만 프리팹과 다른 점은 일부 로직의 구현을 소스 코드에서 빼낼 수 있다는 것이다. 유니티의 경우 현재 프리팹에 기능을 추가하기 위해서는 스크립트를 추가하는 방식밖에 없었다.(내가 알기로는) 그래서 무언가 새롭게 추가할 때 스크립트를 추가하는데, 블루프린트 클래스의 경우 그럴 필요 없이 현재 클래스에서만 사용해서 로직의 재사용 가능성이 없거나, 로직의 흐름을 시각적으로 판단하고 싶을 때 블루프린트로 로직을 짤 수 있다.
- 블루프린트는 일반적인 프로그래밍 언어처럼 변수, 함수를 작성하는 기능이 존재하며, 각 노드들을 연결하여 로직을 구성한다.
- 이때, 노드에서 활용하는 함수는 엔진에서 미리 제공하는 것을 사용하거나, UFUNCTION 매크로 함수를 통해 엔진에 등록한 함수들을 사용할 수 있다.
- 커스텀 이벤트도 만들 수 있다. 이벤트는 특정 조건이 만족되었을 때 실행되는 방식의 작업으로, 사용자가 임의로 발동시키거나 시스템에 등록해 두고 알아서 발동시키게 할 수도 있다.
블루프린트의 단점
- 블루프린트는 단점이 몇 가지 존재한다. 그중 가장 주의 깊게 봐야 하는 단점은 바로 “성능 저하”인데, 기본적으로 블루프린트 방식으로 로직을 작성하면 C++ 방식의 로직 실행 성능보다 떨어진다.
블루프린트는 왜 성능이 떨어질까? - 노드 해석 비용(오버헤드 발생)
- C++은 컴파일 방식이며, 함수를 호출하는 코드는 함수 포인터만 남게 되기 때문에 호출 시, 고민할 것 없이 포인터를 타고 이동하면 된다.
- 하지만, 블루프린트는 인터프리터 방식이기 때문에 각 노드의 순서가 미리 정해져 있더라도 뒤에 실행될 노드들이 미리 기계어로 번역되어 있지 않는다. 즉, 각 블루프린트 노드들은 런타임에 해석되어 실행된다는 것이다.
헷갈리면 안 되는 점 : 함수 자체의 실행은 빠르다
- 윗 말이 “각 노드의 함수 원본 코드는 런타임에 컴파일된다”는 것을 의미하지는 않는다. UFUNCTION을 통해 등록된 함수의 경우, 함수 자체는 이미 기계어로 컴파일되어 있으며, 각 노드가 인터프리터 방식으로 해석되는 부분은 “이 노드가 호출해야 할 함수는 무엇인지, 다음 노드는 무엇인지 등”이다. 함수를 찾은 뒤 함수를 실행하는 속도는 거의 네이티브와 같다.
C++: Function1() → Function2() → Function3() (직접 호출)
Blueprint: Node1 → [노드 검색] → Node2 → [노드 검색] → Node3
↑ ↑ ↑
실행 컨텍스트 관리 다음 노드 찾기 실행 컨텍스트 관리
그럼 블루프린트의 용도는 무엇인가? 그저 C++ 이 무서운 겁쟁이들의 쉼터일까?
- 결론만 말하자면 아니다. 위에서도 잠깐 말했지만, 블루프린트는 일부 로직을 소스코드로부터 분리해서 구현할 수 있다는 장점이 있다.
- 이러한 점은 깔끔하게 프로젝트를 관리하거나 디자이너와 협력할 때 유용하게 쓰일 수 있는데, 개인적으로 생각했을 때 아래와 같이 사용하는 것이 가장 좋아 보인다.
“C++은 기능을 정의하고, 블루프린트는 기능 간의 흐름을 디자인한다”
- C++에서 직접적으로 캐릭터 특징을 디자인하거나, 전투의 흐름을 설계하지 않는 것이다. 이러한 게임 디자인적인 측면은 전부 블루프린트에게 맡긴다. C++은 그저 필요한 기능을 만들고, 이에 대한 활용은 하지 않는다.
- 예를 들어, 각 캐릭터마다 특징이 있고 어떤 캐릭터가 대미지를 받으면 괴랄하게 멀리 날아간다고 가정해 보자. 이때 C++은 날아가는 조건과 이벤트가 발생했을 때의 흐름을 정의하지 않는다. 대신, 날아가는 기능을 정의할 뿐이다. 충격 수치, 날아가는 정도, 날아가는 조건 등은 블루프린트에서 정의한다.
- 아래는 AI한테 물어본 결과인데, C++에서 작성할 내용은 아래와 같다.
- 성능이 중요한 로직: 복잡한 계산, 물리 시뮬레이션, AI 로직, 대량의 데이터 처리 등 성능의 핵심적인 부분은 C++을 사용한다.(블루프린트보다 훨씬 빠르게 실행되기 때문)
- 엔진 수준의 기능 구현: 게임 엔진 자체의 핵심 기능(렌더링, 물리, 네트워킹 등)을 확장하거나 수정할 때 사용
- 코드 재사용성 및 모듈화: 여러 프로젝트나 클래스에서 공통적으로 사용되는 기능을 C++로 라이브러리 형태로 활용하여 재사용성을 높인다.
- 아래도 똑같이 물어본 결과인데, 블루프린트에서 작성할 내용은 아래와 같다.
- 빠른 프로토타이핑 및 이터레이션: 게임 디자이너나 아티스트가 코딩 없이도 게임 로직을 빠르게 구현하고 테스트할 수 있도록 하고 싶을 때 사용
- 게임 플레이 로직: 상호작용, UI 이벤트 처리 등 게임 플레이어와 직접적으로 관련된 로직을 구현할 때 사용
- C++ 클래스의 확장: C++ 클래스에서 정의된 함수를 블루프린트로 노출시켜, C++의 기능을 블루프린트에서 쉽게 활용하고 확장할 때 사용한다. 예를 들어, C++로 정의된 기본 캐릭터 클래스에 블루프린트로 점프나 공격과 같은 특정 동작을 추가할 수 있다.
요약: 블루프린트 vs. C++
| 특징 | C++ | 블루프린트 |
| 용도 | 핵심 엔진 기능, 성능이 중요한 로직, 복잡한 시스템 구현 | 게임 플레이 로직, 빠른 프로토타이핑, 디자이너 작업 |
| 성능 | 우수 (컴파일된 코드) | 상대적으로 느림 (인터프리터 방식) |
| 개발자 | 프로그래머 | 프로그래머, 디자이너, 아티스트 |
| 가독성 | 텍스트 기반으로 복잡한 로직은 파악이 어려울 수 있음 | 비주얼 노드 기반으로 로직 흐름 파악이 용이 |
| 디버깅 | IDE(Visual Studio 등)를 사용한 강력한 디버깅 도구 | 엔진 내장 디버깅 도구 (블루프린트 디버거) |
결론
- C++은 기반을 다지는 역할을 하며, 게임의 핵심 시스템, 성능에 민감한 로직만 구현하고 게임 플레이 로직 디자인은 하지 않는다.
- 블루프린트는 게임의 살을 붙이는 역할을 하며, C++로 만든 뼈대 위에서 디자이너들이 게임 플레이 로직 디자인을 한다.