CP_MainMenu.h
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "Components/Button.h"
#include "CP_MainMenu.generated.h"
UCLASS()
class CYBERPUNK_API UCP_MainMenu : public UUserWidget
{
GENERATED_BODY()
public:
UCP_MainMenu(const FObjectInitializer& ObjectInitializer);
protected:
virtual void NativeConstruct() override;
UPROPERTY(meta = (BindWidget))
UButton* StartButton;
UPROPERTY(meta = (BindWidget))
UButton* ExitButton;
private:
UFUNCTION()
void OnStartButtonClicked();
UFUNCTION()
void OnExitButtonClicked();
// 게임 재개 또는 종료를 위한 메뉴 표시 함수
UFUNCTION()
void ShowPauseMenu();
// 게임 재개 함수
UFUNCTION()
void OnResumeButtonClicked();
// 게임 종료 함수
UFUNCTION()
void OnExitFromPauseButtonClicked();
UPROPERTY(meta = (BindWidget))
UButton* ResumeButton;
UPROPERTY(meta = (BindWidget))
UButton* ExitFromPauseButton;
UPROPERTY()
UUserWidget* PauseMenuWidget; // Pause 메뉴 위젯
};
기억해야 할 것
UCLASS() 매크로: 이 클래스가 언리얼 엔진의 UObject 시스템에 등록된다는 것을 알림.
GENERATED_BODY() 매크로: UCLASS()와 함께 사용되며, 언리얼 엔진이 필요한 코드를 자동으로 생성해줌.
UPROPERTY() 매크로: 언리얼 엔진 에디터에서 변수를 편집할 수 있도록 해줌.
meta = (BindWidget): UMG 위젯을 C++ 코드와 연결해줌.
UFUNCTION() 매크로: 언리얼 엔진의 UObject 시스템에 함수를 등록해줌.
AddDynamic() 함수: 위젯의 이벤트를 C++ 함수에 연결해줌.
팁
- 헤더 파일에는 클래스 선언과 필요한 멤버 변수, 함수 선언만 넣는 것이 좋음.
- 구현은 cpp 파일에서 하는 것이 일반적.
주의사항
#pragma once는 헤더 파일이 컴파일러에 의해 단 한 번만 포함되도록 하는 지시어임.
- 언리얼 엔진의 클래스 이름은
U로 시작하는 것이 일반적임.
CP_MainMenu.cpp
#include "CP_MainMenu.h"
#include "Kismet/GameplayStatics.h"
#include "Blueprint/WidgetTree.h" // 위젯 트리 사용을 위한 include
#include "EnhancedInputSubsystems.h" // UInputSubsystem 사용을 위한 include
#include "CP_PlayerHUD.h"
#include "Kismet/KismetSystemLibrary.h"
UCP_MainMenu::UCP_MainMenu(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
}
void UCP_MainMenu::NativeConstruct()
{
Super::NativeConstruct();
if (StartButton)
{
StartButton->OnClicked.AddDynamic(this, &UCP_MainMenu::OnStartButtonClicked);
}
else
{
UE_LOG(LogTemp, Warning, TEXT("StartButton 위젯이 바인딩되지 않았습니다."));
}
if (ExitButton)
{
ExitButton->OnClicked.AddDynamic(this, &UCP_MainMenu::OnExitButtonClicked);
}
else
{
UE_LOG(LogTemp, Warning, TEXT("ExitButton 위젯이 바인딩되지 않았습니다."));
}
}
void UCP_MainMenu::OnStartButtonClicked()
{
UGameplayStatics::OpenLevel(GetWorld(), TEXT("MenuMap")); // "YourLevelName"을 실제 레벨 이름으로 변경
// 게임 시작 후 ESC 키 입력 활성화
if (APlayerController* PlayerController = GetWorld()->GetFirstPlayerController())
{
if (UEnhancedInputLocalPlayerSubsystem* InputSubsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
{
// SetInputActionMappingByName 함수가 없으므로, 적절한 함수로 대체해야 합니다.
// InputSubsystem->SetInputActionMappingByName("Pause", EInputEvent::IE_Pressed); // "Pause" 액션 매핑
}
}
// 게임 시작 시 HUD 위젯 표시 (CP_PlayerHUD)
if (APlayerController* PlayerController = GetWorld()->GetFirstPlayerController())
{
TSubclassOf<UCP_PlayerHUD> HUDClass; // CP_PlayerHUD 클래스
if (HUDClass)
{
UCP_PlayerHUD* PlayerHUD = CreateWidget<UCP_PlayerHUD>(PlayerController, HUDClass);
if (PlayerHUD)
{
PlayerHUD->AddToViewport();
}
}
}
UE_LOG(LogTemp, Warning, TEXT("Start Button Clicked"));
}
void UCP_MainMenu::OnExitButtonClicked()
{
UKismetSystemLibrary::QuitGame(GetWorld(), GetWorld()->GetFirstPlayerController(), EQuitPreference::Quit, true);
UE_LOG(LogTemp, Warning, TEXT("Exit Button Clicked"));
}
void UCP_MainMenu::ShowPauseMenu()
{
if (PauseMenuWidget)
{
PauseMenuWidget->AddToViewport();
if (ResumeButton)
{
ResumeButton->OnClicked.AddDynamic(this, &UCP_MainMenu::OnResumeButtonClicked);
}
if (ExitFromPauseButton)
{
ExitFromPauseButton->OnClicked.AddDynamic(this, &UCP_MainMenu::OnExitFromPauseButtonClicked);
}
}
else
{
// PauseMenuWidget이 없으면 생성
PauseMenuWidget = CreateWidget<UUserWidget>(GetWorld()->GetFirstPlayerController(), LoadObject<UClass>(nullptr, TEXT("/Game/UI/WBP_PauseMenu.WBP_PauseMenu"))); // 실제 경로와 이름으로 변경
if (PauseMenuWidget)
{
ShowPauseMenu(); // 다시 호출하여 Pause 메뉴 표시
}
}
}
void UCP_MainMenu::OnResumeButtonClicked()
{
if (PauseMenuWidget)
{
PauseMenuWidget->RemoveFromParent(); // RemoveFromViewport 대신 RemoveFromParent 사용
}
// 게임 재개 로직 (Unpause 등)
UE_LOG(LogTemp, Warning, TEXT("Resume Button Clicked"));
}
void UCP_MainMenu::OnExitFromPauseButtonClicked()
{
UKismetSystemLibrary::QuitGame(GetWorld(), GetWorld()->GetFirstPlayerController(), EQuitPreference::Quit, true);
UE_LOG(LogTemp, Warning, TEXT("Exit from Pause Button Clicked"));
}
기억해야 할 것
#include 문: 필요한 헤더 파일을 포함시켜서 해당 기능들을 사용할 수 있도록 함.
Super::NativeConstruct(): 부모 클래스의 NativeConstruct() 함수를 호출해야 함.
UE_LOG(): 언리얼 엔진의 로그 시스템을 사용하여 메시지를 출력함.
UGameplayStatics::OpenLevel(): 레벨을 여는 함수.
UKismetSystemLibrary::QuitGame(): 게임을 종료하는 함수.
CreateWidget(): 위젯을 생성하는 함수.
AddToViewport(): 위젯을 화면에 표시하는 함수.
RemoveFromParent(): 위젯을 부모 위젯에서 제거하는 함수.
팁
- cpp 파일에는 헤더 파일에서 선언된 함수들의 구현과 추가적인 함수들을 넣음.
NativeConstruct() 함수는 위젯이 생성될 때 호출되는 함수임.
OnButtonClicked() 함수는 버튼이 클릭되었을 때 호출되는 함수임.
주의사항
LoadObject<UClass>() 함수를 사용할 때, 정확한 위젯 블루프린트 경로를 지정해야 함.
RemoveFromViewport() 대신 RemoveFromParent()를 사용하는 이유는, Pause 메뉴가 다른 위젯의 자식으로 추가될 수 있기 때문임.
추가 팁
SetGamePaused() 함수를 사용하여 게임을 일시 정지/재개할 수 있음.
GetWorld()->GetFirstPlayerController()를 사용하여 플레이어 컨트롤러를 얻을 수 있음.
TSubclassOf<UCP_PlayerHUD> HUDClass 부분을 실제 CP_PlayerHUD 클래스로 변경해야 함.
/Game/UI/WBP_PauseMenu.WBP_PauseMenu 부분을 실제 Pause 메뉴 위젯의 경로와 이름으로 변경해야 함.
- "MenuMap" 부분을 실제 레벨 이름으로 변경해야 함.
전체적인 주의사항
- 언리얼 엔진 프로젝트에서는 C++ 코드와 블루프린트를 함께 사용할 수 있음.
- C++ 코드를 변경하면 반드시 컴파일을 해야 함.
- 언리얼 엔진 에디터에서 위젯을 생성하고, C++ 코드와 바인딩해야 함.
- Pause 메뉴 기능을 사용하려면, "Pause"라는 이름의 액션 매핑을 생성하고, ESC 키를 할당해야 함.