안녕하세요.
오히려 구체적으로 질문을 주시어 내용을 이해하는데 큰 도움이 되었습니다.
현 상황에 대해서 조금 납득하기 어려운 부분이 있으실 것으로 예상되지만, 현재 이러한 부분들은 의도된 개발 방향이라는 답변을 들어 이를 전달드립니다.
송구하지만 조금 더 구체적으로 주신 내용들을 통해 설명드려보면 다음과 같습니다.
현재 작업중인 동작에 대해서 설명을 드리면 HUD 용 위젯을 화면에 띄웠을때 개발내 테스트 동작을 위해서 Hud Widget 에 BP 에서 AnyKey 바인딩같은 Key Event 액션에 대해 특정한 개발용 함수를 호출하게 하였습니다. 그런데 이게 최초로 Widget 이 화면에 띄워지는 경우에는 해당 Widget 의 BP 에서 제대로 Key Event 처리가 됩니다. 위젯을 띄울때는 InputMode 를 GameAndUI 이걸로 세팅하였습니다.
=> 전달주신 내용에서 Key Event는 앞서 말씀드렸던 GamePlay Event에 속합니다. 따라서, Input Mode를 GameOnly, GameAndUI 둘 중 어떤 것을 설정하셔도 이벤트를 받을 수 있도록 활성화됩니다.
그리고 실제 내부 시스템 상에서는 어떠한 경우에서도 이벤트를 받는 리스너는 Player Controller지만, Player Controller 내에는 Input Stack이라는 형태로 본인 것을 제외한 외부의, 즉 여기서는 Widget BP에서의 Input Component를 들고 있게 됩니다.
Widget BP가 다수가 있을 경우 Stack의 FIFO(First In First Out) 자료구조의 특성상 가장 최근에 등록된 Widget BP가 우선권을 가져가게 됩니다.
한가지 부가적으로 말씀드릴 사항으로 Widget BP에는 Set Input Action Blocking이라는 설정 함수를 두고 있습니다.
기본적으로 해당 설정은 False로 되어있으며, False에서는 Widget BP상에서 정의한 이벤트만 처리되고 나머지들은 그 후순위의 리스너에서 처리되도록 하고 있습니다.
예를 들어, 문의주신 상황에서 Player Controller에는 Key 1, 2에 대한 이벤트를 정의하고 있고 Widget BP에서는 2에 대한 이벤트만 정의하고 있다면,
Widget BP에서는 2의 이벤트가 처리되고, Player Controller는 1의 이벤트만 처리할 수 있는 상태가 됩니다.
참고로 해당 설정값을 True로 설정하실 경우, Widget BP의 이벤트만 처리되고 후순위 이벤트들은 모두 생략하도록 동작하고 있습니다.
제가 겪고 있는 문제는 PlayerController 에서도 KeyEvent 처리를 하게 되는 경우 동작에 혼선이 오는 경우입니다.
다시 설명을 드리면 BP_PlayerController 에도 KeyEvent 처리를 하는게 있고 해당 Hud Widget 의 BP 에서도 KeyEvent 처리를 하는 동작이 있는데 위젯이 처음에 띄워질때는 Widget 의 KeyEvent 가 PlayerController 보다 먼저 처리되고 위젯을 RemoveFromParent 로 삭제한후 다시 위젯을 띄우게 되면 PlayerController 의 KeyEvent 처리가 먼저 되는 상황입니다.
=> Widget의 KeyEvent 처리가 등록되는 시점은 혼란스러워시겠지만, Add to Viewport 시점이 아닌 Create Widget 시점입니다.
조금 더 정확하게 말씀드려보면 On Initialized 시점에 이러한 이벤트 등록처리가 진행되고 있습니다.
실제로 Create Widget 이후 Add to Viewport를 실행하지 않더라도 생성된 Widget에서의 Key Event가 호출되는 것을 확인할 수 있습니다.
Remove from Parent 시점에는 Destruct가 호출되면서 등록된 이벤트들을 해제하면서 내부의 이벤트 리스너 용 모듈인 Input Component 역시 삭제 처리하고 있습니다.
이후 Add to Viewport로 다시 가시화는 가능하나, 이때는 On Initialized를 호출하지 않기에 이벤트 리스너가 활성화되지 않게 되고 있습니다.
이 상태에서는 기존의 리스너였던 Player Controller가 지속적으로 이벤트 리스너로써의 역활을 수행하게 됩니다.
만약 이벤트 리스너로써의 동작의 일관성(항상 Widget이 보여질 때, 이벤트를 처리하도록)을 유지하시기 위해서는 Create Widget > Add to Viewport의 전체 초기화 단계를 다시 진행하는 것이 필요합니다.
이것이 언리얼에서 의도한 동작인건지 아니면 문제가 되는 상황인건지 그것이 궁금합니다.
=> 납득하시기 어려운 내용들이 많을 것으로 보입니다.
다만, 해당 내용을 개발팀에 문의해본 결과 이는 의도된 내용이라는 답변을 들을 수 있었습니다.
저희쪽 EGK 내부에서도 해당 디자인을 검토 중에 있으며, 그 결과에 따라 에스컬레이션해서 관련 디자인에 대한 변경요청하는 것을 고려하고 있습니다.
이러한 과정에는 다소 시간이 소요될 수 있다는 점에 대해서도 거듭 양해의 말씀을 드립니다.
추가로 의도한 동작이라면 어떠한 조건으로 우선순위가 설정되는건지 알고 싶습니다.
=> 지금까지 전달드린 내용들이 모두 관련되어 있어, 내용들을 한번 정리하여 전달드려보면 다음과 같습니다.
- Key Event는 GamePlay Event의 하나로 Player Controller의 Input Mode가 Game 또는 GameAndUI일 경우 활성화 됨
- Key Event의 정의를 Widget BP에 하더라도 실질적으론 Player Controller에서 모든 리스너들을 관리하고 있음
- 가장 마지막에 생성된(Create Widget) Widget BP에서 이벤트에 대한 가장 높은 우선권을 가짐
- Create Widget 후, Add to Viewport하지 않더라도 이벤트 리스너로써의 동작은 등록됨
- 생성된 Widget BP의 Set Input Action Blocking 기본값은 False로, 본인이 정의하고 있는 Key Event를 처리하고 나머지는 후순위의 리스너로 넘김
- Widget BP에서 Set Input Action Blocking를 True로 변경 호출할 경우, 최상위 리스너인 Widget에서만 이벤트를 처리함
- Widget BP의 이벤트 리스너로써의 기능은 Remove from Parent가 호출될 때이며, 이후 다시 이벤트 리스너로 동작시키기 위해서는 Create Widget부터 다시 실행 필요
다시 한번 부족한 답변을 드리는 점 양해의 말씀을 드립니다.
내부적으로 관련 모듈의 디자인에 대한 검토 후 에스컬레이션이 진행될 경우 해당 내용의 진행 상황을 공유드려 볼 수 있도록 하겠습니다.
또한 전달드린 내용에서 모호한 점이나 추가 문의가 있으실 경우 말씀주시면 그에 대한 리서치를 진행할 수 있도록 하겠습니다.
감사합니다.