기존에 HUD에서 위젯마다 하나하나 적었던 입력 모드 설정을 함수로 빼서 필요할 때 호출하기
이렇게 하면 나중에 다른 곳에서도 입력 모드 바꿔야 할 때 UIManager 통해서 편하게 호출하면 된다
SetInputModeUIOnly
UI 메뉴용 (마우스 커서 표시 + UI만 입력 받음)
SetInputModeGameOnly
게임 플레이용 (마우스 커서 숨김 + 게임만 입력 받음)
SetInputModeGameAndUI
인벤토리 같은 곳용 (게임과 UI 둘 다 입력 받음)
bShowMouseCursor
마우스 커서를 보일지 숨길지 결정함
true : 커서가 화면에 보임false : 커서가 안 보임bLockMouseToViewport (SetLockMouseToViewportBehavior)
마우스를 게임 창 안에 가둘지 결정함
true : 마우스가 게임 창 밖으로 못 나감false : 마우스가 창 밖으로 나갈 수 있음bHideCursorDuringCapture
Capture : 마우스 입력을 게임이 받아서 처리한다
게임 화면 클릭 → 마우스가 캡쳐됨
true : 기본값 - 캡처되면 커서 숨김false : 캡처되어도 커서 계속 보임// 기본 동작
FInputModeGameAndUI InputMode;
InputMode.SetHideCursorDuringCapture(true); // 기본값
InputMode.SetHideCursorDuringCapture(false); // 커서 계속 보임
// 실제 사용
// 인벤토리 열 때: 커서 계속 보임
UIManager->SetInputModeGameAndUI(PC, nullptr, true, false);
// ↑커서보임 ↑클릭해도 커서 안 숨김
// FPS 조준 모드: 클릭하면 커서 숨김
UIManager->SetInputModeGameAndUI(PC, nullptr, true, true);
// ↑커서보임 ↑클릭하면 커서 숨김
public:
// 입력 모드: UI 전용, 마우스 커서 ON
void SetInputModeUIOnly(APlayerController* PC, UWidget* WidgetToFocus = nullptr, bool bLockMouseToViewport = false);
// 입력 모드: Game 전용, 마우스 커서 OFF
void SetInputModeGameOnly(APlayerController* PC);
// 입력 모드: Game & UI
void SetInputModeGameAndUI(APlayerController* PC, UWidget* WidgetToFocus = nullptr, bool bShowCursor = true, bool bHideCursorDuringCapture = false);
UI Only 모드는 마우스 커서가 무조건 보여야 하니까 Look 여부만 선택
→ bShowMouseCursor 는 항상 true 로 고정
마우스를 창 안에 가둘지는 상황마다 다름
false) - 다른 프로그램 켜거나 Alt+Tab 할 때true) - 마우스가 화면 밖으로 안 나가게SetInputModeGameAndUI 함수 사용해야 함bShowCursor 매개변수를 따로 받음UWidget* WidgetToFocus = nullptr
UWidget*// 실제 사용
// 함수 정의
void SetInputModeUIOnly(APlayerController* PC, UWidget* WidgetToFocus = nullptr);
// 사용할 때 - 두 가지 방법 가능
UIManager->SetInputModeUIOnly(PC); // WidgetToFocus 안 넘김 → nullptr 사용됨
UIManager->SetInputModeUIOnly(PC, MyButton); // MyButton에 포커스 줌
// 코드 동작
void ULNUIManageSubsystem::SetInputModeUIOnly(APlayerController* PC, UWidget* WidgetToFocus, bool bLockMouseToViewport)
{
FInputModeUIOnly InputMode;
// WidgetToFocus가 nullptr이 아닐 때만 실행돼
if (WidgetToFocus)
{
InputMode.SetWidgetToFocus(WidgetToFocus->TakeWidget());
}
// nullptr이면 이 부분을 건너뛰고, 포커스 없이 진행
}
void ULNUIManageSubsystem::SetInputModeUIOnly(APlayerController* PC, UWidget* WidgetToFocus, bool bLockMouseToViewport)
{
// PlayerController가 유효한지 확인
if (!PC)
{
return;
}
// 마우스 커서를 표시
PC->bShowMouseCursor = true;
// UI 전용 입력 모드를 생성
FInputModeUIOnly InputMode;
// 마우스를 뷰포트에 고정할지 설정
if (bLockMouseToViewport)
{
InputMode.SetLockMouseToViewportBehavior(EMouseLockMode::LockAlways);
}
else
{
InputMode.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock);
}
// 포커스를 줄 위젯이 있다면 설정
if (WidgetToFocus)
{
InputMode.SetWidgetToFocus(WidgetToFocus->TakeWidget());
}
// 입력 모드를 적용
PC->SetInputMode(InputMode);
}
void ULNUIManageSubsystem::SetInputModeGameOnly(APlayerController* PC)
{
// PlayerController가 유효한지 확인
if (!PC)
{
return;
}
// 마우스 커서를 숨김
PC->bShowMouseCursor = false;
// 게임 전용 입력 모드를 생성하고 적용
FInputModeGameOnly InputMode;
PC->SetInputMode(InputMode);
}
void ULNUIManageSubsystem::SetInputModeGameAndUI(APlayerController* PC, UWidget* WidgetToFocus, bool bShowCursor, bool bHideCursorDuringCapture)
{
// PlayerController가 유효한지 확인
if (!PC)
{
return;
}
// 마우스 커서 표시 여부를 설정
PC->bShowMouseCursor = bShowCursor;
// 게임과 UI 둘 다 사용하는 입력 모드를 생성
FInputModeGameAndUI InputMode;
// 캡처 중 커서를 숨길지 설정
InputMode.SetHideCursorDuringCapture(bHideCursorDuringCapture);
// 마우스를 뷰포트에 고정하지 않음
InputMode.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock);
// 포커스를 줄 위젯이 있다면 설정
if (WidgetToFocus)
{
InputMode.SetWidgetToFocus(WidgetToFocus->TakeWidget());
}
// 입력 모드를 적용
PC->SetInputMode(InputMode);
}
void ALNHUD::OnRootLayoutReady()
{
// UIManager Subsystem을 가져옴
ULNUIManageSubsystem* UIManager = GetGameInstance()->GetSubsystem<ULNUIManageSubsystem>();
if (!UIManager)
{
return;
}
// 현재 레벨 이름을 가져옴
FString CurrentLevelName = GetWorld()->GetName();
// PlayerController를 가져옴
APlayerController* PC = GetOwningPlayerController();
if (CurrentLevelName.Contains("MainMenu"))
{
// 메인메뉴 UI 띄우기
UIManager->ShowWidget(FGameplayTag::RequestGameplayTag(TEXT("UI.Request.MainMenu")));
// UI 전용 입력 모드로 설정 (마우스 커서 표시 + RootLayout에 포커스)
UIManager->SetInputModeUIOnly(PC, RootLayoutInstance, false);
}
else
{
// 인게임 HUD 띄우기
UIManager->ShowWidget(FGameplayTag::RequestGameplayTag(TEXT("UI.Request.ShowHUD")));
// 게임 전용 입력 모드로 설정 (마우스 커서 숨김)
UIManager->SetInputModeGameOnly(PC);
}
}
📎 Epic Games Developer - Asserts
📎 [Unreal] 언리얼 유효성 검사 - IsValid, == nullptr, ensure
if (!PC)
{
return;
}
check(PC != nullptr);
언리얼 엔진은 상황에 따라 다른 방식으로 컴파일 가능
Development (개발용)
check(), ensure() 같은 검사 코드가 실제로 실행됨Shipping (배포용)
check(), ensure() 같은 매크로가 코드에서 아예 사라짐작성한 코드
void MyFunction()
{
check(PC != nullptr); // 이 줄이
PC->DoSomething();
}
Development 빌드로 컴파일
void MyFunction()
{
if (PC == nullptr) { 크래시! } // check가 실제로 검사
PC->DoSomething();
}
Shipping 빌드로 컴파일
// 실제 실행되는 코드
void MyFunction()
{
// check 줄이 완전히 사라짐
PC->DoSomething();
}
개발할 때는 check() 로 버그를 빡빡하게 잡고, 최종 배포할 때는 자동으로 제거
void ULNUIManageSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
Super::Initialize(Collection);
// 1) Config(UIMapDataAssetPath)에 경로가 제대로 들어왔는지 확인
check(LNMapDataAssetPath.IsValid());
// ...
}
LNMapDataAssetPath 는 Config 파일이나 프로젝트 세팅에서 개발자가 반드시 설정해야 하는 값
이게 없으면
→ check() 사용해서 개발 할 때 즉시 크래시로 세팅 안 했다고 알려줌
if (!LNMapDataAsset)로 하면
TryLoad() 결과는 런타임에 다양한 이유로 실패할 수 있음
→ 정상적으로 발생할 수 있는 외부 상황에 의한 실패
→ 부드럽게 실패 처리해서 게임 크래시 안 내고 계속 돌아감
if (!ensure(PC))
{
return;
}