May 5, 2014

블루프린트의 복잡도 관리

저자: Michael Noland 홍성진 번역

블루프린트로 대규모 프로젝트를 제작하다 보면, 넘실대는 노드의 바다에 빠져버리는 경우가 허다합니다.  그 혼돈을 겪지 않도록 돕고자, 여러가지 다양한 캡슐화 및 코드 재사용 메커니즘이 내장되어 있습니다.

무언가를 캡슐화시킨다는 것은, "(무언가의) 주요 개념이나 품질을 간단한 방식으로 표시 또는 표현하는 것"을 말합니다. 다른 말로는, 노드의 복잡한 시퀸스를, 의미와 개념이 같은 간단한 대역으로 대체하는 것입니다.  물론 파고들어가 보면 내부적으로 어떻게 작동되는지 확인할 수는 있지만, 큰 그림에서 볼 때는 세부적인 부분을 걱정할 필요가 없습니다.

코드 재사용은 주로 캡슐화와 함께 짝을 이루지만, 기본적으로는 작업 내용을 매번 복제할 필요 없이 다른 상황에 같은 개념(노드 세트)을 적용하는 방식입니다.  같은 작업 내용을 매번 복제해야 한다면 확실히 노력이 많이 드는 일이고, 버그나 기능상의 변화가 있다면 각각의 사본마다 별도로 작업을 해 줘야 할 것입니다.

여러가지 접근법의 장점과 단점을 비교해 보면 이렇습니다:

 

함수

이벤트

매크로

접힌 그래프

실행 경로

하나

하나

아무거나

아무거나

비실행 출력

아무거나

없음

아무거나

아무거나

잠복성 동작

아니오

예*

컴포넌트/타임라인 추가

아니오

아니오

예*

기타 이벤트

아니오

사용불가

아니오

예*

* 접힌 그래프는 그것이 들어있는 그래프의 한계를 이어받습니다. 예를 들어 함수 속에 들어있는 접힌 그래프는 잠복성 동작이나 타임라인을 포함할 수 없습니다.

접힌 그래프

선택된 노드들 중 하나에 우클릭한 다음 'Collapse Nodes' (노드 접기)를 선택하면 접힌 그래프를 만들 수 있습니다. 선택된 세트 밖의 노드에 연결된 와이어는 새로이 접히는 노드의 입력이나 출력이 됩니다. 접힌 노드 위에 마우스 커서를 올리면 접힌 그래프에서 노드 미리보기를 확인할 수 있습니다.

Collapsed Graph Node, hover over it to see a preview of the graph

접힌 노드에는 현재 맥락상 허용되는 어떠한 종류의 노드도 들어갈 수 있으며, 그 입력/출력에 제한이 없습니다.  접힌 그래프가 포함할 수 있는 노드에 제한이 없다니 최고인 것 같아 보일 수는 있지만, 단지 캡슐화만일 뿐, 코드 재사용은 가능하지 않습니다.  접힌 그래프를 복사/붙여넣기 하면, 그 안의 모든 노드 역시도 복제되므로, 원본에 대한 참조가 아니라 접힌 그래프가 새로 생겨버립니다.

함수와 이벤트

'내 블루프린트' 툴바의 '함수 추가' 버튼을 사용해서 빈 함수를 만들거나, (조건이 맞는 경우) 선택된 노드들 중 하나에 우클릭한 다음 'Collapse to Function' (함수로 접기) 옵션을 사용하여 함수로 변환할 수도 있습니다.  그래프 맥락 메뉴에서 'Add Custom Event...' (Custom Event 추가)를 사용하여 새 이벤트를 만들 수도 있습니다.  함수는 내 블루프린트 목록에 별도의 그래프로 나타나는 반면, 이벤트는 여러가지 이벤트를 포함할 수 있는 이벤트 그래프에 들어갑니다.

함수와 이벤트 둘 다 C++ 로 정의된 함수를 호출하듯이 블루프린트 내 다른 곳에서 호출 가능합니다. 둘 다 내부적으로 분기나 루프를 가질 수는 있지만, 외부 호출자의 관점에서 보면 하나의 실행 경로로 정의됩니다. 이벤트의 경우, 잠복성 동작을 통해 실행 흐름을 늦추거나, 심지어 다른 이벤트의 흐름에 병합시키는 것도 가능합니다.

Event DeclarationEvent or Function Call

함수는 그 안에 어떠한 유형의 노드를 배치시킬지 제한(, 즉 잠복성 동작, 타임라인 등을 전부 금지)시켜 즉시 실행 및 반환되도록 만들 수 있습니다. 이를 통해 이벤트나 매크로로는 가능하지 않을, C++ 호출자에게 값을 반환하는 것이 가능합니다.

함수와 이벤트를 통해 C++ 에서 블루프린트로의 호출이 가능하기도 합니다. C++ 에서 함수를 BlueprintImplementableEvent 로 정의하면 블루프린트에서 구현이 가능해 집니다.  이러한 함수들에는 작동방식이 내장되어 있지 않아서 블루프린트 구현 없이 호출하면 아무런 작업도 하지 않지만, BlueprintNativeEvent 로 선언하는 경우 C++ 정의도 같이 줄 수 있습니다.  이 UFUNCTION() 키워드는 이벤트만 취급하긴 해도, 반환값의 유무에 따라 블루프린트에서 구현시 블루프린트 안에서 이벤트 또는 함수로 변환될 것입니다.

매크로

'내 블루프린트' 툴바의 'Add Macro' (매크로 추가) 옵션을 사용하여 빈 매크로를 만들거나, 선택된 노드들 중 하나에 우클릭한 다음 'Collapse to Macro' (매크로로 접기)를 사용해서 매크로로 변환할 수도 있습니다. 블루프린트 매크로 라이브러리를 생성하여 다수의 블루프린트에 매크로를 공유할 수도 있습니다. 블루프린트 코드 재사용에 있어 가장 효율적인 수단 중 하나가 됩니다. 앞으로의 글에서는 매크로와 매크로 라이브러리에 대해 보다 심도있게 다루도록 하겠습니다.

Macro Instance

매크로는 임의의 입력과 출력은 물론 실행 와이어를 가질 수 있습니다.  매크로는 블루프린트에서 함수나 이벤트와 같은 방식으로 호출 가능하나, C++ 코드에서 보이지가 않습니다. 접힌 그래프처럼 매크로는 컴파일된 블루프린트에 실제로 존재하지 않으며, 모든 인스턴스는 컴파일 도중 고유의 노드 세트로 펼쳐집니다.

매크로 인스턴스는 하나 이상 있을 수 있기에, Custom Event 같은 것들은 매크로 안에 금지됩니다. 어느 것을 (또는 어느 순서로) 실행시킬지 모호할 수가 있기 때문입니다. Timeline 과 Add Component 노드 역시도 현재 구현상의 세부사항 때문에 금지되어 있으나, 앞으로 허용할 계획입니다.

코멘트

코멘트는 기본적으로 현재의 자신이 미래의 자신에게 보내는 선물입니다. 의도가 무엇이었는지, 또는 잠재적인 문제점이나 앞으로 해야 할 작업을 기록해 두는 것입니다.

Screenshot on Comments

C 키를 누르면 선택된 노드 주변에 코멘트 박스를 두를 수 있습니다.  기본적으로 이 박스를 움직이면 포함된 노드도 같이 이동됩니다만, 디테일 패널에서 그 작동방식은 물론 색도 변경할 수 있습니다.  코멘트에 더블클릭하거나 F2 키를 누르면 여느 제목줄처럼 편집할 수 있습니다.  다른 개별 노드의 코멘트도 맥락 메뉴의 칸을 통해 달아주면 노드 위에 말풍선처럼 나타나게 됩니다.

마지막으로 'Blueprint Property' (블루프린트 프로퍼티)의 디테일 패널에서 'Blueprint Description' (블루프린트 설명) 편집을 통해 콘텐츠 브라우저에서 블루프린트를 볼 때 툴팁으로 나타나는 코멘트를 작성할 수 있습니다.  썸네일 미리보기가 없는 게임플레이 블루프린트에 정말 유용한 기능이긴 하지만, 썸네일이 있는 레벨 소품 같은 것에도 활용 노트를 추가해 주는 것이 좋습니다.

질문이나 남기실 코멘트가 있는 경우,  언리얼 엔진 포럼 또는 트위터에서 @joatski 를 찾아주시기 바랍니다.