[UE5] 겹쳐진 widget blueprints에서 Click 처리 - Z-Order, Visibility, InputMode (ProjectVT 개발기)
팀 프로젝트로 출시를 위해 개발하고 있는 게임은 3D가 아닌 2D 기반 게임이다. 2D 환경을 위한 다른 플러그인을 사용하지 않고 UI, 게임화면, 캐릭터, 대화창 등을 모두 위젯 블루프린트로 구현하고 있다.
이전 다른 게임을 만들 때, 위젯 블루프린트는 단순하게 체력바, 게임시작 메뉴, 게임 종료 안내처럼 나누어진 공간을 차지하여 겹쳐지는 경우가 없었다. 하지만 이번에는 배경이 되는 위젯에 대화, 옵션, 설정, 확인창 위젯이 위로 계속 쌓이고 그에 따라 User input이 어떻게 처리되어야 하는지가 복잡하였고 구현상에서도 어려움을 겪었다. 이에 대해 포스팅을 해보려 한다.
테스트를 위한 Level과 위젯블루프린트를 만들자.
Canvas Panel안에 Image와 Button1을 배치하였고 Button1은 OnClicked 이벤트에 Button1이 클릭되었다는 메시지를 화면에 출력하게끔 설정해 두었다.
테스트하기 위한 레벨은 BeginPlay에서 위젯 블루프린트를 생성하고 Viewport에 추가한다.
레벨을 play하고 버튼을 클릭하면 당연히 정상적으로 버튼이 클릭되었다는 메시지가 출력된다.
Z-Order
이번에는 Button1을 image보다 Hierarchy에서 위에 오도록 배치하였다.
위젯 블루프린트의 Hierarchy는 아래에 있을수록 화면상에서 더 위에 배치되기 때문에 이미지가 버튼을 가리는 것을 볼 수 있다. (이미지 뒤에 있다는 것을 표현하기 위해 버튼의 크기를 늘렸다)
레벨을 실행하고 이미지가 버튼을 가린 부분을 클릭해도 메시지가 출력되지 않는다. 버튼이 이미지 밖으로 나와있는 부분(회색)을 클릭하면 메시지가 정상적으로 출력된다.
이는 Z order와 관련이 있다. Z order는 Canvas Panel Slot의 프로퍼티로 겹쳐있는 오브젝트들의 순서를 결정하는 인덱스이다. 위젯 블루프린트에서 만든 오브젝트들의 Z order의 초기값은 0으로 되어있다.
앞서 Button1과 Image의 Z order값도 0인 것을 확인할 수 있다.
언리얼 엔진의 위젯 블루프린트는 ZOrder가 동일할 경우 Hierarchy 창에서 더 아래에 있는 오브젝트가 더 위에 위치하도록 조정한다. Button의 ZOrder를 1로 변경하면 ZOrder가 0인 이미지보다 위에 위치하게 된다. (Hierarchy 상에서는 여전히 더 위에 있음에도)
아래와 같이 Image가 Button의 child로 배치되어 있는 경우에는 Image 영역을 클릭하여도 Button이 클릭되었다는 메시지가 출력된다.
클릭 이벤트를 가져가는 버튼을 알아보기 위해 두 개의 버튼을 겹쳐두고 겹친 영역을 클릭하면 ZOrder가 커서 나중에 렌더링 된 파란 버튼만 클릭되었다는 메시지만 출력된다.
Visibility
ZOrder를 조정하여 더 위에 위치한 오브젝트가 클릭을 가져가도록 할 수 있다는 것을 알았는데 시각적으로 위에 있으나 클릭이 필요하지 않은 오브젝트가 있을 때는 어떻게 해야 할까?
개발하면서 화면 전체에 효과(그라데이션 )를 주기 위한 위젯 또는 컴포넌트가 있는 상황, 사용자에게 클릭되기를 원치 않는 팝업이 존재하는 상황이 있었는데 Visibility를 조정하여 이를 해결할 수 있었다.
Image의 Visibility 속성을 보면 아래처럼 5개 중 하나를 선택할 수 있다
- Visible: Visible and hit-testable (can interact with cursor) - 보이고 클릭 가능
- Collapsed: Not visible and takes up no space in the layout (obviously not hit-testable) - 보이지 않고 layout에서 공간을 차지하지 않으며 클릭 불가능
- Hidden: Not visible but occupied layout space (obviously not hit-testable) - 보이지 않고 layout에서 공간을 차지하나 클릭 불가능
- Not Hit-Testable (Self & All Children): Visible but not hit-testable (cannot interact with cursor) and children in the hierarchy are also not hit-testable - 보이지만 클릭 불가능, child까지 포함
- Not Hit-Testable (Self Only): Visible but not hit-testable (cannot interact with cursor) and doesn't affect hit-testing on children.- 보이지만 클릭 불가능, chlid 제외
위 5가지 Visibilty를 테스트해보기 위해 아래와 같이 예시 위젯을 변경하였다. 각 버튼을 OnClicked 이벤트에 메시지 출력을 연결해두었다.
버튼을 4개 배치하였고 가장 위에는 Opacity가 0.5인 Image를 배치하였다.
Image가 Visible일 경우에는 클릭이 가능한 오브젝트가 가장 위에 있기 때문에 아무 버튼도 클릭할 수 없다.
Image가 Collapsed, Hidden일 경우 Image는 보이지 않으며 버튼도 정상적으로 클릭 가능.
Image가 Not-Hit Testable일 경우에는 Image가 보이나 버튼은 정상적으로 클릭이 가능하였다.
나머지 속성에 대해 자세히 알아보기 위해 Image를 제거하고 Layout을 관찰해보려 한다.
먼저 Layout에서 공간을 차지하는지 알아보기 위해 Vertical Box에서 ButtonRed, ButtonBlue, CanvasPanelInside 3개의 child를 두었으며 Size를 Fill로 설정하여 다른 child가 공간을 차지하지 않으면 자동으로 더 큰 공간을 차지하도록 하였다.
CanvasPanelInside의 기본 visibility는 Not Hit-Testable (Self Only)로 되어있는데 이는 내부에 child를 배치하는 바탕이 되는 Canvas panel의 특성 때문으로 보인다.
이를 Visible로 바꾸고 CanvasPanelInside의 Child인 ButtonYellow, ButtonGreen을 클릭해 보았다.
위에서 Button의 child로 Image를 두고 클릭했던 테스트의 결과와 동일하게 Parent가 Visible이어도 Child는 모두 정상적으로 Click 이벤트를 처리한다.
다음으로 CanvasPanelInside의 Visibility를 Hidden, Collapsed로 바꾸고 나서 레벨을 실행시켜 보았다.
Hidden에서는 Vertical box 안에서 공간을 그대로 차지하지만 보이지 않고 클릭도 되지 않는 것을 볼 수 있으며 Collapsed에서는 Vertical box에서 공간을 차지하지 않아 Red, Blue button이 전체를 채운 것을 볼 수 있다.
두 경우 모두 설명대로 Child인 Yellow, Green 버튼의 클릭이 불가능하였다.
다음으로 Not Hit-Testable (Self & All Children) / Not Hit-Testable (Self Only)로 CanvasPanelInside의 Visibility를 설정하고 테스트해보았다.
두 설정 모두 오브젝트가 눈에 보이기 때문에 아래 화면을 동일하게 렌더링 하였으나 Self & All Children에서는 child인 Yellow, Green 버튼의 클릭이 불가능하였다.
Input Mode
블루프린트에는 Left Mouse Button이라는 이벤트로도 클릭이벤트를 다룰 수 있는데 이는 Player Controller와 관련 있는 이벤트다. 이에 대해 예시를 통해 알아보자.
기본으로 Input Mode는 Game And UI로 설정되어 있는데, 이는 UI가 player의 input을 처리하지 않았을 때 Controller가 그 input을 처리하는 방식이다.
실험을 위해 아래 가운데 부분을 비워두어 UI가 player input을 처리하지 않는 공간을 만들었다.
레벨을 실행하고 버튼들을 누르면 정상적으로 눌리며 버튼이 눌렸다는 메시지가 출력된다. 하지만 Left Mouse Button Pressed 이벤트에 연결한 "Mouse Click" 메시지는 출력되지 않는다.
UI가 player input을 처리하지 않는 가운데 검은 부분을 클릭하면 Mouse Click 메시지가 출력되며 마우스 커서가 사라진다.
이번에는 레벨에서 Input Mode를 Game Only로 아래와 같이 설정해보았다.
버튼을 눌렀음에도 위젯 블루프린트에서 설정한 메시지가 아닌 "Mouse Click" 메시지만 출력된다. UI가 아닌 Player Controller만 유저의 Input을 다루게 된 것이다.
마지막으로 Input Mode를 UI Only로 설정하면 반대로 버튼을 눌렀을 때 위젯 블루프린트에서 설정한 메시지가 정상적으로 출력되며 가운데 비어있는 부분을 클릭하여도 Player Controller가 이를 처리하지 않기 때문에 Mouse Click이라는 메시지가 출력되지 않는다.
정리
OnClicked에 정확히 함수를 구현해두었는데도 아무런 반응이 없었던 문제를 많이 겪었고 이를 해결하기 위해 찾은 자료들을 모아서 정리해보았다.
Z Order, Visibility, Input Mode를 고려하면서 개발하였더니 2D 게임처럼 위젯 블루프린트가 쌓여있는 상황에서도 원하는 오브젝트가 Input을 정확히 처리하도록 할 수 있었다.
Reference