[CommonUI 3] Confirmation Dialogue Widget

김여울·2일 전
0

내일배움캠프

목록 보기
112/114

Confirmation Dialogue Widget - Unreal Common UI Tutorial Part 3

WBP_ConfirmationDialogue

Confirmation Dialogue (CommonText) Style 설정하기

Vertical Box & Button 2개 모두 중앙 정렬 맞추기

Vertical Box → Wrap with Common Border

Vertical Box 중앙 정렬하기

BorderStyle_Background

BorderStyle_Background 만들어서 Common Border에 적용하기

Confirmation Dialogue 위젯 배경 색깔 설정하기

WBP_ConfirmationDialogue

Button 두 개 모두 중앙 정렬하기

버튼 사이에 Spacer 넣고 Fill 채우기

Horizontal Box Top Padding을 20 추가해서 Dialogue Message와 간격 띄우기

함수 만들어서 ConfirmationDialogue 위젯을 뷰포트에 띄우기



WBP_MainMenu

Exit 버튼 누르면 WBP_ConfirmationDialogue 화면 나오게 하기

함수로 접기
Exit 버튼 누르면 WBP_ConfirmationDialogue 화면 나오게 하기

✅ Pure 함수로 전환

  • 블루프린트 함수(Function) 의 실행 방식(Execution type) 을 바꾸는 중요한 옵션
  • 실행 핀(흰색 선)이 없는, “부작용 없는 계산 함수”

Pure 함수

항목Non-Pure✅ Pure
실행 핀 (흰색)있음❌ 없음
데이터 핀 (파란색 등)있음있음
상태 변경가능❌ 없음 (읽기 전용)
실행 순서 의존있음❌ 없음
대표 예시Set Text, Add ChildGet Player Controller, Get Health, Calculate Damage

Pure로 만들면 생기는 장점

장점설명
✅ 노드 연결이 간결실행 핀이 필요 없어 선이 줄어듦
✅ 계산 함수처럼 즉시 사용 가능예: 다른 노드의 입력 핀에 바로 꽂기 가능
✅ 읽기 전용 함수로 안전내부 상태를 바꾸지 않음
✅ 블루프린트에서 "Get"류 함수로 직관적으로 사용 가능Getter 역할에 적합

Pure 함수로 만들면 안 되는 경우

  • 위젯 추가, 변수 변경, 애니메이션 재생 등 → 상태를 바꾸는 행위가 있으면 Pure ❌
  • Pure 함수는 실행 흐름을 제어할 수 없기 때문에 "한 번만 실행해야 하는 명령"에는 부적합

이런 건 Pure로 하면 안 됨:

Add to Viewport
Play Animation
Set Text
Spawn Actor

노란 박스 변수로 승격 → Default Value에 문구 입력

Exit 누르면 WBP_ConfirmationDialogue 위젯 호출

WBP_ConfirmationDialogue

배경에 블러 효과 추가하기

Border → Wrap with Backgroud Blur

블러 강도 5.0

YES / NO 버튼 기능 만들기 (이벤트 디스패쳐)

이벤트 디스패쳐 생성

Create Event의 Create a matching function



Remove from Parent

  • 언리얼 UMG(Widget) 안에서 현재 위젯을 화면에서 제거하는 함수
  • 이 위젯을 부모(화면)에서 떼어내서 더 이상 보이지 않게 한다 🧹

언리얼에서 UI 위젯은 계층 구조(Tree)로 구성:

Viewport
 └── MainMenu (UserWidget)
      ├── SettingsPanel (VerticalBox)
      └── ExitDialog (Overlay)

Remove from Parent는 이 중에서 자기 자신을 부모 컨테이너(Parent)로부터 제거하는 것

void UWidget::RemoveFromParent()
{
	if (UPanelWidget* Parent = GetParent())
	{
	Parent->RemoveChild(this);
	}
}
  1. 자신의 부모 위젯(PanelWidget 등)을 찾고
  2. 그 부모의 자식 리스트에서 자기 자신(this) 을 제거함
  3. 부모-자식 관계가 끊기면서 렌더링 대상에서도 빠짐

🚨 주의할 점

항목설명
❌ 파괴(Destroy) 아님단지 부모에서 분리만 되는 것, 메모리엔 여전히 남아 있음
✅ 재사용 가능나중에 AddToViewport()로 다시 붙이면 다시 보임
⚠️ 여러 부모 중복 불가하나의 위젯은 동시에 하나의 Parent만 가질 수 있음

WBP_MainMenu

노란색 부분 변수로 승격하고 이름 바꾸기

이미 존재하는 대화창(확인창)이 있어? → 그걸 반환
없어? → 새로 만들어서 변수에 저장한 뒤 반환

GetDialogue (pure)

1️⃣ GET — WBP Confirmation Dialogue 변수 확인

  • WBP Confirmation Dialogue 라는 변수는 확인창 (예: “Are you sure you want to exit the game?”) 위젯의 참조를 담는 변수
  • 이 변수를 Get 노드로 가져와서, Is Valid 로 “이미 만들어져 있는지”를 검사

🔍 의미: ****이미 존재하면 재사용하고, 없으면 새로 만든다.

2️⃣ Is Valid 분기

  • Is Valid → “이 변수가 null(=없음)이 아닌가?” 검사
  • True (Valid) → 이미 만들어져 있으니 그대로 반환
  • False (Not Valid) → 새로 만들어야 함

3️⃣ Get Owning Player

  • 현재 이 위젯(WBP_MainMenu)을 띄운 플레이어 컨트롤러를 가져옴
  • 새 위젯을 생성할 때 “누가 소유자인지” 지정하기 위해 필요

🔍 의미: “이 확인창은 어떤 플레이어의 화면에 표시될 것인가?”

4️⃣ Create WBP Confirmation Dialogue Widget

  • 확인창 위젯(WBP_ConfirmationDialogue)을 새로 생성하는 노드
  • Owning Player 핀에는 방금 구한 Get Owning Player 결과를 연결
  • 실행 결과(Return Value)가 새로 생성된 위젯 인스턴스가 됨

5️⃣ SET — 변수에 저장

  • 새로 만든 확인창 위젯을 WBP Confirmation Dialogue 변수에 저장합니다.
  • 이렇게 하면 다음번 GetDialogue() 호출 시, 이미 존재하는 동일 인스턴스를 재사용할 수 있습니다.

🔍 의미: “다음에 또 필요하면 새로 만들지 말고 이걸 써라.”

6️⃣ Return Node

  • 마지막으로 WBP Confirmation Dialogue 변수를 반환
  • 즉, 기존 것이든 새로 만든 것이든 결과적으로 사용 가능한 대화창 위젯 참조를 반환

🌊 전체 흐름

GetDialogue()
│
├── [Get] WBP Confirmation Dialogue
│      ├── If Valid → 바로 반환
│      └── If Not Valid → 새로 생성
│
├── [Get Owning Player]
├── [Create WBP Confirmation Dialogue Widget]
├── [Set] WBP Confirmation Dialogue = 새 위젯
│
└── Return (WBP Confirmation Dialogue)

👍🏻 장점

항목설명
✅ 효율적이미 생성된 위젯을 재사용하므로 불필요한 CreateWidget 호출 방지
✅ 안정적null 참조 오류 방지 (IsValid 체크로 안전함)
✅ 유지보수 용이언제든 동일한 함수로 “대화창 가져오기” 가능
✅ 깔끔한 코드GetDialogue() 한 줄로 필요한 위젯 확보 가능

MB_Exit 버튼 클릭 시 “종료 확인 다이얼로그”를 띄우는 로직

Unbind All Events from Input Dispatch 노드 추가

  • 다이얼로그 위젯 안에서 이전에 연결되어 있던 입력(버튼 클릭 등) 이벤트 바인딩을 모두 해제하는 역할
(1) Exit 버튼 클릭
      ↓
(2) GetDialogue() → 기존 다이얼로그 위젯 가져오기 (없으면 생성)
      ↓
(3) ShowDialogue() → 메시지 표시 : “정말 종료하시겠습니까?”
      ↓
(4) UnbindAllEventsFromInputDispatch() → 기존 콜백들 제거
      ↓
(5) CreateEvent(OnExitConfirmation) → 새로운 콜백 준비
      ↓
(6) BindEventToInputDispatch() → 새 이벤트(Exit YES/NO) 바인딩

1️⃣ Get Dialogue

  • 아까 만든 Lazy Initialization 함수 (GetDialogue)를 호출해서
    WBP_ConfirmationDialogue 인스턴스를 가져옴
  • 없으면 새로 생성하고, 이미 있으면 기존 걸 재사용 → 즉, 다이얼로그 창 위젯을 확보하는 단계

2️⃣ Show Dialogue

  • 실제로 다이얼로그를 화면에 표시하는 커스텀 함수
  • Message 핀에는 표시할 텍스트 (Exit Message = “Are you sure you want to exit the game?”)가 들어감
  • Target은 WBP_ConfirmationDialogue 위젯

"확인창 위젯을 불러서 메시지 띄워줘."

3️⃣ Unbind All Events from Input Dispatch

여기가 핵심👇

⚙️ 역할:

“이 다이얼로그 위젯에 이전에 바인딩된 입력(YES/NO 응답) 이벤트들을 전부 해제해라.”

이전에 이 다이얼로그를 썼을 때 남아 있던 이전 콜백(이벤트 리스너) 들을 다 지워주는 단계

🧠 왜 필요?

WBP_ConfirmationDialogue는 여러 번 재사용될 수 있는 위젯

그런데 만약 매번 새로운 이벤트를 바인딩만 하고 언바인딩을 안 하면 이런 문제가 생김

⚠️ 문제 시나리오

  1. 유저가 Exit 버튼을 눌러 다이얼로그 표시 → BindEvent 연결됨
  2. “Cancel” 눌러서 닫음 (하지만 바인딩은 남음)
  3. 다시 Exit 버튼 누름 → 또 BindEvent 추가됨
  4. 이제 YES를 누르면 이전, 현재 바인딩된 모든 함수가 중복으로 실행됨

결과:

🔁 “YES”를 한 번 눌렀는데 OnExitConfirmation 이벤트가 여러 번 실행됨

그래서, “새로 바인딩하기 전에 무조건 이전 걸 다 언바인딩(Unbind)” 해야 함

4️⃣ Create Event

  • 이건 실제로 “YES/NO 눌렀을 때 호출될 함수”를 연결하는 부분
  • 오른쪽에 “OnExitConfirmation(YES/NO)” → 다이얼로그 위젯 안에 선언된 Delegate(입력 이벤트 디스패처) 를 의미

“이 다이얼로그에서 YES 또는 NO를 선택하면,

WBP_MainMenu의 OnExitConfirmation(bool bYes) 함수를 호출하라.”

5️⃣ Bind Event to Input Dispatch

  • 위에서 생성한 이벤트를 다이얼로그 위젯의 OnExitConfirmation 이벤트에 연결
  • 이렇게 하면 사용자가 YES / NO를 클릭했을 때 MainMenu 쪽으로 신호가 전달

WBP_ConfirmationDialogue

위젯 애니메이션 추가하기

AnimationRender Opacity (0.00 → 0.25)
FadeIn0.0 → 1.0
FadeOutPlay Animation Reserve

FadeIn 만 애니메이션 만들고 FadeOut 은 만든 애니메이션 reverse 해주기

블루프린트 노드

다이얼로그(UI 창)가 FadeOut 애니메이션으로 서서히 사라지고,

그 애니메이션이 끝난 뒤 Remove from Parent로 위젯을 화면에서 완전히 제거하는 구조

여기서 Get End Time + Delay 조합은 “애니메이션이 다 끝난 뒤 정확한 타이밍에 Remove 실행하기”용입

1️⃣ Play Animation (FadeIn, Reverse)

  • 원래 FadeIn 애니메이션을 Reverse 모드(역재생) 로 재생 → 즉, “페이드아웃(FadeOut)”처럼 서서히 사라지는 효과
  • 여기서 재생은 바로 시작하지만, 언제 끝나는지 알 수 없기 때문에 다음 동작(위젯 제거)은 바로 하면 안 됨

2️⃣ Get End Time

  • FadeIn 애니메이션의 전체 길이(재생 시간) 를 가져오는 노드
  • 이 값은 초 단위(float) 로 반환됨 예를 들어 FadeIn 애니가 0.8초라면 → Get End Time의 반환값 = 0.8

“이 애니메이션은 몇 초짜리인가?”를 자동으로 구하는 노드

3️⃣ Delay

  • 연결된 시간(초) 동안 기다렸다가 다음 실행핀을 이어줌
  • 여기서는 Get End Time의 값을 Delay Duration으로 연결

“애니메이션이 끝날 때까지 기다렸다가, 그 다음에 실행해라.”

4️⃣ Remove from Parent

  • 위젯을 부모(Viewport/Canvas 등)에서 제거

→ 화면에서 완전히 사라짐

이걸 애니 끝나기 전에 실행하면 FadeOut이 끝나기도 전에 갑자기 꺼져버리므로,
Delay(GetEndTime)을 둬서 자연스럽게 마무리

🌊 전체 흐름

[Button Yes/No Clicked]
   ↓
Call Input Dispatch (이벤트 전달)
   ↓
Play Animation (FadeIn, Reverse) → 페이드아웃 시작
   ↓
Get End Time (FadeIn 길이 구함)
   ↓
Delay (그 길이만큼 대기)
   ↓
Remove from Parent (위젯 완전히 제거)

👍🏻 장점

장점설명
자동 타이밍애니메이션 길이를 하드코딩할 필요 없음 (0.8초, 1.2초 등 자동 감지)
유지보수 편함나중에 FadeIn 애니 길이 수정해도 Delay 자동 맞춰짐
부드러운 전환FadeOut이 다 끝난 뒤 위젯이 제거돼 자연스럽게 사라짐

UI 등장(Fade In) → 대기(사용자 입력) → 사라짐(Fade Out)

1️⃣ Event Pre Construct → FadeIn (Forward)

  • 다이얼로그 위젯이 처음 화면에 등장할 때 실행됨
  • FadeIn 애니메이션을 정방향(Forward) 으로 재생해서 투명도 0 → 1 로 자연스럽게 나타나게 함
  • “대화창이 천천히 등장하는 연출”을 담당

이게 없으면 위젯이 바로 1.0 투명도로 튀어나옴 (뚝 하고 나타나는 느낌)

2️⃣ 사용자 입력 (Button_Yes / Button_No)

  • 사용자가 버튼을 클릭하면 → Call Input Dispatch 로 상위(MainMenu)에게 “YES/NO” 신호를 보냄
  • 이어서 Play Animation (FadeIn, Reverse) 실행 → FadeIn을 역재생해서 “서서히 사라짐(FadeOut)” 효과를 냄
  • GetEndTime → Delay → Remove from Parent 로 애니메이션이 끝난 뒤 위젯을 완전히 제거

💡 이게 페이드아웃 타이밍 제어 부분

→ “YES/NO 눌렀을 때 다이얼로그가 부드럽게 닫히게 하려는 구조”

3️⃣ 정리하면 구조적으로 이렇게 동작

단계이벤트동작애니메이션
Event Pre Construct위젯 생성 시FadeIn (Forward) — 서서히 등장
OnClicked(Yes/No)사용자 입력FadeIn (Reverse) — 서서히 사라짐
Delay 후 Remove애니 끝난 뒤위젯 제거

💡 포인트

구분이유
Event Pre Construct에서 FadeIn다이얼로그가 나타날 때 부드럽게 보이게 하려고
Play Animation (Reverse)동일한 FadeIn 애니를 역재생해서 FadeOut 효과로 재사용
GetEndTime + DelayFadeOut 끝나는 시점까지 기다렸다가 제거하기 위해
Remove from Parent화면에서 완전히 제거

Event Pre Construct에서는 등장 시 FadeIn을,

버튼 클릭 시에는 퇴장용 FadeOut(=FadeIn Reverse) 를 실행하는 구조

→ 다이얼로그가 자연스럽게 “나타났다 → 사라지는” 완성된 UI 흐름

0개의 댓글