Making A Custom Node Class
Sorry, this document is still not translated into English!
커스텀 노드 시스템은 플러그인에 기본적으로 제공되는 노드 외에 사용자가 원하는 기능이 추가되어있는 노드를 새롭게 정의할 수 있게 해주는 시스템입니다.
복잡하게 c++ 네이티브 코드를 작성할 필요 없이, 단순히 노드 클래스로부터 자손 블루프린트 클래스를 만들고 새로운 기능을 정의하고 프로퍼티를 마킹하는 것 만으로 우리가 만든 노드 클래스를 다이얼로그 매니저 상에서 사용할 수 있습니다.
이 문서에서는 블루프린트를 통해서 어떻게 새로운 노드를 정의하는지를 알아봅니다.
[!Info] 이 문서에서 다룰 노드 개발 방법과 노드의 작동 방식은 플러그인에서 기본 제공하는 다이얼로그 노드에도 같은 방식으로 사용되었습니다. 물론 기본제공 다이얼로그 노드들은 Native 코드와의 연계 및 확장성을 위해서 c++를 통해 제작이 되어있으나, 이 문서에서 블루프린트를 이용해 제작하는 것과 같은 방법과 로직 및 함수를 이용해 작동됩니다.
새로운 다이얼로그 노드 클래스 만들기
이 튜토리얼에서는 다이얼로그 위젯 플레이 도중 별도의 미니게임을 표시하는 커스텀 다이얼로그 노드를 개발해봅시다.
우선 블루프린트 추가 버튼을 눌러 기존에 플러그인에 존재하는 노드 클래스에서부터 새로운 노드 클래스를 파생하는 것으로부터 시작합시다.
모든 종류의 노드 클래스를 사용 할 수 있지만, 가장 자주 사용되는 클래스는 다이얼로그 노드 베이스 클래스 입니다.
다이얼로그 노드 베이스 클래스들의 종류는 다음과 깉습니다 :
- [[다이얼로그 노드 베이스]]
- [[다이얼로그 노드 베이스 콘텍스트]]
전자는 대사가 없는 노드를 개발하기에 좋으며 (랜덤 노드, 익스큐 트 노드, 브랜치 노드 등)
후자는 대사가 있는 노드를 개발하기에 좋습니다. (모놀로그 노드, 셀렉트 노드 등)
우리는 대사를 프린트하는 기능이 필요하지 않으므로, [[다이얼로그 노드 베이스]]를 활용하여 개발해보겠습니다.
그래프 노드에서부터 노드 인스턴스로 데이터 받기
거창하게 제목을 붙혔지만 실제로는 그냥 그래프상에 놓여진 노드 위젯에서 핀 혹은 노드 위젯 자체에 액션이 가해졌을때 이를 감지하고 반응하여 우리가 원하는 데이터를 처리할 수 있게 해주는 작업입니다.
우선, 노드에 핀을 하나 추가해줍시다.
CustomPins 프로퍼티에 새로운 엘리먼트를 추가하고, PinName 을 output으로, PinCategory 를 DialogueOut 으로, PinDirection을 EDPD_Output으로 설정합니다.
[!Info] PinName은 말그대로 핀의 표시 이름을 나타냅니다. PinCategory는 핀의 디자인 카테고리를 나타냅니다. 플러그인에서 기본적으로 지원하는 카테고리는 다음과 같습니다 : PinDirection은 핀의 생성 방향을 나타냅니다. Input일시엔 노드의 왼쪽에 입력 핀으로,Output 일시엔 노드의 오른쪽에 출력핀으로 형성됩니다.
이 핀은 우리의 미니게임이 다 끝난 뒤에 재생할 다이얼로그 노드들과 연결 될 핀입니다.
이렇게 하면 그래프상에 표시된 노드에 핀이 자동으로 하나 생겨나는걸 볼 수 있습니다.
원한다면 후술할 OnCustomGraphNodeUpdated 함수에 우리가 원하는 데이터에 따라서 자동적으로 핀 데이터를 넣어서 핀이 생겨나도록 하는 로직을 부착하여 동적으로 핀을 생성 및 제거 할 수 있습니다. (예 : Answer 프로퍼티에 따라서 자동으로 핀을 생성하는 셀렉트 노드)
이제 우리가 만든 노드의 핀에 새로운 노드가 연결되거나 떨어질때 연결된 노드들의 리스트 업데이트를 위해서 OnCustomGraphNodeUpdated 함수를 오버라이드 하겠습니다.
이 함수는 핀 데이터와 그 핀에 연결된 노드들을 담은 맵을 제공합니다. 우리는 여기에서 우리가 만든 output 핀에 연결된 노드들을 업데이트시에 따로 저장하겠습니다.
NextNodes 라는 이름의 컨테이너를 하나 만들어서 다음과 같이 노드들을 저장했습니다.
이렇게 하면, 이제 우리가 만든 output 핀에 노드가 부착될때 마다 노드 인스턴스가 이 핀에 부착된 노드들을 저장합니다.
런타임 로직 작성하기
이제 기본적인 노드 위젯과 노드 클래스의 상호작용 부분은 전부 작성했으니, 실제 노드의 인게임 액션을 구현해봅시다.
노드가 처음 실행될 때
우선 HandleOnSelectedAsNextNode() 함수를 재정의합니다. 이 함수는 만약 이 노드가 다이얼로그에서 재생 시도될 노드로 선정되었을 때 호출되며, 이 노드가재생될 때 실제로 재생 될 노드를 리턴해야합니다. 만약 다이얼로그 재생을 중단시키려면 null 포인터를 리턴하면 됩니다.
[!Info] 이렇게 구성된 이유는, 재생 될 노드로 선정된 노드 대신 다른 노드를 실행시켜야하는 경우가 있기 때문입니다. 랜덤 노드와 브랜치 노드가 대표적으로, 이들은 다음 재생 될 노드로 선정 되었을때 이 노드에 연결된 다른 노드를 대신해서 실행시킵니다.
우리같은 경우는 이 노드를 재생 시킬 것이므로, 자기 자신을 리턴합니다. 다만, 우리가 만든 노드는 재생시킬 텍스트가 없으므로, 다이얼로그 위젯은 이 노드를 만나는 즉시 다음 노드로 넘어가려고 할 것입니다. 따라서 이 함수에서 위젯을 일시정지 시키겠습니다.
[!Info] 왜 기본 동작이 멈추지 않고 즉시 다음 노드로 넘어가는 동작이 기본 동작인지는 다이얼로그 노드 베이스 기반의 노드가 일반적으로 행하는 동작이 지속적이지 않고 즉발적이기 때문입니다. 익스큐트 노드, 브랜치 노드, 랜덤 노드 모두 즉발적으로 액션을 취한 뒤 다음 노드로 넘어가려하지 지속적으로 위젯을 멈춰두지 않습니다.
그 후엔 미니게임 역할을 해줄 위젯을 소환하고 다이얼로그 위젯의 레퍼런스를 넘겨주고 화면에 부착한 뒤, 다이얼로그 위젯을 숨기겠습니다.
아, 그리고 미니게임 역할을 해 줄 위젯의 클래스를 하드코딩 하지 않고, 다이얼로그 매니저의 노드상에서 지정해주고 싶네요. 그럴땐 프로퍼티를 하나 만들어서 퍼블릭으로 마킹해주면 정상적으로 매니저 에디터 상에서 표시 및 수정이 가능해집니다.
데이터를 실제로 넣는건 이따가 보여드리겠습니다.
미니게임 부분
이제 미니게임 위젯에 들어가, 미니게임 로직을 만들었습니다. 예제에서는 귀여운 팝 캣 게임을 만들었습니다.
게임을 그만하고 싶으면 우측 상단에 있는 종료 버튼을 누르면 됩니다. 종료 버튼을 누르면 미니게임 위젯을 제거합니다. 그리고 그 전에 다이얼로그 위젯을 다시 화면에 표시하고, 일시정지를 해제한 뒤에 다음 노드로 넘어가게끔 MoveToNextNode 함수를 호출 했습니다.
이제 미니게임 파트는 전부 끝났습니다.
노드가 종료될 때
다시 다이얼로그 노드로 돌아와서, 이제 이 노드의 실행이 끝났을 때, 다음 노드로 넘어갈때 어떤 노드를 실행 시켜야 하는 지를 결정하기 위해서 SelectNextNodeFromThisNode 함수를 재정의합시다. 이 함수에는 이 노드의 재생이 끝나면 다음으로 재생할 노드를 리턴해야합니다. 널 포인터를 리턴함으로서 다이얼로그를 끝낼 수 있습니다.
여기서 우리가 아까 저장해두었던 output 핀에 연결된 노드들을 실행시켜봅시다.
다이얼로그 노드 베이스 클래스엔 실행시킬 노드를 일괄적으로 컨디션 테스트하여 선발된 노드를 리턴하는 TestChildNodes 함수가 있습니다. 여기에 아까 저장한 노드들을 넣어주면 알아서 노드 우선도에 따라 다음으로 실행될 노드를 리턴해줍니다.
이제 이걸 함수 리턴에 넣어주면 됩니다.
커스텀 노드 활성화 하기
아, 그리고 아주 중요한 부분이 있습니다. 마지막으로 노드 클래스의 bIsCustomNode 프로퍼티를 true로 설정해줍니다.
그래야만 이 노드가 다이얼로그 매니저 에디터상에서 정상적으로 표시됩니다.
재생해보기
이제 우리가 만든 노드를 다이얼로그 매니저에 넣어보고 실제로 재생해봅시다.
우리가 만든 커스텀 노드를 추가 했습니다. 멋있군요.
우리가 플레이할 미니게임도 지정해 주어야겠죠? 노드를 클릭하고 우리가 만든 미니게임 위젯 클래스를 넣어주었습니다. 이렇게 노드 클래스에 선언된 퍼블릭 프로퍼티는 에디터에 표시가 되므로 우리가 임의로 데이터를 넣을 수 있습니다.
실행해보면 정상적으로 게임이 플레이 되는 걸 볼 수 있습니다.
[!note] 글자별 애니메이션 시스템도 있습니다. [[글자별 애니메이션 써보기]]] 튜토리얼을 확인해보십시오.