Ein flexibles Menüsystem wurde hinzugefügt, das ein Hauptmenü und ein In-Game-Menü umfasst. Das Hauptmenü bietet Optionen wie "Neues Spiel starten", "Optionen" und "Credits". Das In-Game-Menü ermöglicht Pausenfunktionen wie "Fortsetzen", "Optionen" und "Zum Desktop beenden". Neue Klassen wurden eingeführt, darunter `MenuManagerSubsystem` zur Verwaltung von Menübildschirmen, `MenuScreenWidget` als Basisklasse für Menüs sowie spezifische Widgets wie `MainMenuWidget`, `InGameMenuWidget` und `OptionsMenuWidget`. Zusätzlich wurden stilisierte Schaltflächen (`MenuButtonWidget`) und ein neuer `MenuPlayerController` für menübasierte Levels implementiert. Änderungen an `KingshearthLegacyPlayerController` ermöglichen die Steuerung des In-Game-Menüs. Binäre Assets für Menüs und UI wurden hinzugefügt.
119 lines
2.8 KiB
C++
119 lines
2.8 KiB
C++
#include "MenuManagerSubsystem.h"
|
|
#include "MenuScreenWidget.h"
|
|
#include "Engine/GameInstance.h"
|
|
#include "GameFramework/PlayerController.h"
|
|
#include "UObject/UObjectGlobals.h"
|
|
|
|
void UMenuManagerSubsystem::Initialize(FSubsystemCollectionBase& Collection)
|
|
{
|
|
Super::Initialize(Collection);
|
|
FCoreUObjectDelegates::PreLoadMap.AddUObject(this, &UMenuManagerSubsystem::HandlePreLoadMap);
|
|
}
|
|
|
|
void UMenuManagerSubsystem::Deinitialize()
|
|
{
|
|
FCoreUObjectDelegates::PreLoadMap.RemoveAll(this);
|
|
Super::Deinitialize();
|
|
}
|
|
|
|
void UMenuManagerSubsystem::HandlePreLoadMap(const FString& MapName)
|
|
{
|
|
ClearStack();
|
|
}
|
|
|
|
UMenuScreenWidget* UMenuManagerSubsystem::PushScreen(TSubclassOf<UMenuScreenWidget> ScreenClass)
|
|
{
|
|
if (!ScreenClass)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
APlayerController* OwningController = GetGameInstance() ? GetGameInstance()->GetFirstLocalPlayerController() : nullptr;
|
|
if (!OwningController)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
UMenuScreenWidget* NewScreen = CreateWidget<UMenuScreenWidget>(OwningController, ScreenClass);
|
|
if (!NewScreen)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
// Hide (not just cover) whatever screen was on top - it stops rendering and stops taking
|
|
// input, rather than sitting underneath the new screen doing both pointlessly.
|
|
if (UMenuScreenWidget* PreviousTop = GetActiveScreen())
|
|
{
|
|
PreviousTop->SetVisibility(ESlateVisibility::Collapsed);
|
|
}
|
|
|
|
NewScreen->AddToPlayerScreen(static_cast<int32>(BaseZOrder + ScreenStack.Num()));
|
|
ScreenStack.Add(NewScreen);
|
|
RefreshInputMode();
|
|
return NewScreen;
|
|
}
|
|
|
|
void UMenuManagerSubsystem::PopScreen()
|
|
{
|
|
if (ScreenStack.Num() == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UMenuScreenWidget* TopScreen = ScreenStack.Pop();
|
|
if (TopScreen)
|
|
{
|
|
TopScreen->NotifyScreenClosing();
|
|
TopScreen->RemoveFromParent();
|
|
}
|
|
|
|
if (UMenuScreenWidget* NewTop = GetActiveScreen())
|
|
{
|
|
NewTop->SetVisibility(ESlateVisibility::Visible);
|
|
}
|
|
|
|
RefreshInputMode();
|
|
}
|
|
|
|
void UMenuManagerSubsystem::ClearStack()
|
|
{
|
|
for (UMenuScreenWidget* Screen : ScreenStack)
|
|
{
|
|
if (Screen)
|
|
{
|
|
Screen->NotifyScreenClosing();
|
|
Screen->RemoveFromParent();
|
|
}
|
|
}
|
|
ScreenStack.Reset();
|
|
RefreshInputMode();
|
|
}
|
|
|
|
UMenuScreenWidget* UMenuManagerSubsystem::GetActiveScreen() const
|
|
{
|
|
return ScreenStack.Num() > 0 ? ScreenStack.Last() : nullptr;
|
|
}
|
|
|
|
void UMenuManagerSubsystem::RefreshInputMode()
|
|
{
|
|
APlayerController* OwningController = GetGameInstance() ? GetGameInstance()->GetFirstLocalPlayerController() : nullptr;
|
|
if (!OwningController)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (UMenuScreenWidget* Top = GetActiveScreen())
|
|
{
|
|
FInputModeUIOnly InputMode;
|
|
InputMode.SetWidgetToFocus(Top->TakeWidget());
|
|
InputMode.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock);
|
|
OwningController->SetInputMode(InputMode);
|
|
OwningController->SetShowMouseCursor(true);
|
|
}
|
|
else
|
|
{
|
|
OwningController->SetInputMode(FInputModeGameOnly());
|
|
OwningController->SetShowMouseCursor(false);
|
|
}
|
|
}
|