Unreal Engine - CPP / BP Manual

JUSTICE_DER·2023년 3월 24일
0

🌵UNREAL

목록 보기
27/42
post-thumbnail

서론

언리얼 프로젝트를 진행하면서 정말로 항상 고민했다.
CPP로만 게임을 만들어보았었고, BP로만 게임을 만들고 있다..
하지만 만들면서 느끼는 것은,
"한쪽 기능만 사용해서 만드는 것은 굉장히 찝찝하다?" 라는 것인데..
뭘 CPP로 써야하고 뭘 BP로 써야할까..?

기본적으로 CPP와 BP의 장단점이 극명해서,
한쪽의 단점이 다른 한쪽의 장점에서 채워지는 느낌이었다.

내가 생각하는 CPP는,

장점 :
내가 원하는 구조대로 코드를 짤 수 있다.
자유도가 매우 높고, 범용적으로 짤 수 있다.
작업의 수행 속도가 굉장히 빠르다.

단점 :
타이핑할게 많고,

특히, Unreal에 이미 존재하는 특정 요소나,
특정 기능을 가져오고 싶은데 그 과정이 복잡하다.

내가 생각하는 BP는,

장점 :
시작화되어 훨씬 간단하다.
클래스별로 어디에 어떤 변수, 함수가 존재하는지 한눈에 파악이 가능하다.
특정 요소를 가져오기가 굉장히 쉽다.
큼지막한 알고리즘들을 일일히 구현할 필요가 없다.

단점 :
수행속도가 느리다.
이미 다 입력, 출력이 만들어진 노드들을 사용하기 때문에,
자유도면에서 제한적이다.

이를 아래의 영상에서 다룬다.
https://www.youtube.com/watch?v=VMZftEVDuCE


Game Making Levels

영상에서는 설명한다.
Unreal이라는 엔진을 C언어같은 관점에서 보았을 때,
단순히 물체를 움직이거나 빛나는 구현된 기능들은 Low-Level의 언어이고,
High-Level에서는 기능들을 모아 반딫불이라는 존재가 된다.

즉, 반딫불이를 만들기 위해서, 필요한 기능들을 모아서 만드는 것이다.

프로그래머는, Low와 High의 중간 부분을 채우기 위해서,
기존 Engine의 기능을 어떻게 조합해야 반딫불이가 될지 고민해야만 한다.

총 Level을 3단계로 나눌 수가 있는데, 낮은순으로,
Engine Programming - Game Progremming - Scripting이다.

더 세분화하여 설명한다면,
Engine Programming은 게임이 뭐일진 모르겠으나, 범용적으로 사용할 수 있는 기능들을 구현해놓는 것이고,
Game Programming은 엔진기능들 중, 게임에 필요한 기능들을 모아서 핵심 기능으로 만들어 놓는 것이고,
Scripting은 구현된 핵심 기능을 사용하여, 실제 게임에서 어느 상황에 사용할지 정하는 것이다.

최종 목적인 Game이라는 문제상황을 해결하기 위해서,
Low Level -> High Level로 점차 범용적인 것에서 구체화 하며 발전해나가는 것이다.


Low-High Level

Engine Programming - Game Progremming을 Low-Level로 취급할 수 있고,
실제로 Programming이라고 merge할 수 있을 것이다.

Scripting은 굳이 보자면 Programming은 아닌 개념이고, High-Level로 볼 수 있을 것이다.

여기서 보이게 된다.
CPP와 BP를 어디에 써야하는지.

CPP는 Programming언어고, BP는 Scripting을 구현할 수 있다.
즉, CPP는 저수준의 게임시스템 구현,
BP는 고수준의 상호작용, 동작, 에셋, 시각적인 요소를 다루는데 초점을 맞춘다.


하지만 가장 중요한 것은,
언리얼은 CPP와 BP를 사용해야할 명확한 경계선을 그어주지 않는다는 것이다.

위의 부분이 가장 중요한데,
명확한 경계선이 없다는 이야기는, 어떤건 CPP로만 구현이 되고, 어떤건 BP로만 구현되는 것이 아니라,
Game을 만들기 위해서 CPP, 혹은 BP만으로도 구현이 된다는 말이 된다.

그리고 이 말은 다시말해,
상대적으로 High-Level이 더 쉽기 때문에,
현재 진행중인 UTR RPG게임처럼, BP로만 게임을 만드는 경우도 가능해지는 것이고,
구현의 어려움의 정도에 따라서 CPP와 BP의 비중을 달리하여 구현할 수 있다는게 가능하다는 말이 된다.

즉, 명확한 정답이 없다.
같은 목적을 달성할 수 있고,
그 난이도를 달리할 수 있다는 말이 된다.


Standard of Using CPP or BP

하지만, 권장사항은 존재한다.

두개의 요소의 사용처를 구분짓는 특정 룰은 없지만,
언리얼엔진을 사용하는 프로그래머들이 그 구분짓는 기준을 나누는 척도를 정했고,

가장 자주 사용되는 항목은 성능이다.
똑같이 구현할 수 있다면, 더 효율적인걸 항상 추구하기 때문이다.

Performance

CPP는 CPP컴파일러를 통해서, 바로 기계언어로 컴파일 된다.
BP는 GameEngine이 시작시에 스크립트컴파일러를 통해서,
2차원 평면상의 그래프가 1차원으로 컴파일 된다.
1차원의 스크립트에서 CPP함수도 추가적으로 호출하게 된다.
그 호출된 CPP는 다시 기계어로 변환되어 실행하고,
해당 결과를 1차원 스크립트에 알려주게 된다.
즉, 기본적으로 BP는 처리해야할 CPU명령들이 CPP보다 길어지게 된다.
대부분 CPP의 함수를 사용하게 되기 때문에, BP가 성능이 나쁠 수 밖에 없다.

하지만, 한프레임에 16밀리초가 있게 되는데,
CPP를 사용하거나 BP를 사용하는게 의미가 있는게 아니라고 한다.
뭘 사용하든 대부분의 연산이 16밀리초안에 끝나기 때문인가보다.

하지만, 단 한번 실행할 경우의 이야기이고,
해당 BP의 노드를 1000개 이상 사용하게 된다면, 성능에 문제를 주게 된다.
CPP에 비해 더 긴 하나의 연산을 여러번 진행해야하기 때문에, 오버헤드가 발생한다.

즉, 성능면에서 CPP는
Low-Level을 구현할 때 당연히 사용해야하고,
대규모 데이터를 조작하는 모든 부분에서 사용되어야하고,
자주 실행되어야 하는 반복문이라던가,
특히 액터에서 Tick이라는 프레임-반복문 떄문에 액터까지도 CPP에서 다루는 것이 좋다.

BlueprintNativization - BP를 Native언어(CPP)로 바꾸는 기능
성능을 위해서 이런 기능도 Unreal Engine에 존재한다.
해당 기능을 사용하면, 자동으로 Naitive언어(CPP)로 변환시킬 수 있게 된다.
사람이 세부적인 기능을 읽고 수정할 수는 없지만, 동일한 작업을 하게 된다.

성능이라는 항목에 추가로,
파레토법칙을 적용시킬 수 있는데,

게임 전체 내에서 매우 적게 사용되는 기능을 아무리 효율적으로 짜봤자 의미 없기때문에,
정말 성능상 중요한 부분만 Low Level언어로 힘들게 작성한다면 어떨까 라는 것이다.

모든 부분을 효율적으로 짤 수 있지만, 그에 소모되는 시간과 비용이 과연 합당한가


Dependency

구현적으로는 CPP가 더 어렵지만, 성능면에서는 CPP가 BP보다 좋다는 결론이었다.
하지만, 성능뿐만이 아니라, 다른 이유로 CPP를 선호하는 이유가 존재한다고 한다.

Dependencies Between Types
BP에서의 문제는 무언가를 참조할 때 발생한다.

총알의 경우, 그냥 앞으로 나가기만 하면 되는 객체인데,
총알을 쏘는 총의 transform값을 가져오기 위해서 총객체 자체를 가져오고,
계산하여 앞으로 날아가는 이런 경우가 문제라는 것이다.

총알은 그냥 생성되면 앞으로 나가야한다.
총의 정보를 알 필요가 없다는 것이다.
여태까지 이렇게 작성했었다..

BP로는 계속 게임의 규모가 커지면서 구조를 제어하기 힘들어지게 된다.
BP는 그냥 모든 것을 참조하고 모든것에 참조될 수 있다.
Delegate 등 방법이 존재하긴 하지만, CPP에 비해서 적다

CPP에서는 모듈을 사용하여, 단방향 참조로 계층구조를 만들 수 있어서
형상관리나 버그제어, 기능수정이 쉬워진다.

반대로, 모듈을 사용하면 양방향 소통이 되지 않고,
구조를 생각하면서 코드를 짜야하기 때문에,
BP에서 총의 위치값을 가져오고 그냥 위치만 더해서 총알을 spawn하고 나가게 하는것을 못한다.
추가로, BP에서는 CPP의 값들을 참조가 가능하지만, CPP에서는 BP의 값을 참조할 수 없다.

즉, Dependency면에서 CPP는
계층구조를 명확하게 디자인해야하는 게임의 핵심 시스템에 사용하는 것이 좋다.


Unreal Engine에서는, 2가지 규칙이 존재한다.
1. BP에서는 CPP를 자유롭게 참조할 수 있지만,
2. CPP에서는 BP를 인식하지 못해서 참조할 수 없다. 직접 파일을 참조하는 하드코딩 제외

이런 2가지 규칙을 깨지 않으면서, 아래와 같은 구조를 만들면,
CPP에서도 BP를 조금이나마 참조할 수 있게 된다.


CPP

  • Performance
    BP의 오버헤드를 보았듯이 CPP는 극한의 런타임을 구현할 수 있다.

  • Fundamental Code
    BP의 기초가 되는 코드이고 CPP는 견고하다.
    엔진의 세부적인 기능까지도 접근하고, 사용자지정하여 설정할 수 있다.

  • Extra Libraries
    가장 간단하면서 강력한 기능이다.
    Third Party Libraries를 추가하여 간단히 여러 기능들을 구현할 수 있다.

  • Diffing and Merging
    협업에서 중요한 기능으로,
    BP에서는 명확하게 뭐가 추가되었고, 뭘 병합해야하는지 파악하기 힘들다.
    BP는 병합하기도 상당히 어렵고, 수작업으로 수정해야한다.
    CPP코드는 몇번째 줄이 추가되고 명확하기에 형상관리에 특화되었다.


BP

  • Assets / Visual Effects
    CPP에서는 파일을 가져올때 이름만 적게되는데, BP로 구현하면 시각적으로 보면서 작업가능.

  • Laten Function / TimeLine&Lerp
    CPP에서는 가능은 한데 타이머와 콜백을 사용하는데에 제한이 존재.

  • Speedy Modify
    플레이중에 캐릭터의 스탯값등을 바로바로 바꾸는 등, 테스트하기가 용이하다.

  • Easy to Understand
    CPP가 미숙한 디자이너와의 소통 등 코드가 더 직관적이다.

  • Can Search Quickly
    검색기능을 사용하면, 알아서 다른 객체가 자동으로 뜨는 기능이 매우 유용하다.


결론

CPP든 BP든 게임을 구현할 수 있다
그냥 취향차이이고, 게임만 잘 돌아간다면 문제없다.

하지만, 협업하고 유지보수하는 관점에서는 CPP가 더 유용하고,
시간과 개발 비용을 절약하기 위해서
CPP만 사용하는 것보다 BP를 적절히 섞는 것도 필요하다.

추가 링크
https://forums.unrealengine.com/t/do-you-use-bp-or-c/95487/12

profile
Time Waits for No One

0개의 댓글