kwivaro웹 도구
UNREAL · UI · 게임 시스템

일시정지 메뉴를 배타적 패널 시스템에 통합하기

게임 클라이언트 개발자2026-09-106분

인벤토리·월드맵은 이미 ‘한 번에 하나만 열리는’ 배타적 패널 규칙으로 돌고 있었다. 일시정지 메뉴도 별도로 만들지 않고 이 규칙에 얹었다. 문제는 닫을 때 입력 모드 복원이었다.

ESC 진입과 위젯 구조

활성 패널이 없고 퀵슬롯 휠도 안 열린 순수 게임플레이 상태에서 ESC를 일시정지 진입점으로 잡았다.

if (!ActivePanel && !bQuickSlotWheelOpen && Params.Key == EKeys::Escape)
    OpenPauseMenu();

URetrievePauseMenuWidget은 BP가 아니라 URetrieveGamePanelWidget을 상속한 C++ 베이스로 두고, 버튼은 BindWidgetOptional로 찾아 NativeConstruct에서 OnClicked를 프로그래매틱하게 바인딩했다.

진짜 문제 — 하드코딩된 입력 모드 복원

패널을 닫는 RemoveActivePanelImmediately()가 무조건 FInputModeGameOnly + 커서 숨김으로 복원했다. 인게임 인벤토리엔 맞지만 메뉴(UIOnly + 커서)에선 치명적이었다. 하드코딩된 복원값이 원래 ‘인게임 인벤토리’ 맥락의 가정을 그대로 박아 놨던 것이다. 그래서 현재 세션 상태로 분기하게 고쳤다.

if (SessionState == MainMenu || SessionState == Result)
    UpdateInputMode(SessionState);      // UIOnly, 커서 유지
else
    SetInputMode(FInputModeGameOnly()); // 인게임, 커서 숨김

멀티플레이에선 SetGamePaused(true)를 클라이언트 로컬 입력 필터링으로 대체했다. 한 클라이언트가 서버 전체를 멈출 순 없어서다.

배운 점

‘닫은 뒤 상태’는 상수가 아니라 맥락이다. 하드코딩된 복원값은 그 코드가 처음 쓰인 맥락의 가정을 박아 넣는다. 새 진입점(메뉴)에서 재사용하면 그 가정이 깨진다.

이미 있는 상태 머신(세션 상태)을 단일 진실로 삼아 복원값을 파생시키면, 진입점이 늘어도 각자 맞는 모드로 돌아온다.