Class GameDev* SheepAdult

[Unreal Engine 4.27] LevelBlueprint C++ && Main Menu && Game Start && Game Quit 본문

Unreal Project

[Unreal Engine 4.27] LevelBlueprint C++ && Main Menu && Game Start && Game Quit

SheepAdult 2022. 3. 15. 02:08

먼저 LevelBlueprint역할을 하는 C++함수를 하나 만든다.

LevelScriptActor

LevelScriptActor C++ 클래스를 만들든 후 블루프린트 클래스로 만든다. 그리고

위와 같이 LevelBlueprint로 들어간다. 클래스 세팅에서 클래스 옵션의 부모 클래스를 방금 만든 블루프린트로 설정해 놓으면 LevelBlueprint처럼 사용할 수 있다.

class ***_API AMyLevelScriptActor : public ALevelScriptActor
{
	GENERATED_BODY()
	
public:
	UPROPERTY(EditAnywhere, Category = "Widget")
		TSubclassOf<UUserWidget> _MainMenuWidget;
	UPROPERTY(VisibleInstanceOnly, Category = "Widget")
		UMainMenuWidget* MainMenuWidget;

protected:
	virtual void BeginPlay() override;
};

만든 C++ 클래스에 메인 메뉴로 사용할 Widget을 넣어줄 변수를 만들고

void AMyLevelScriptActor::BeginPlay()
{
	Super::BeginPlay();
	if (_MainMenuWidget)
	{
		MainMenuWidget = Cast<UMainMenuWidget>(CreateWidget(GetWorld(), _MainMenuWidget));
		if (MainMenuWidget)
		{
			MainMenuWidget->AddToViewport();
			UGameplayStatics::GetPlayerController(GetWorld(), 0)->bShowMouseCursor = true;
		}
	}	
}

BeginPlay()에서 Widget을 띄워준다. 여기까지 LevelBlueprint C++버전이고 아래부터는 메인 메뉴 내용이다.

 

메인 메뉴 Level(유니티로 따지면 Scene)에서 게임 시작을 했을 때 메뉴 UI를 띄워야 하므로 Widget를 하나 만든다.

MainMenu Widget

각 버튼은 아래와 같이 모두 변수로 처리해줘야 한다.

"변수인지" 체크

그리고 해당 위젯의 부모 C++ 클래스 헤더 파일에서 버튼의 이름과 똑같은 이름의 변수를 설정해줘야 한다. 그렇지 않으면 블루프린트에서 이름이 달라 에러가 난다. 참고로 C++ UUserWidget클래스를 먼저 만든 후에 블루프린트 생성에서 해당 Widget이름을 검색한 후 Widget 블루프린트를 만들어주면 된다.

UCLASS()
class ***_API UMainMenuWidget : public UUserWidget
{
	GENERATED_BODY()

public:
	UPROPERTY(meta = (BindWidget))
		class UButton* NewGameButton;
	UPROPERTY(meta = (BindWidget))
		class UButton* ResumeGameButton;
	UPROPERTY(meta = (BindWidget))
		class UButton* SettingButton;
	UPROPERTY(meta = (BindWidget))
		class UButton* QuitButton;

	UFUNCTION()
		void StartNewGame();
	UFUNCTION()
		void QuitGame();

protected:
	virtual void NativeConstruct() override;
};

테스트로 구현할 버튼은 Quit과 StartNewGame만 할 것이므로 UFUNCTION()로 해당 함수를 선언한다. 이 두 함수는 Delegate에 Bind 시켜줄 것이므로 UFUNCTION()으로 해줘야 한다. 그렇지 않으면 동작하지 않는다. 그리고 여기서 시간을 좀 썼는데 UUserWidget은 생성자가 안 먹어서 당황했다. 여기저기 찾아보니 

UCLASS()
class ***_API UMyWidget : public UUserWidget
{
	GENERATED_BODY()
	
public:
	UMyWidget(const FObjectInitializer &ObjectInitializer);
};

UMyWidget::UMyWidget(const FObjectInitializer &ObjectInitializer)
	: Super(ObjectInitializer)
{
}

위처럼 생성자에 매개변수를 추가하면 된다고 해서 해봤는데 "uuserwidget 클래스의 기본 생성자가 없습니다"라는 에러가 떴다. 그래서 기본 생성자도 추가해서 했더니 또 안되고,,, 하다가 UUserWidget에서는 NativeConstruct()를 사용하면 된다는 것을 알았다. 

void UMyWidget::NativeConstruct()
{
	Super::NativeConstruct();

	NewGameButton->OnClicked.AddDynamic(this, &UMainMenuWidget::StartNewGame);
	QuitButton->OnClicked.AddDynamic(this, &UMainMenuWidget::QuitGame);
}

void UMyWidget::StartNewGame()
{
	UGameplayStatics::OpenLevel(this, FName("Main"));
}

void UMyWidget::QuitGame()
{
	UKismetSystemLibrary::QuitGame(this, 0, EQuitPreference::Quit, false);
}

그래서 위와 같이 NativeConstruct에서 버튼에 Delegate를 Bind 해주고 GameLevel에 들어갈 때는 OpenLevel함수로, Quit 할 땐 QuitGame함수로 시작 및 종료를 구현해주면 된다.