HAxis sos
This commit is contained in:
4
Source/UnrealProject/GUI/Menu/ButtonHintBar.cpp
Normal file
4
Source/UnrealProject/GUI/Menu/ButtonHintBar.cpp
Normal file
@@ -0,0 +1,4 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "ButtonHintBar.h"
|
||||
13
Source/UnrealProject/GUI/Menu/ButtonHintBar.h
Normal file
13
Source/UnrealProject/GUI/Menu/ButtonHintBar.h
Normal file
@@ -0,0 +1,13 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "UserWidget.h"
|
||||
#include "ButtonHintBar.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API UButtonHintBar : public UUserWidget
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
};
|
||||
246
Source/UnrealProject/GUI/Menu/GameList.cpp
Normal file
246
Source/UnrealProject/GUI/Menu/GameList.cpp
Normal file
@@ -0,0 +1,246 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "GameList.h"
|
||||
#include "GameListItem.h"
|
||||
#include "DefaultGameInstance.h"
|
||||
#include "SessionManager.h"
|
||||
#include "ScreenOverlay.h"
|
||||
#include "PlayerControllerBase.h"
|
||||
|
||||
static UClass* itemWidgetClass;
|
||||
|
||||
UGameList::UGameList(const FObjectInitializer& init)
|
||||
: Super(init)
|
||||
{
|
||||
itemWidgetClass = ConstructorHelpers::FClassFinder<UGameListItem>(TEXT("/Game/Assets/GUI/Components/WEEGEE_GameListItem")).Class;
|
||||
m_quickJoining = false;
|
||||
}
|
||||
|
||||
void UGameList::NativeConstruct()
|
||||
{
|
||||
Super::NativeConstruct();
|
||||
m_searchingSessions = false;
|
||||
m_joining = false;
|
||||
|
||||
UWorld* world = this->GetWorld();
|
||||
if (!world)
|
||||
return;
|
||||
m_gameInstance = Cast<UDefaultGameInstance>(world->GetGameInstance());
|
||||
if (!m_gameInstance)
|
||||
return;
|
||||
|
||||
onItemSelectionConfirmed.AddDynamic(this, &UGameList::OnListItemPressed);
|
||||
}
|
||||
void UGameList::NativeDestruct()
|
||||
{
|
||||
m_StopPingingGames();
|
||||
Super::NativeDestruct();
|
||||
}
|
||||
void UGameList::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
|
||||
{
|
||||
Super::NativeTick(MyGeometry, InDeltaTime);
|
||||
}
|
||||
|
||||
void UGameList::OnStartSearching_Implementation()
|
||||
{
|
||||
}
|
||||
void UGameList::OnEndSearching_Implementation(int32)
|
||||
{
|
||||
}
|
||||
void UGameList::SetInitialSearchMode_Implementation(bool useLan)
|
||||
{
|
||||
}
|
||||
void UGameList::OnQuickJoin()
|
||||
{
|
||||
OnSearchButton();
|
||||
m_quickJoining = true;
|
||||
}
|
||||
void UGameList::JoinSession(const class FOnlineSessionSearchResult& result)
|
||||
{
|
||||
m_StopPingingGames();
|
||||
|
||||
if(!m_joining)
|
||||
{
|
||||
APlayerControllerBase* pc = Cast<APlayerControllerBase>(GetOwningPlayer());
|
||||
check(!m_joiningOverlay);
|
||||
m_joiningOverlay = pc->overlay->ShowOverlay("Joining game");
|
||||
m_joining = true;
|
||||
|
||||
UDefaultGameInstance* inst = Cast<UDefaultGameInstance>(GetGameInstance());
|
||||
inst->sessionManager->onJoinSessionComplete.AddUObject(this, &UGameList::m_OnJoinSessionComplete);
|
||||
inst->sessionManager->JoinSession(result);
|
||||
}
|
||||
}
|
||||
void UGameList::SetSearchMode(bool useLan)
|
||||
{
|
||||
}
|
||||
void UGameList::OnSearchButton()
|
||||
{
|
||||
UDefaultGameInstance* inst = Cast<UDefaultGameInstance>(GetGameInstance());
|
||||
if (!m_searchingSessions)
|
||||
{
|
||||
check(!m_searchingOverlay);
|
||||
inst->sessionManager->onFindSessionsComplete.AddUObject(this, &UGameList::m_OnFindSessionsComplete);
|
||||
inst->sessionManager->FindSessions();
|
||||
m_searchingSessions = true;
|
||||
container->ClearChildren();
|
||||
|
||||
m_StopPingingGames();
|
||||
m_gameItems.SetNum(0);
|
||||
|
||||
RescanItems();
|
||||
OnStartSearching();
|
||||
|
||||
APlayerControllerBase* pc = Cast<APlayerControllerBase>(GetOwningPlayer());
|
||||
m_searchingOverlay = pc->overlay->ShowOverlay("Searching for games");
|
||||
}
|
||||
}
|
||||
|
||||
void UGameList::OnListItemPressed(UMenuItemBase* item)
|
||||
{
|
||||
GWPRINT(L"Pressed item " + item);
|
||||
UGameListItem* listItem = Cast<UGameListItem>(item);
|
||||
if(listItem)
|
||||
{
|
||||
JoinSession(*listItem->result);
|
||||
}
|
||||
}
|
||||
|
||||
void UGameList::m_OnFindSessionsComplete(bool success)
|
||||
{
|
||||
UDefaultGameInstance* inst = Cast<UDefaultGameInstance>(GetGameInstance());
|
||||
|
||||
// Hide searching overlay
|
||||
m_searchingOverlay->Close();
|
||||
m_searchingOverlay = nullptr;
|
||||
|
||||
m_searchingSessions = false;
|
||||
|
||||
if(!success)
|
||||
{
|
||||
APlayerControllerBase* pc = Cast<APlayerControllerBase>(GetOwningPlayer());
|
||||
TArray<FString> options;
|
||||
options.Add("OK");
|
||||
pc->overlay->ShowMessageBox("Error", "Error occured while fining games", options);
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_quickJoining)
|
||||
{
|
||||
// Find session with most players in, that is not full
|
||||
auto& results = inst->sessionManager->sessionSearch->SearchResults;
|
||||
if(results.Num() > 0)
|
||||
{
|
||||
FOnlineSessionSearchResult* optimal = &results[0];
|
||||
int32 largest = 0;
|
||||
for(int32 i = 1; i < results.Num(); i++)
|
||||
{
|
||||
const int32 available = results[i].Session.NumOpenPublicConnections;
|
||||
if(available == 0) continue;
|
||||
const int32 max = results[i].Session.SessionSettings.NumPublicConnections;
|
||||
const int32 current = max - available;
|
||||
if(current > largest)
|
||||
{
|
||||
optimal = &results[i];
|
||||
largest = current;
|
||||
}
|
||||
}
|
||||
JoinSession(*optimal);
|
||||
}
|
||||
m_quickJoining = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get session results
|
||||
auto& results = inst->sessionManager->sessionSearch->SearchResults;
|
||||
for(int32 i = 0; i < results.Num(); i++)
|
||||
{
|
||||
// Create a selectable slot in the game list
|
||||
UGameListItem* childItem = CreateWidget<UGameListItem>(GetWorld(), itemWidgetClass);
|
||||
check(container);
|
||||
container->AddChild(childItem);
|
||||
childItem->SetItem(this, results[i]);
|
||||
m_gameItems.Add(childItem);
|
||||
}
|
||||
|
||||
OnEndSearching(results.Num());
|
||||
RescanItems();
|
||||
|
||||
// Give ping data for games
|
||||
m_StartPingingGames();
|
||||
}
|
||||
|
||||
m_searchingSessions = false;
|
||||
|
||||
// Remove callback
|
||||
inst->sessionManager->onFindSessionsComplete.RemoveAll(this);
|
||||
}
|
||||
void UGameList::m_OnJoinSessionComplete(int32 result)
|
||||
{
|
||||
UDefaultGameInstance* inst = Cast<UDefaultGameInstance>(GetGameInstance());
|
||||
APlayerControllerBase* pc = Cast<APlayerControllerBase>(GetOwningPlayer());
|
||||
|
||||
m_joining = false;
|
||||
|
||||
// Remove callback
|
||||
inst->sessionManager->onJoinSessionComplete.RemoveAll(this);
|
||||
|
||||
if(result != EOnJoinSessionCompleteResult::Success)
|
||||
{
|
||||
FString error = "Unknown";
|
||||
switch(result)
|
||||
{
|
||||
case EOnJoinSessionCompleteResult::AlreadyInSession:
|
||||
error = "Already in session";
|
||||
break;
|
||||
case EOnJoinSessionCompleteResult::CouldNotRetrieveAddress:
|
||||
error = "Could not retrieve address";
|
||||
break;
|
||||
case EOnJoinSessionCompleteResult::SessionDoesNotExist:
|
||||
error = "Session does not exist";
|
||||
break;
|
||||
case EOnJoinSessionCompleteResult::SessionIsFull:
|
||||
error = "Session is full";
|
||||
break;
|
||||
}
|
||||
|
||||
// Close joining overlay
|
||||
m_joiningOverlay->Close();
|
||||
m_joiningOverlay = nullptr;
|
||||
|
||||
// Show error message
|
||||
TArray<FString> options;
|
||||
options.Add("OK");
|
||||
pc->overlay->ShowMessageBox("Error", FString("Failed to join session:\n") + error, options);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Travel to destination player lobby
|
||||
pc->ClientTravel(inst->sessionManager->joinConnectionString, ETravelType::TRAVEL_Absolute, false);
|
||||
//UWorld* world = GetWorld();
|
||||
//world->SeamlessTravel(inst->sessionManager->joinConnectionString, true);
|
||||
//world->ServerTravel()
|
||||
//AMenuGameMode* mgm = Cast<AMenuGameMode>(world->GetAuthGameMode());
|
||||
}
|
||||
}
|
||||
|
||||
void UGameList::m_PingGames()
|
||||
{
|
||||
for(auto& g : m_gameItems)
|
||||
{
|
||||
g->Ping();
|
||||
}
|
||||
}
|
||||
void UGameList::m_StartPingingGames()
|
||||
{
|
||||
GetGameInstance()->GetTimerManager().SetTimer(m_pinger, this, &UGameList::m_PingGames, 1.0f, true);
|
||||
}
|
||||
void UGameList::m_StopPingingGames()
|
||||
{
|
||||
GetGameInstance()->GetTimerManager().ClearTimer(m_pinger);
|
||||
for(UGameListItem* i : m_gameItems)
|
||||
{
|
||||
i->Ping();
|
||||
}
|
||||
}
|
||||
75
Source/UnrealProject/GUI/Menu/GameList.h
Normal file
75
Source/UnrealProject/GUI/Menu/GameList.h
Normal file
@@ -0,0 +1,75 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MenuScreen.h"
|
||||
#include "OnlineSessionInterface.h"
|
||||
#include "GameList.generated.h"
|
||||
using namespace std;
|
||||
|
||||
struct SessionItemData
|
||||
{
|
||||
FString name;
|
||||
int32 index;
|
||||
FOnlineSessionSearchResult* result;
|
||||
};
|
||||
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API UGameList : public UPersistentSideView
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UGameList(const FObjectInitializer& init);
|
||||
|
||||
virtual void NativeConstruct() override;
|
||||
virtual void NativeDestruct() override;
|
||||
virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;
|
||||
|
||||
UFUNCTION(BlueprintNativeEvent, Category = "UI")
|
||||
void OnStartSearching();
|
||||
UFUNCTION(BlueprintNativeEvent, Category = "UI")
|
||||
void OnEndSearching(int32 gamesFound);
|
||||
UFUNCTION(BlueprintNativeEvent, Category = "UI")
|
||||
void SetInitialSearchMode(bool useLan);
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
void OnQuickJoin();
|
||||
|
||||
void JoinSession(const class FOnlineSessionSearchResult& result);
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
void SetSearchMode(bool useLan);
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
void OnSearchButton();
|
||||
|
||||
UFUNCTION()
|
||||
void OnListItemPressed(UMenuItemBase* item);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
int32 GetNumGames() const { return m_gameItems.Num(); }
|
||||
UFUNCTION(BlueprintCallable, Category = "UI")
|
||||
TArray<class UGameListItem*> GetGames() const { return m_gameItems; }
|
||||
|
||||
private:
|
||||
UFUNCTION()
|
||||
void m_OnFindSessionsComplete(bool success);
|
||||
UFUNCTION()
|
||||
void m_OnJoinSessionComplete(int32 result);
|
||||
|
||||
void m_PingGames();
|
||||
void m_StartPingingGames();
|
||||
void m_StopPingingGames();
|
||||
FTimerHandle m_pinger;
|
||||
|
||||
TArray<class UGameListItem*> m_gameItems;
|
||||
|
||||
bool m_searchingSessions;
|
||||
bool m_quickJoining;
|
||||
bool m_joining;
|
||||
|
||||
UPROPERTY()
|
||||
class UOverlayInfo* m_searchingOverlay;
|
||||
UPROPERTY()
|
||||
class UOverlayInfo* m_joiningOverlay;
|
||||
UPROPERTY()
|
||||
class UDefaultGameInstance* m_gameInstance;
|
||||
};
|
||||
53
Source/UnrealProject/GUI/Menu/GameListItem.cpp
Normal file
53
Source/UnrealProject/GUI/Menu/GameListItem.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
|
||||
#include "GameListItem.h"
|
||||
#include "GameList.h"
|
||||
#include "DefaultGameInstance.h"
|
||||
#include "SessionManager.h"
|
||||
|
||||
UGameListItem::UGameListItem(const FObjectInitializer& init)
|
||||
: Super(init)
|
||||
{
|
||||
valid = false;
|
||||
}
|
||||
|
||||
void UGameListItem::NativeConstruct()
|
||||
{
|
||||
Super::NativeConstruct();
|
||||
OnGameInfoUpdated();
|
||||
}
|
||||
|
||||
void UGameListItem::SetItem(UGameList* parent, const FOnlineSessionSearchResult& _result)
|
||||
{
|
||||
// Set the sesion result to be displayed in this item
|
||||
check(parent);
|
||||
m_parent = parent;
|
||||
result = &_result;
|
||||
valid = result != nullptr;
|
||||
if(valid)
|
||||
{
|
||||
UWorld* world = GetWorld();
|
||||
check(world);
|
||||
UDefaultGameInstance* inst = Cast<UDefaultGameInstance>(world->GetGameInstance());
|
||||
FString nickname = inst->sessionManager->GetPlayerName(*result->Session.OwningUserId);
|
||||
// Game Name = Online platform nickname of host
|
||||
gameHost = nickname;
|
||||
gamePing = result->PingInMs;
|
||||
if(!result->Session.SessionSettings.Get(SETTING_MAPNAME, gameMapName))
|
||||
{
|
||||
GWWARNING(L"Game does not have a map name set");
|
||||
}
|
||||
gamePlayersMax = result->Session.SessionSettings.NumPublicConnections;
|
||||
gamePlayers = gamePlayersMax - result->Session.NumOpenPublicConnections;
|
||||
}
|
||||
OnGameInfoUpdated();
|
||||
}
|
||||
|
||||
void UGameListItem::Ping()
|
||||
{
|
||||
UDefaultGameInstance* inst = Cast<UDefaultGameInstance>(GetWorld()->GetGameInstance());
|
||||
inst->sessionManager->PingResult(*result);
|
||||
OnGameInfoUpdated();
|
||||
}
|
||||
41
Source/UnrealProject/GUI/Menu/GameListItem.h
Normal file
41
Source/UnrealProject/GUI/Menu/GameListItem.h
Normal file
@@ -0,0 +1,41 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MenuButton.h"
|
||||
#include "GameListItem.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API UGameListItem : public UMenuButton
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UGameListItem(const FObjectInitializer& init);
|
||||
virtual void NativeConstruct() override;
|
||||
|
||||
void SetItem(class UGameList* parent, const FOnlineSessionSearchResult& result);
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = "UI")
|
||||
void OnGameInfoUpdated();
|
||||
|
||||
void Ping();
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Game")
|
||||
bool valid;
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Game")
|
||||
FString gameHost;
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Game")
|
||||
FString gameMapName;
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Game")
|
||||
int32 gamePlayers;
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Game")
|
||||
int32 gamePlayersMax;
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Game")
|
||||
int32 gamePing;
|
||||
|
||||
const class FOnlineSessionSearchResult* result;
|
||||
private:
|
||||
UPROPERTY()
|
||||
class UGameList* m_parent;
|
||||
};
|
||||
103
Source/UnrealProject/GUI/Menu/GraphicsMenu.cpp
Normal file
103
Source/UnrealProject/GUI/Menu/GraphicsMenu.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "SelectButton.h"
|
||||
#include "DefaultGameInstance.h"
|
||||
#include "Prefs.h"
|
||||
#include "GraphicsMenu.h"
|
||||
|
||||
|
||||
|
||||
void UGraphicsMenu::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
|
||||
{
|
||||
Super::NativeTick(MyGeometry, InDeltaTime);
|
||||
|
||||
m_Update();
|
||||
}
|
||||
|
||||
|
||||
void UGraphicsMenu::InitButtons(USelectButton* templateButton, TArray<USelectButton*> settingButtons)
|
||||
{
|
||||
m_templateButton = templateButton;
|
||||
m_settingButtons = settingButtons;
|
||||
|
||||
if (!IsValid(m_templateButton) || m_settingButtons.Num() != 6)
|
||||
{
|
||||
JERROR("InitButton arguments invalid");
|
||||
m_templateButton = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
UDefaultGameInstance* instance = Cast<UDefaultGameInstance>(GetGameInstance());
|
||||
if (!IsValid(instance))
|
||||
return;
|
||||
|
||||
UPrefs* const prefs = instance->GetPrefs();
|
||||
int32 fetchPreset = instance->GetScalabilityQuality();
|
||||
templateButton->selected = prefs->usingCustomGraphicsSettings ? 0 : fetchPreset + 1;
|
||||
|
||||
m_previousSelection = -5;
|
||||
m_Update();
|
||||
}
|
||||
|
||||
|
||||
void UGraphicsMenu::Apply()
|
||||
{
|
||||
UDefaultGameInstance* instance = Cast<UDefaultGameInstance>(GetGameInstance());
|
||||
if (!IsValid(m_templateButton) || !IsValid(instance))
|
||||
return;
|
||||
|
||||
const int32 current = m_templateButton->selected;
|
||||
if (current > 0)
|
||||
{
|
||||
// Store the template setting
|
||||
instance->SetScalabilityQuality(current - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Store the individual sub settings
|
||||
instance->SetScalabilityQualityValues(
|
||||
m_settingButtons[0]->selected,
|
||||
m_settingButtons[1]->selected,
|
||||
m_settingButtons[2]->selected,
|
||||
m_settingButtons[3]->selected,
|
||||
m_settingButtons[4]->selected,
|
||||
m_settingButtons[5]->selected);
|
||||
}
|
||||
}
|
||||
|
||||
void UGraphicsMenu::m_Update()
|
||||
{
|
||||
UDefaultGameInstance* instance = Cast<UDefaultGameInstance>(GetGameInstance());
|
||||
if (!IsValid(m_templateButton) || !IsValid(instance))
|
||||
return;
|
||||
|
||||
const int32 current = m_templateButton->selected;
|
||||
if (m_previousSelection != current) // Only update when the value has changed
|
||||
{
|
||||
if (current == 0)
|
||||
{
|
||||
// Enable the sub setting buttons
|
||||
for (int32 i = 0; i < m_settingButtons.Num(); i++)
|
||||
m_settingButtons[i]->SetIsEnabled(true);
|
||||
|
||||
// Fetch the stored sub settings from prefs
|
||||
TArray<int32> customSettings = instance->GetPrefs()->customGraphicsSettings;
|
||||
if (customSettings.Num() <= m_settingButtons.Num())
|
||||
{
|
||||
for (int32 i = 0; i < customSettings.Num(); i++)
|
||||
m_settingButtons[i]->selected = customSettings[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Disable the subsetting buttons and set them to the template
|
||||
for (int32 i = 0; i < m_settingButtons.Num(); i++)
|
||||
{
|
||||
m_settingButtons[i]->SetIsEnabled(false);
|
||||
m_settingButtons[i]->selected = current - 1;
|
||||
}
|
||||
}
|
||||
m_previousSelection = current;
|
||||
}
|
||||
}
|
||||
32
Source/UnrealProject/GUI/Menu/GraphicsMenu.h
Normal file
32
Source/UnrealProject/GUI/Menu/GraphicsMenu.h
Normal file
@@ -0,0 +1,32 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MenuScreen.h"
|
||||
#include "GraphicsMenu.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API UGraphicsMenu : public USideView
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Graphics")
|
||||
void InitButtons(class USelectButton* templateButton, TArray<class USelectButton*> settingButtons);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Graphics")
|
||||
void Apply();
|
||||
|
||||
private:
|
||||
void m_Update();
|
||||
|
||||
USelectButton* m_templateButton;
|
||||
TArray<USelectButton*> m_settingButtons;
|
||||
|
||||
int32 m_previousSelection;
|
||||
};
|
||||
161
Source/UnrealProject/GUI/Menu/MapSelectionScreen.cpp
Normal file
161
Source/UnrealProject/GUI/Menu/MapSelectionScreen.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "MapData.h"
|
||||
#include "MapSelectionScreen.h"
|
||||
#include "AssetRegistryModule.h"
|
||||
#include "DefaultGameInstance.h"
|
||||
#include "MapSlot.h"
|
||||
#include "SessionManager.h"
|
||||
#include "MenuController.h"
|
||||
#include "ScreenOverlay.h"
|
||||
#include "MenuGameMode.h"
|
||||
|
||||
static UClass* mapSlotWidgetClass;
|
||||
|
||||
UMapSelectionScreen::UMapSelectionScreen(const FObjectInitializer& init)
|
||||
: Super(init)
|
||||
{
|
||||
mapSlotWidgetClass = ConstructorHelpers::FClassFinder<UMapSlot>(TEXT("/Game/Assets/GUI/Components/WEEGEE_MapListItem")).Class;
|
||||
}
|
||||
|
||||
void UMapSelectionScreen::NativeConstruct()
|
||||
{
|
||||
Super::NativeConstruct();
|
||||
if(container)
|
||||
{
|
||||
// Get all the available maps and create selection buttons for them
|
||||
UWorld* world = GetWorld();
|
||||
check(world);
|
||||
auto& maps = Cast<UDefaultGameInstance>(world->GetGameInstance())->maps;
|
||||
for(int32 i = 0; i < maps.Num(); i++)
|
||||
{
|
||||
UMapSlot* mapSlot = CreateWidget<UMapSlot>(GetWorld(), mapSlotWidgetClass);
|
||||
check(mapSlot);
|
||||
mapSlot->mapData = maps[i];
|
||||
mapSlot->mapScreen = this;
|
||||
mapSlot->OnMapSet();
|
||||
m_mapSlots.Add(mapSlot);
|
||||
container->AddChild(mapSlot);
|
||||
}
|
||||
|
||||
onItemSelected.RemoveAll(this);
|
||||
onItemSelected.AddDynamic(this, &UMapSelectionScreen::OnSelectionChanged);
|
||||
RescanItems();
|
||||
SelectMap(0);
|
||||
}
|
||||
}
|
||||
|
||||
void UMapSelectionScreen::OnSelectionChanged(UMenuItemBase* item)
|
||||
{
|
||||
UMapSlot* mapSlot = Cast<UMapSlot>(item);
|
||||
if(mapSlot)
|
||||
{
|
||||
//SelectMap(mapSlot->index);
|
||||
}
|
||||
}
|
||||
void UMapSelectionScreen::SelectMap(int32 index)
|
||||
{
|
||||
UWorld* world = GetWorld();
|
||||
check(world);
|
||||
UDefaultGameInstance* inst = Cast<UDefaultGameInstance>(world->GetGameInstance());
|
||||
|
||||
TArray<UMapData*>& maps = inst->maps;
|
||||
if(index < 0 || index > maps.Num())
|
||||
{
|
||||
GWERROR(L"Selected map out of range");
|
||||
return;
|
||||
}
|
||||
|
||||
mapData = maps[index];
|
||||
check(mapData);
|
||||
|
||||
// Set the asset path to the selected map in the session manager
|
||||
AMenuGameMode* gameMode = Cast<AMenuGameMode>(world->GetAuthGameMode());
|
||||
if(gameMode)
|
||||
{
|
||||
gameMode->SetMap(mapData->pathToAsset);
|
||||
GWPRINT(L"Selected map: " + maps[index]->friendlyName);
|
||||
}
|
||||
else
|
||||
{
|
||||
GWARNING(L"Can't select map, no game mode!");
|
||||
}
|
||||
}
|
||||
|
||||
void UMapSelectionScreen::CreateGame()
|
||||
{
|
||||
SelectMap(GetSelectedItem());
|
||||
|
||||
if(!mapData)
|
||||
{
|
||||
GERROR("No map set");
|
||||
return;
|
||||
}
|
||||
|
||||
UWorld* world = GetWorld();
|
||||
check(world);
|
||||
UDefaultGameInstance* inst = Cast<UDefaultGameInstance>(world->GetGameInstance());
|
||||
|
||||
AMenuGameMode* gameMode = Cast<AMenuGameMode>(world->GetAuthGameMode());
|
||||
if(!gameMode)
|
||||
{
|
||||
GERROR("Can't start game, no menu game mode set");
|
||||
return;
|
||||
}
|
||||
|
||||
APlayerControllerBase* pc = Cast<APlayerControllerBase>(GetOwningPlayer());
|
||||
if(m_sessionCreateOverlay)
|
||||
return; // Already creating session
|
||||
m_sessionCreateOverlay = pc->overlay->ShowOverlay("Creating session");
|
||||
|
||||
// Set the map setting in the game mode
|
||||
gameMode->AssignMapData(mapData);
|
||||
|
||||
// Make sure there is no connection already
|
||||
inst->sessionManager->CloseNetConnections();
|
||||
|
||||
// Set host settings
|
||||
FOnlineSessionSettings& sessionSettings = inst->sessionManager->sessionSettings;
|
||||
sessionSettings.NumPublicConnections = mapData->maxTeamCount * 2; // Team count setting translated to max connected players (x2)
|
||||
sessionSettings.Set(SETTING_MAPNAME, mapData->pathToAsset, EOnlineDataAdvertisementType::ViaOnlineServiceAndPing);
|
||||
|
||||
// Create a new session
|
||||
inst->sessionManager->onCreateSessionComplete.AddUObject(this, &UMapSelectionScreen::m_OnCreateSessionCompleted);
|
||||
inst->sessionManager->CreateSession();
|
||||
}
|
||||
|
||||
void UMapSelectionScreen::m_OnCreateSessionCompleted(bool success)
|
||||
{
|
||||
if(m_sessionCreateOverlay)
|
||||
{
|
||||
m_sessionCreateOverlay->Close();
|
||||
m_sessionCreateOverlay = nullptr;
|
||||
}
|
||||
|
||||
UDefaultGameInstance* inst = Cast<UDefaultGameInstance>(GetWorld()->GetGameInstance());
|
||||
inst->sessionManager->onCreateSessionComplete.RemoveAll(this);
|
||||
|
||||
AMenuController* mc = Cast<AMenuController>(GetOwningPlayer());
|
||||
if(success)
|
||||
{
|
||||
// Goto the lobby
|
||||
mc->OnEnterLobby();
|
||||
|
||||
// Start the session, @note not sure if this is needed
|
||||
//inst->sessionManager->StartSession();
|
||||
}
|
||||
else
|
||||
{
|
||||
TArray<FString> options;
|
||||
options.Add("OK");
|
||||
mc->overlay->ShowMessageBox("Error", "Failed to create game session", options);
|
||||
}
|
||||
}
|
||||
|
||||
UMapData::UMapData()
|
||||
{
|
||||
maxTeamCount = 3;
|
||||
friendlyName = "Map Name";
|
||||
description = "<Designers: Add description>";
|
||||
}
|
||||
40
Source/UnrealProject/GUI/Menu/MapSelectionScreen.h
Normal file
40
Source/UnrealProject/GUI/Menu/MapSelectionScreen.h
Normal file
@@ -0,0 +1,40 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MenuScreen.h"
|
||||
#include "MapSelectionScreen.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API UMapSelectionScreen : public USideView
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UMapSelectionScreen(const FObjectInitializer& init);
|
||||
virtual void NativeConstruct() override;
|
||||
|
||||
UFUNCTION()
|
||||
void OnSelectionChanged(UMenuItemBase* item);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Level")
|
||||
void SelectMap(int32 mapIndex);
|
||||
UFUNCTION(BlueprintCallable, Category = "Level")
|
||||
void CreateGame();
|
||||
|
||||
// Currently Selected map data
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Level")
|
||||
class UMapData* mapData;
|
||||
UPROPERTY()
|
||||
class UMapSlot* selectedMapSlot;
|
||||
|
||||
private:
|
||||
UPROPERTY()
|
||||
class UOverlayInfo* m_sessionCreateOverlay;
|
||||
|
||||
UFUNCTION()
|
||||
void m_OnCreateSessionCompleted(bool success);
|
||||
|
||||
UPROPERTY()
|
||||
TArray<class UMapSlot*> m_mapSlots;
|
||||
};
|
||||
14
Source/UnrealProject/GUI/Menu/MapSlot.cpp
Normal file
14
Source/UnrealProject/GUI/Menu/MapSlot.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "MapSlot.h"
|
||||
#include "MapData.h"
|
||||
|
||||
void UMapSlot::NativeConstruct()
|
||||
{
|
||||
Super::NativeConstruct();
|
||||
}
|
||||
|
||||
void UMapSlot::OnMapSet_Implementation()
|
||||
{
|
||||
}
|
||||
26
Source/UnrealProject/GUI/Menu/MapSlot.h
Normal file
26
Source/UnrealProject/GUI/Menu/MapSlot.h
Normal file
@@ -0,0 +1,26 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MenuButton.h"
|
||||
#include "MapSlot.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API UMapSlot : public UMenuButton
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
virtual void NativeConstruct() override;
|
||||
|
||||
UFUNCTION(BlueprintNativeEvent, Category = "Slot")
|
||||
void OnMapSet();
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Slot")
|
||||
class UMapSelectionScreen* mapScreen;
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Slot")
|
||||
class UMapData* mapData;
|
||||
};
|
||||
32
Source/UnrealProject/GUI/Menu/MenuAction.h
Normal file
32
Source/UnrealProject/GUI/Menu/MenuAction.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "MenuAction.Generated.h"
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EMenuActionBinding : uint8
|
||||
{
|
||||
Confirm,
|
||||
Back,
|
||||
Opt1,
|
||||
Opt2,
|
||||
Start,
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right,
|
||||
Repeat_Left,
|
||||
Repeat_Right,
|
||||
Trigger_Left,
|
||||
Trigger_Right,
|
||||
Shoulder_Left,
|
||||
Shoulder_Right,
|
||||
Options,
|
||||
|
||||
// These are actually just for button hint icons
|
||||
// don't use these for actual actions as they wont get used
|
||||
LeftStick,
|
||||
RightStick,
|
||||
DPad,
|
||||
ShoulderButtons,
|
||||
Triggers
|
||||
};
|
||||
147
Source/UnrealProject/GUI/Menu/MenuButton.cpp
Normal file
147
Source/UnrealProject/GUI/Menu/MenuButton.cpp
Normal file
@@ -0,0 +1,147 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "MenuButton.h"
|
||||
#include "SubMenu.h"
|
||||
|
||||
|
||||
FLinearColor uiIdleColor = FLinearColor(1.0f, 1.0f, 1.0f, 0.3f);
|
||||
FLinearColor uiSelectedColor = FLinearColor(0.8f, 1.0f, 0.8f, 0.4f);
|
||||
FLinearColor uiSelectedFocusedColor = FLinearColor(0.2f, 1.0f, 0.2f, 0.8f);
|
||||
|
||||
TSubclassOf<class UMenuButton> defaultButtonClass;
|
||||
|
||||
UMenuButton::UMenuButton(const FObjectInitializer& init)
|
||||
: Super(init)
|
||||
{
|
||||
defaultButtonClass = ConstructorHelpers::FClassFinder<UMenuButton>(L"/Game/Assets/GUI/Components/WEEGEE_Button").Class;
|
||||
}
|
||||
void UMenuButton::NativeConstruct()
|
||||
{
|
||||
m_button = WidgetTree->FindWidget<UButton>("Button");
|
||||
m_label = WidgetTree->FindWidget<UTextBlock>("Label");
|
||||
m_textOverlay = WidgetTree->FindWidget<UOverlay>("TextOverlay");
|
||||
if(!m_button)
|
||||
{
|
||||
GWERROR(L"Widget " + GetName() + L" does not contain a Button componenet");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_button->OnClicked.AddDynamic(this, &UMenuButton::m_OnPressed);
|
||||
}
|
||||
|
||||
|
||||
NativeOnSelectionChanged(false, true);
|
||||
Super::NativeConstruct();
|
||||
|
||||
if(m_textOverlay && m_label)
|
||||
{
|
||||
m_blurOverlay = NewObject<UOverlay>(GetWorld());
|
||||
UOverlaySlot* slot = m_textOverlay->AddChildToOverlay(m_blurOverlay);
|
||||
slot->SetHorizontalAlignment(EHorizontalAlignment::HAlign_Fill);
|
||||
slot->SetVerticalAlignment(EVerticalAlignment::VAlign_Fill);
|
||||
|
||||
UOverlaySlot* labelSlot = Cast<UOverlaySlot>(m_label->Slot);
|
||||
EHorizontalAlignment textAlignH = labelSlot ? labelSlot->HorizontalAlignment.GetValue() : HAlign_Fill;
|
||||
EVerticalAlignment textAlignV = labelSlot ? labelSlot->VerticalAlignment.GetValue() : VAlign_Fill;
|
||||
|
||||
m_label->RemoveFromParent();
|
||||
|
||||
static int32 quality = 16;
|
||||
static float distance = 2.0f;
|
||||
for(int32 i = 0; i < quality; i++)
|
||||
{
|
||||
float r = (float)i / (float)(quality - 1);
|
||||
FVector2D offset = FVector2D(cos(r*PI), sin(r*PI)) * distance;
|
||||
// Create Glow effect
|
||||
UTextBlock* blurText = NewObject<UTextBlock>(GetWorld());
|
||||
UOverlaySlot* textSlot = m_blurOverlay->AddChildToOverlay(blurText);
|
||||
textSlot->SetHorizontalAlignment(textAlignH);
|
||||
textSlot->SetVerticalAlignment(textAlignV);
|
||||
|
||||
FSlateFontInfo font = m_label->Font;
|
||||
blurText->SetFont(font);
|
||||
blurText->SetColorAndOpacity(FSlateColor(FLinearColor(0.6f, 0.6f, 1.0f, 0.5f)));
|
||||
blurText->SetRenderTranslation(offset);
|
||||
blurText->SetText(m_label->GetText());
|
||||
}
|
||||
m_blurOverlay->SetVisibility(ESlateVisibility::Hidden);
|
||||
|
||||
labelSlot = m_textOverlay->AddChildToOverlay(m_label);
|
||||
labelSlot->SetHorizontalAlignment(textAlignH);
|
||||
labelSlot->SetVerticalAlignment(textAlignV);
|
||||
}
|
||||
}
|
||||
|
||||
void UMenuButton::FocusTick(float DeltaTime)
|
||||
{
|
||||
Super::FocusTick(DeltaTime);
|
||||
if(m_button && m_button->IsHovered() && GetSubMenu()->GetSelectedItem() != index)
|
||||
{
|
||||
GetSubMenu()->SelectNewItemByIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
void UMenuButton::m_OnPressed()
|
||||
{
|
||||
if(HasFocus())
|
||||
{
|
||||
NativeOnPressed(false);
|
||||
}
|
||||
}
|
||||
void UMenuButton::NativeOnMenuAction(EMenuActionBinding binding)
|
||||
{
|
||||
Super::NativeOnMenuAction(binding);
|
||||
if(binding == EMenuActionBinding::Confirm)
|
||||
NativeOnPressed(true);
|
||||
}
|
||||
|
||||
void UMenuButton::NativeOnSelectionChanged(bool selected, bool controller)
|
||||
{
|
||||
Super::NativeOnSelectionChanged(selected, controller);
|
||||
if(!m_button)
|
||||
return;
|
||||
|
||||
UScrollBox* sb = Cast<UScrollBox>(Slot->Parent);
|
||||
if(sb && selected)
|
||||
{
|
||||
sb->ScrollWidgetIntoView(this, true);
|
||||
}
|
||||
|
||||
if(m_blurOverlay)
|
||||
{
|
||||
if(selected)
|
||||
{
|
||||
m_blurOverlay->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_blurOverlay->SetVisibility(ESlateVisibility::Hidden);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UMenuButton::NativeOnPressed(bool controllerInput)
|
||||
{
|
||||
// Simulate OnSelectionConfirmed event if this button is pressed by a mouse
|
||||
GetSubMenu()->NativeOnSelectionConfirmed(this);
|
||||
onPressed.Broadcast();
|
||||
}
|
||||
|
||||
void UMenuButton::SetButtonText(FString textStr)
|
||||
{
|
||||
FText text = FText::FromString(textStr);
|
||||
if(m_label)
|
||||
m_label->SetText(text);
|
||||
if(m_blurOverlay)
|
||||
{
|
||||
for(int32 i = 0; i < m_blurOverlay->GetChildrenCount(); i++)
|
||||
{
|
||||
UTextBlock* tb = Cast<UTextBlock>(m_blurOverlay->GetChildAt(i));
|
||||
if(tb)
|
||||
{
|
||||
tb->SetText(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
48
Source/UnrealProject/GUI/Menu/MenuButton.h
Normal file
48
Source/UnrealProject/GUI/Menu/MenuButton.h
Normal file
@@ -0,0 +1,48 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GUI/Menu/MenuItemBase.h"
|
||||
#include "MenuButton.generated.h"
|
||||
|
||||
extern FLinearColor uiIdleColor;
|
||||
extern FLinearColor uiSelectedColor;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API UMenuButton : public UMenuItemBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UMenuButton(const FObjectInitializer& init);
|
||||
void NativeConstruct() override;
|
||||
void FocusTick(float DeltaTime) override;
|
||||
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FButtonPressed);
|
||||
UPROPERTY(BlueprintAssignable, Category = "MenuButton")
|
||||
FButtonPressed onPressed;
|
||||
|
||||
virtual void NativeOnMenuAction(EMenuActionBinding binding) override;
|
||||
virtual void NativeOnSelectionChanged(bool selected, bool controller) override;
|
||||
|
||||
// Called when this button is pressed, and if it was a controller or a mouse
|
||||
virtual void NativeOnPressed(bool controllerInput);
|
||||
|
||||
// Updates button text + glow
|
||||
UFUNCTION(BlueprintCallable, Category="MenuButton")
|
||||
void SetButtonText(FString text);
|
||||
|
||||
void SimulatePressed() { m_OnPressed(); }
|
||||
|
||||
protected:
|
||||
UFUNCTION()
|
||||
virtual void m_OnPressed();
|
||||
|
||||
UOverlay* m_textOverlay;
|
||||
UOverlay* m_blurOverlay;
|
||||
UPROPERTY()
|
||||
UTextBlock* m_label;
|
||||
UButton* m_button;
|
||||
};
|
||||
9
Source/UnrealProject/GUI/Menu/MenuEnum.h
Normal file
9
Source/UnrealProject/GUI/Menu/MenuEnum.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class MenuButtonID : uint8
|
||||
{
|
||||
OptionsGeneral,
|
||||
OptionsGraphics,
|
||||
Options,
|
||||
};
|
||||
92
Source/UnrealProject/GUI/Menu/MenuItemBase.cpp
Normal file
92
Source/UnrealProject/GUI/Menu/MenuItemBase.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "MenuItemBase.h"
|
||||
#include "SubMenu.h"
|
||||
#include "PlayerControllerBase.h"
|
||||
#include "ScreenOverlay.h"
|
||||
|
||||
void UMenuItemBase::NativeConstruct()
|
||||
{
|
||||
m_selected = false;
|
||||
blockInput = false;
|
||||
m_subMenu = nullptr;
|
||||
priority = 0;
|
||||
Super::NativeConstruct();
|
||||
}
|
||||
void UMenuItemBase::NativeDestruct()
|
||||
{
|
||||
Super::NativeDestruct();
|
||||
}
|
||||
|
||||
void UMenuItemBase::FocusTick(float DeltaTime)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
UMsgBoxInfo* UMenuItemBase::ShowMessageBox(FOverlayItemClosed cb, FString caption, FString message, TArray<FString> options, FString defaultOption)
|
||||
{
|
||||
UScreenOverlay* overlay = Cast<APlayerControllerBase>(GetOwningPlayer())->overlay;
|
||||
if(!overlay)
|
||||
return nullptr;
|
||||
return overlay->ShowMessageBoxCallback(cb, caption, message, options, defaultOption);
|
||||
}
|
||||
|
||||
void UMenuItemBase::NativeOnSelectionChanged(bool selected, bool controller)
|
||||
{
|
||||
if(selected != m_selected)
|
||||
{
|
||||
m_selected = selected;
|
||||
onSelectionChanged.Broadcast(selected);
|
||||
}
|
||||
}
|
||||
|
||||
bool UMenuItemBase::IsSelected() const
|
||||
{
|
||||
return m_selected;
|
||||
}
|
||||
|
||||
class USubMenu* UMenuItemBase::GetSubMenu() const
|
||||
{
|
||||
return m_subMenu;
|
||||
}
|
||||
|
||||
bool UMenuItemBase::HasFocus() const
|
||||
{
|
||||
return GetSubMenu() && GetSubMenu()->HasFocus();
|
||||
}
|
||||
|
||||
void UMenuItemBase::AddActionBinding(EMenuActionBinding binding, FMenuAction action)
|
||||
{
|
||||
m_actionBindings.Add(binding, action);
|
||||
}
|
||||
|
||||
void UMenuItemBase::ClearActionBinding(EMenuActionBinding binding)
|
||||
{
|
||||
m_actionBindings.Remove(binding);
|
||||
}
|
||||
|
||||
void UMenuItemBase::OnMenuAction_Implementation(EMenuActionBinding binding)
|
||||
{
|
||||
}
|
||||
void UMenuItemBase::NativeOnMenuAction(EMenuActionBinding binding)
|
||||
{
|
||||
OnMenuAction(binding);
|
||||
|
||||
TArray<FMenuAction> actions;
|
||||
m_actionBindings.MultiFind(binding, actions);
|
||||
for(int32 i = 0; i < actions.Num(); i++)
|
||||
{
|
||||
actions[i].Execute();
|
||||
}
|
||||
}
|
||||
|
||||
FText UMenuItemBase::GetDescription_Implementation()
|
||||
{
|
||||
return FText();
|
||||
}
|
||||
|
||||
FText UMenuItemBase::GetTitle_Implementation()
|
||||
{
|
||||
return FText();
|
||||
}
|
||||
83
Source/UnrealProject/GUI/Menu/MenuItemBase.h
Normal file
83
Source/UnrealProject/GUI/Menu/MenuItemBase.h
Normal file
@@ -0,0 +1,83 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MenuAction.h"
|
||||
#include "Blueprint/UserWidget.h"
|
||||
#include "MenuItemBase.generated.h"
|
||||
|
||||
DECLARE_DYNAMIC_DELEGATE_OneParam(FOverlayItemClosed, int32, choice);
|
||||
|
||||
extern TSubclassOf<class UMenuButton> defaultButtonClass;
|
||||
extern TSubclassOf<class UMenuSlider> defaultSliderClass;
|
||||
|
||||
/**
|
||||
* Base class for a menu item with controller navigation/input support
|
||||
*/
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API UMenuItemBase : public UUserWidget
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
void NativeConstruct() override;
|
||||
void NativeDestruct() override;
|
||||
|
||||
// Called when the item's menu has focus every frame
|
||||
virtual void FocusTick(float DeltaTime);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="MenuItem")
|
||||
virtual void NativeOnSelectionChanged(bool selected, bool controller);
|
||||
|
||||
// Shows a message box and fires a delegate when the user chooses an option
|
||||
UFUNCTION(BlueprintCallable, Category = "SubMenu")
|
||||
class UMsgBoxInfo* ShowMessageBox(FOverlayItemClosed cb, FString caption, FString message, TArray<FString> options, FString defaultOption);
|
||||
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FSelectionChanged, bool, selected);
|
||||
UPROPERTY(BlueprintAssignable, Category = "MenuItem")
|
||||
FSelectionChanged onSelectionChanged;
|
||||
|
||||
// UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "MenuItem")
|
||||
int32 priority;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly)
|
||||
int32 index;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "MenuItem")
|
||||
bool IsSelected() const;
|
||||
UFUNCTION(BlueprintCallable, Category = "MenuItem")
|
||||
class USubMenu* GetSubMenu() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "MenuItem")
|
||||
bool HasFocus() const;
|
||||
|
||||
DECLARE_DYNAMIC_DELEGATE(FMenuAction);
|
||||
UFUNCTION(BlueprintCallable, Category = "MenuItem")
|
||||
void AddActionBinding(EMenuActionBinding binding, FMenuAction action);
|
||||
UFUNCTION(BlueprintCallable, Category = "MenuItem")
|
||||
void ClearActionBinding(EMenuActionBinding binding);
|
||||
|
||||
UFUNCTION(BlueprintNativeEvent, Category = "MenuItem")
|
||||
void OnMenuAction(EMenuActionBinding binding);
|
||||
virtual void NativeOnMenuAction(EMenuActionBinding binding);
|
||||
|
||||
UFUNCTION(BlueprintNativeEvent, Category = "MenuItem")
|
||||
FText GetDescription();
|
||||
UFUNCTION(BlueprintNativeEvent, Category = "MenuItem")
|
||||
FText GetTitle();
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category="MenuItem")
|
||||
bool blockInput;
|
||||
|
||||
private:
|
||||
|
||||
bool m_selected;
|
||||
friend class APlayerControllerBase;
|
||||
friend class USubMenu;
|
||||
|
||||
TMultiMap<EMenuActionBinding, FMenuAction> m_actionBindings;
|
||||
|
||||
protected:
|
||||
UPROPERTY()
|
||||
class USubMenu* m_subMenu;
|
||||
};
|
||||
337
Source/UnrealProject/GUI/Menu/MenuScreen.cpp
Normal file
337
Source/UnrealProject/GUI/Menu/MenuScreen.cpp
Normal file
@@ -0,0 +1,337 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "MenuScreen.h"
|
||||
#include "ButtonHintBar.h"
|
||||
#include "SubMenu.h"
|
||||
#include "MenuButton.h"
|
||||
|
||||
void UMenuScreen::NativeConstruct()
|
||||
{
|
||||
Super::NativeConstruct();
|
||||
m_sideViewActive = false;
|
||||
m_buttonHintBar = Cast<UButtonHintBar>(WidgetTree->FindWidget("ButtonHintBar"));
|
||||
m_menuContainer = Cast<UOverlay>(WidgetTree->FindWidget("MenuContainer"));
|
||||
m_sideViewContainer = Cast<UOverlay>(WidgetTree->FindWidget("SideViewContainer"));
|
||||
m_menuTitle = Cast<UTextBlock>(WidgetTree->FindWidget("MenuTitle"));
|
||||
m_sideViewTitle = Cast<UTextBlock>(WidgetTree->FindWidget("SideViewTitle"));
|
||||
}
|
||||
|
||||
UMenuPanel* UMenuScreen::OpenScreenMenu(TSubclassOf<UMenuPanel> cls)
|
||||
{
|
||||
UMenuPanel* menu = CreateWidget<UMenuPanel>(GetWorld(), cls);
|
||||
if(!menu)
|
||||
{
|
||||
GERROR("Failed to create menu for screen " + GetName());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
m_menuContainer->AddChildToOverlay(menu);
|
||||
OpenSubMenu(menu);
|
||||
|
||||
menu->FadeIn();
|
||||
|
||||
return menu;
|
||||
}
|
||||
USideView* UMenuScreen::OpenSideView(TSubclassOf<class USideView> cls)
|
||||
{
|
||||
USideView* view = CreateWidget<USideView>(GetWorld(), cls);
|
||||
if(!view)
|
||||
{
|
||||
GERROR("Failed to create side view for screen " + GetName());
|
||||
return nullptr;
|
||||
}
|
||||
UPersistentSideView* pview = Cast<UPersistentSideView>(view);
|
||||
|
||||
UOverlaySlot* slot = m_sideViewContainer->AddChildToOverlay(view);
|
||||
slot->SetHorizontalAlignment(HAlign_Fill);
|
||||
slot->SetVerticalAlignment(VAlign_Fill);
|
||||
|
||||
if(pview)
|
||||
m_OpenSubMenu(view, false);
|
||||
else
|
||||
OpenSubMenu(view);
|
||||
|
||||
view->FadeIn();
|
||||
|
||||
// Switch side view active event
|
||||
if(!m_sideViewActive)
|
||||
{
|
||||
SwitchSideViewVisible(true);
|
||||
m_sideViewActive = true;
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
void UMenuScreen::CloseAllSideViews()
|
||||
{
|
||||
TArray<USideView*> viewsToRemove;
|
||||
for(int32 i = 0; i < m_sideViewContainer->GetChildrenCount(); i++)
|
||||
{
|
||||
USideView* sv = Cast<USideView>(m_sideViewContainer->GetChildAt(i));
|
||||
if(sv && !sv->IsA<UPersistentSideView>())
|
||||
viewsToRemove.Add(sv);
|
||||
}
|
||||
|
||||
for(USideView* sv : viewsToRemove)
|
||||
{
|
||||
CloseSubMenu(sv);
|
||||
}
|
||||
}
|
||||
|
||||
void UMenuScreen::OpenPersistentSideView(UPersistentSideView* sideView)
|
||||
{
|
||||
UMenuScreen::OpenSubMenu(sideView);
|
||||
}
|
||||
void UMenuScreen::ClosePersistentSideView(UPersistentSideView* sideView)
|
||||
{
|
||||
m_CloseSubMenu(sideView, true);
|
||||
}
|
||||
|
||||
void UMenuScreen::OpenSubMenu(class USubMenu* submenu)
|
||||
{
|
||||
m_OpenSubMenu(submenu);
|
||||
}
|
||||
void UMenuScreen::CloseSubMenu(class USubMenu* submenu)
|
||||
{
|
||||
m_CloseSubMenu(submenu);
|
||||
}
|
||||
|
||||
void UMenuScreen::m_OpenSubMenu(class USubMenu* submenu, bool transferFocus)
|
||||
{
|
||||
CloseAllSideViews();
|
||||
|
||||
if(transferFocus)
|
||||
Super::OpenSubMenu(submenu);
|
||||
UMenuScreenSubMenu* mssm = Cast<UMenuScreenSubMenu>(submenu);
|
||||
if(!m_menuTitle || !mssm)
|
||||
return;
|
||||
|
||||
// Update titles and sub-titles
|
||||
UMenuPanel* panel = Cast<UMenuPanel>(submenu);
|
||||
if(panel)
|
||||
m_menuTitle->SetText(FText::FromString(mssm->menuName));
|
||||
USideView* view = Cast<USideView>(submenu);
|
||||
if(view)
|
||||
{
|
||||
m_sideViewTitle->SetText(FText::FromString(mssm->menuName));
|
||||
m_currentSideViews.Add(view);
|
||||
}
|
||||
}
|
||||
void UMenuScreen::m_CloseSubMenu(class USubMenu* submenu, bool persist)
|
||||
{
|
||||
UMenuScreenSubMenu* mssm = Cast<UMenuScreenSubMenu>(submenu);
|
||||
if(mssm)
|
||||
mssm->m_isBeingClosed = true;
|
||||
UMenuPanel* panel = Cast<UMenuPanel>(submenu);
|
||||
if(panel)
|
||||
{
|
||||
CloseAllSideViews();
|
||||
panel->onAnimationEnded.RemoveAll(this);
|
||||
panel->onAnimationEnded.AddUObject(this, &UMenuScreen::m_OnFadeOutComplete);
|
||||
panel->FadeOut();
|
||||
}
|
||||
USideView* view = Cast<USideView>(submenu);
|
||||
if(view && !persist)
|
||||
{
|
||||
view->onAnimationEnded.RemoveAll(this);
|
||||
view->onAnimationEnded.AddUObject(this, &UMenuScreen::m_OnFadeOutComplete);
|
||||
view->FadeOut();
|
||||
|
||||
// Switch side view active event
|
||||
if(m_currentSideViews.Num() > 0 && m_sideViewActive)
|
||||
{
|
||||
SwitchSideViewVisible(false);
|
||||
m_sideViewActive = false;
|
||||
}
|
||||
|
||||
m_currentSideViews.Remove(view);
|
||||
}
|
||||
|
||||
Super::CloseSubMenu(submenu);
|
||||
|
||||
// Update titles and sub-titles
|
||||
if(panel)
|
||||
{
|
||||
if(m_subMenus.Num() > 0)
|
||||
{
|
||||
UMenuPanel* newMenu = Cast<UMenuPanel>(m_subMenus.Last());
|
||||
if(newMenu)
|
||||
m_menuTitle->SetText(FText::FromString(newMenu->menuName));
|
||||
else
|
||||
goto _set_no_panel_text;
|
||||
}
|
||||
else
|
||||
{
|
||||
_set_no_panel_text:
|
||||
m_menuTitle->SetText(FText());
|
||||
}
|
||||
}
|
||||
else if(view && !persist)
|
||||
{
|
||||
if(m_subMenus.Num() > 0)
|
||||
{
|
||||
USideView* newMenu = Cast<USideView>(m_subMenus.Last());
|
||||
if(newMenu)
|
||||
m_sideViewTitle->SetText(FText::FromString(newMenu->menuName));
|
||||
else
|
||||
goto _set_no_view_text;
|
||||
}
|
||||
else
|
||||
{
|
||||
_set_no_view_text:
|
||||
m_sideViewTitle->SetText(FText());
|
||||
}
|
||||
}
|
||||
if(mssm)
|
||||
mssm->m_isBeingClosed = false;
|
||||
}
|
||||
|
||||
void UMenuScreen::m_OnFadeOutComplete(UMenuScreenSubMenu* panel, int32 type)
|
||||
{
|
||||
if(type == 2) // Fade Out
|
||||
{
|
||||
panel->RemoveFromParent();
|
||||
}
|
||||
}
|
||||
|
||||
static float animationDuration = 0.35f;
|
||||
void UMenuScreenSubMenu::NativeConstruct()
|
||||
{
|
||||
m_animationType = 0;
|
||||
m_animationTime = 0.0f;
|
||||
m_isBeingClosed = false;
|
||||
Super::NativeConstruct();
|
||||
}
|
||||
UMenuScreenSubMenu::UMenuScreenSubMenu(const FObjectInitializer& init)
|
||||
: Super(init)
|
||||
{
|
||||
menuName = "<Unnamed Menu!>";
|
||||
}
|
||||
void UMenuScreenSubMenu::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
|
||||
{
|
||||
Super::NativeTick(MyGeometry, InDeltaTime);
|
||||
|
||||
float r = FMath::Clamp(m_animationTime / animationDuration, 0.0f, 1.0f);
|
||||
if(m_animationType == 1) // Fade In
|
||||
{
|
||||
SetRenderTranslation(FVector2D(0.0f - ((1.0f - r)*(1.0f - r)) * 100.0f, 0.0f));
|
||||
FLinearColor color = FLinearColor(1.0f, 1.0f, 1.0f, r);
|
||||
SetColorAndOpacity(color);
|
||||
}
|
||||
else if(m_animationType == 2) // Fade Out
|
||||
{
|
||||
SetRenderTranslation(FVector2D(0.0f + (r*r) * 100.0f, 0.0f));
|
||||
FLinearColor color = FLinearColor(1.0f, 1.0f, 1.0f, (1.0f-r));
|
||||
SetColorAndOpacity(color);
|
||||
}
|
||||
|
||||
if(m_animationType != 0)
|
||||
{
|
||||
if(r >= 1.0f)
|
||||
{
|
||||
onAnimationEnded.Broadcast(this, m_animationType);
|
||||
m_animationType = 0;
|
||||
}
|
||||
m_animationTime += InDeltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
void UMenuScreenSubMenu::OnSuspend(USubMenu* newSubMenu, bool loseFocus)
|
||||
{
|
||||
// Don't fade out / lose focus when side view is opened
|
||||
USideView* sv = Cast<USideView>(newSubMenu);
|
||||
|
||||
if(sv)
|
||||
loseFocus = false;
|
||||
else
|
||||
FadeOut();
|
||||
Super::OnSuspend(newSubMenu, loseFocus);
|
||||
}
|
||||
void UMenuScreenSubMenu::OnRestore(USubMenu* removedMenu)
|
||||
{
|
||||
// To prevent playing the fade in animation again when we receive focus from closing side views when we are actually closing this menu
|
||||
if(!m_isBeingClosed && !Cast<USideView>(removedMenu))
|
||||
FadeIn();
|
||||
Super::OnRestore(removedMenu);
|
||||
}
|
||||
|
||||
void UMenuScreenSubMenu::FadeIn()
|
||||
{
|
||||
m_animationTime = 0.0f;
|
||||
m_animationType = 1;
|
||||
}
|
||||
void UMenuScreenSubMenu::FadeOut()
|
||||
{
|
||||
m_animationTime = 0.0f;
|
||||
m_animationType = 2;
|
||||
}
|
||||
UMenuPanel* UMenuScreenSubMenu::OpenScreenMenu(TSubclassOf<class UMenuPanel> cls)
|
||||
{
|
||||
UMenuScreen* screen = Cast<UMenuScreen>(GetScreen());
|
||||
if(screen)
|
||||
{
|
||||
return screen->OpenScreenMenu(cls);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
USideView* UMenuScreenSubMenu::OpenSideView(TSubclassOf<class USideView> cls)
|
||||
{
|
||||
UMenuScreen* screen = Cast<UMenuScreen>(GetScreen());
|
||||
if(screen)
|
||||
{
|
||||
screen->CloseAllSideViews();
|
||||
return screen->OpenSideView(cls);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
class UMenuButton* UMenuScreenSubMenu::AddButton(FString label)
|
||||
{
|
||||
if(!container)
|
||||
return nullptr;
|
||||
|
||||
UMenuButton* button = CreateWidget<UMenuButton>(GetWorld(), defaultButtonClass);
|
||||
if(!button)
|
||||
return nullptr;
|
||||
|
||||
container->AddChild(button);
|
||||
RescanItems();
|
||||
|
||||
button->SetButtonText(label);
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
void UMenuScreenSubMenu::RescanItems()
|
||||
{
|
||||
m_backButton = nullptr;
|
||||
|
||||
Super::RescanItems();
|
||||
|
||||
for(UMenuItemBase* item : m_items)
|
||||
{
|
||||
UMenuButton* button = Cast<UMenuButton>(item);
|
||||
if(button)
|
||||
{
|
||||
if(button->GetName() == "Back")
|
||||
{
|
||||
m_backButton = button;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void UMenuScreenSubMenu::NativeOnMenuAction(EMenuActionBinding binding)
|
||||
{
|
||||
Super::NativeOnMenuAction(binding);
|
||||
if(binding == EMenuActionBinding::Back)
|
||||
{
|
||||
if(m_backButton)
|
||||
{
|
||||
m_backButton->SimulatePressed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
135
Source/UnrealProject/GUI/Menu/MenuScreen.h
Normal file
135
Source/UnrealProject/GUI/Menu/MenuScreen.h
Normal file
@@ -0,0 +1,135 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GUI/Menu/MenuScreenBase.h"
|
||||
#include "SubMenu.h"
|
||||
#include "MenuScreen.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UMenuScreenSubMenu : public USubMenu
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UMenuScreenSubMenu(const FObjectInitializer& init);
|
||||
virtual void NativeConstruct() override;
|
||||
virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;
|
||||
|
||||
virtual void OnSuspend(USubMenu* newSubMenu, bool loseFocus);
|
||||
virtual void OnRestore(USubMenu* removedMenu);
|
||||
|
||||
void FadeIn();
|
||||
void FadeOut();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Menu Screen")
|
||||
UMenuPanel* OpenScreenMenu(TSubclassOf<class UMenuPanel> cls);
|
||||
UFUNCTION(BlueprintCallable, Category = "Menu Screen")
|
||||
USideView* OpenSideView(TSubclassOf<class USideView> cls);
|
||||
|
||||
class UMenuButton* AddButton(FString label);
|
||||
|
||||
virtual void RescanItems() override;
|
||||
virtual void NativeOnMenuAction(EMenuActionBinding binding) override;
|
||||
|
||||
// Assigns a button to be the back button, this button will receive a pressed event when the player presses the circle button
|
||||
void SetBackButton(UMenuButton* button) { m_backButton = button; }
|
||||
|
||||
DECLARE_MULTICAST_DELEGATE_TwoParams(FOnAnimationEnded, UMenuScreenSubMenu*, int32)
|
||||
FOnAnimationEnded onAnimationEnded;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, Category = "SubMenu")
|
||||
FString menuName;
|
||||
|
||||
private:
|
||||
UPROPERTY()
|
||||
UMenuButton* m_backButton;
|
||||
|
||||
int32 m_animationType;
|
||||
float m_animationTime;
|
||||
bool m_isBeingClosed;
|
||||
friend class UMenuScreen;
|
||||
};
|
||||
|
||||
UCLASS()
|
||||
class USideView : public UMenuScreenSubMenu
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
virtual ~USideView() = default;
|
||||
};
|
||||
|
||||
UCLASS()
|
||||
class UPersistentSideView : public USideView
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
virtual ~UPersistentSideView() = default;
|
||||
};
|
||||
|
||||
UCLASS()
|
||||
class UMenuPanel : public UMenuScreenSubMenu
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API UMenuScreen : public UMenuScreenBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
void NativeConstruct() override;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Menu Screen")
|
||||
UMenuPanel* OpenScreenMenu(TSubclassOf<class UMenuPanel> cls);
|
||||
UFUNCTION(BlueprintCallable, Category = "Menu Screen")
|
||||
USideView* OpenSideView(TSubclassOf<class USideView> cls);
|
||||
UFUNCTION(BlueprintCallable, Category = "Menu Screen")
|
||||
void CloseAllSideViews();
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent, Category="Menu Screen")
|
||||
void SwitchSideViewVisible(bool visible);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Menu Screen")
|
||||
void OpenPersistentSideView(UPersistentSideView* sideView);
|
||||
UFUNCTION(BlueprintCallable, Category = "Menu Screen")
|
||||
void ClosePersistentSideView(UPersistentSideView* sideView);
|
||||
|
||||
// When this menu needs to be hidden
|
||||
UFUNCTION(BlueprintImplementableEvent)
|
||||
void OnShow();
|
||||
// When this menu needs to be shown
|
||||
UFUNCTION(BlueprintImplementableEvent)
|
||||
void OnHide();
|
||||
|
||||
virtual void OpenSubMenu(class USubMenu* submenu) override;
|
||||
virtual void CloseSubMenu(class USubMenu* submenu) override;
|
||||
|
||||
private:
|
||||
void m_OpenSubMenu(class USubMenu* submenu, bool transferFocus = true);
|
||||
void m_CloseSubMenu(class USubMenu* submenu, bool persist = false);
|
||||
void m_OnFadeOutComplete(UMenuScreenSubMenu* panel, int32 type);
|
||||
|
||||
bool m_sideViewActive;
|
||||
|
||||
UButtonHintBar* m_buttonHintBar;
|
||||
UOverlay* m_menuContainer;
|
||||
UOverlay* m_sideViewContainer;
|
||||
UTextBlock* m_menuTitle;
|
||||
UTextBlock* m_sideViewTitle;
|
||||
|
||||
UPROPERTY()
|
||||
TArray<USideView*> m_currentSideViews;
|
||||
|
||||
friend class UMenuScreenSubMenu;
|
||||
};
|
||||
|
||||
UCLASS()
|
||||
class UMainMenuScreen : public UMenuScreen
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
};
|
||||
122
Source/UnrealProject/GUI/Menu/MenuScreenBase.cpp
Normal file
122
Source/UnrealProject/GUI/Menu/MenuScreenBase.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "MenuScreenBase.h"
|
||||
#include "PlayerControllerBase.h"
|
||||
#include "SubMenu.h"
|
||||
#include "WidgetBlueprintLibrary.h"
|
||||
|
||||
UMenuScreenBase::UMenuScreenBase(const FObjectInitializer& init)
|
||||
: Super(init)
|
||||
{
|
||||
registerMenuActions = false;
|
||||
}
|
||||
void UMenuScreenBase::NativeConstruct()
|
||||
{
|
||||
Super::NativeConstruct();
|
||||
APlayerControllerBase* pcb = Cast<APlayerControllerBase>(GetWorld()->GetFirstPlayerController());
|
||||
if(registerMenuActions && pcb)
|
||||
{
|
||||
pcb->AddMenuInputItem(this);
|
||||
}
|
||||
}
|
||||
void UMenuScreenBase::NativeDestruct()
|
||||
{
|
||||
Super::NativeDestruct();
|
||||
APlayerControllerBase* pcb = Cast<APlayerControllerBase>(GetWorld()->GetFirstPlayerController());
|
||||
if(registerMenuActions && pcb)
|
||||
{
|
||||
pcb->RemoveMenuInputItem(this);
|
||||
}
|
||||
}
|
||||
|
||||
void UMenuScreenBase::OpenSubMenu(class USubMenu* submenu)
|
||||
{
|
||||
if(m_subMenus.Contains(submenu))
|
||||
{
|
||||
GWARNING("Submenu already active");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!submenu)
|
||||
{
|
||||
GWWARNING(L"Invalid submenu passed to OpenSubMenu");
|
||||
return;
|
||||
}
|
||||
|
||||
submenu->OnEnter(this);
|
||||
if(m_subMenus.Num() > 0)
|
||||
{
|
||||
m_subMenus.Last()->OnSuspend(submenu, true);
|
||||
}
|
||||
m_subMenus.Add(submenu);
|
||||
|
||||
UWidgetBlueprintLibrary::SetFocusToGameViewport();
|
||||
}
|
||||
void UMenuScreenBase::CloseActiveSubMenu()
|
||||
{
|
||||
if(m_subMenus.Num() > 0)
|
||||
{
|
||||
CloseSubMenu(m_subMenus.Last());
|
||||
}
|
||||
else
|
||||
{
|
||||
GWWARNING("No SubMenus to close");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void UMenuScreenBase::CloseSubMenu(class USubMenu* submenu)
|
||||
{
|
||||
if(!m_subMenus.Contains(submenu))
|
||||
return;
|
||||
|
||||
submenu->OnLeave();
|
||||
|
||||
// Restore underlying menus if that was the top-most menu
|
||||
if(m_subMenus.Num() > 1)
|
||||
{
|
||||
bool wasLast = m_subMenus.Last() == submenu;
|
||||
m_subMenus.Remove(submenu);
|
||||
if(wasLast)
|
||||
{
|
||||
m_subMenus.Last()->OnRestore(submenu);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove last menu
|
||||
m_subMenus.Remove(submenu);
|
||||
}
|
||||
|
||||
UWidgetBlueprintLibrary::SetFocusToGameViewport();
|
||||
}
|
||||
|
||||
TArray<class USubMenu*> UMenuScreenBase::GetSubMenus()
|
||||
{
|
||||
return m_subMenus;
|
||||
}
|
||||
class USubMenu* UMenuScreenBase::GetActiveSubMenu()
|
||||
{
|
||||
if(m_subMenus.Num() == 0)
|
||||
return nullptr;
|
||||
return m_subMenus.Last();
|
||||
}
|
||||
|
||||
void UMenuScreenBase::SetButtonHintBar(class UButtonHintBar* bar)
|
||||
{
|
||||
m_buttonHintBar = bar;
|
||||
}
|
||||
class UButtonHintBar* UMenuScreenBase::GetButtonHintBar() const
|
||||
{
|
||||
return m_buttonHintBar;
|
||||
}
|
||||
|
||||
void UMenuScreenBase::NativeOnMenuAction(EMenuActionBinding action)
|
||||
{
|
||||
if(m_subMenus.Num() > 0)
|
||||
{
|
||||
m_subMenus.Last()->NativeOnMenuAction(action);
|
||||
}
|
||||
Super::NativeOnMenuAction(action);
|
||||
}
|
||||
52
Source/UnrealProject/GUI/Menu/MenuScreenBase.h
Normal file
52
Source/UnrealProject/GUI/Menu/MenuScreenBase.h
Normal file
@@ -0,0 +1,52 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MenuItemBase.h"
|
||||
#include "Blueprint/UserWidget.h"
|
||||
#include "MenuScreenBase.generated.h"
|
||||
|
||||
/**
|
||||
* Base class for a menu item with controller navigation/input support
|
||||
*/
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API UMenuScreenBase : public UMenuItemBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UMenuScreenBase(const FObjectInitializer& init);
|
||||
void NativeConstruct() override;
|
||||
void NativeDestruct() override;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "MenuScreen")
|
||||
virtual void OpenSubMenu(class USubMenu* submenu);
|
||||
UFUNCTION(BlueprintCallable, Category = "MenuScreen")
|
||||
void CloseActiveSubMenu();
|
||||
UFUNCTION(BlueprintCallable, Category = "MenuScreen")
|
||||
virtual void CloseSubMenu(class USubMenu* submenu);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "MenuScreen")
|
||||
TArray<class USubMenu*> GetSubMenus();
|
||||
UFUNCTION(BlueprintCallable, Category = "MenuScreen")
|
||||
class USubMenu* GetActiveSubMenu();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "MenuScreen")
|
||||
void SetButtonHintBar(class UButtonHintBar* bar);
|
||||
UFUNCTION(BlueprintCallable, Category = "MenuScreen")
|
||||
class UButtonHintBar* GetButtonHintBar() const;
|
||||
|
||||
void OnItemSelected();
|
||||
|
||||
virtual void NativeOnMenuAction(EMenuActionBinding action) override;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = "MenuScreen")
|
||||
bool registerMenuActions;
|
||||
|
||||
protected:
|
||||
UPROPERTY()
|
||||
TArray<class USubMenu*> m_subMenus;
|
||||
|
||||
UPROPERTY()
|
||||
class UButtonHintBar* m_buttonHintBar;
|
||||
};
|
||||
139
Source/UnrealProject/GUI/Menu/MenuSlider.cpp
Normal file
139
Source/UnrealProject/GUI/Menu/MenuSlider.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
#include "UnrealProject.h"
|
||||
#include "MenuSlider.h"
|
||||
#include "SizeBorder.h"
|
||||
|
||||
void UMenuSliderButton::NativeConstruct()
|
||||
{
|
||||
m_button = Cast<UButton>(WidgetTree->FindWidget("Button"));
|
||||
m_dragBorder = Cast<UBorder>(WidgetTree->FindWidget("DragBorder"));
|
||||
m_text = Cast<UTextBlock>(WidgetTree->FindWidget("Text"));
|
||||
m_button->OnPressed.AddDynamic(this, &UMenuSliderButton::m_OnPressed);
|
||||
m_panel = Cast<UCanvasPanel>(GetParent());
|
||||
|
||||
m_dragging = false;
|
||||
|
||||
Super::NativeConstruct();
|
||||
SetSelected(false);
|
||||
}
|
||||
void UMenuSliderButton::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
|
||||
{
|
||||
UCanvasPanelSlot* canvasSlot = Cast<UCanvasPanelSlot>(Slot);
|
||||
canvasSlot->SetAlignment(FVector2D(0.0f, 0.0f));
|
||||
|
||||
if(m_parent)
|
||||
{
|
||||
float totalPixelWidth = m_parent->m_sizeBorder->pixelSize.X;
|
||||
float totalWidth = m_parent->m_sizeBorder->viewportSize.X;
|
||||
float totalHeight = m_parent->m_sizeBorder->viewportSize.Y;
|
||||
|
||||
float buttonSize = totalWidth * 0.2f;
|
||||
totalPixelWidth -= totalPixelWidth * 0.2f;
|
||||
totalWidth -= buttonSize;
|
||||
|
||||
if(m_dragging)
|
||||
{
|
||||
float mouseX, mouseY;
|
||||
GetOwningPlayer()->GetMousePosition(mouseX, mouseY);
|
||||
float delta = (mouseX - m_dragStart.X) / (totalPixelWidth);
|
||||
m_parent->value = FMath::Clamp(m_dragStartValue + delta, 0.0f, 1.0f);
|
||||
|
||||
if(!m_dragBorder->IsHovered() && !m_button->IsHovered())
|
||||
{
|
||||
m_EndDrag();
|
||||
}
|
||||
UpdateText();
|
||||
}
|
||||
|
||||
canvasSlot->SetPosition(FVector2D(m_parent->value * totalWidth, 0.0f));
|
||||
canvasSlot->SetSize(FVector2D(buttonSize, totalHeight));
|
||||
}
|
||||
Super::NativeTick(MyGeometry, InDeltaTime);
|
||||
}
|
||||
|
||||
void UMenuSliderButton::UpdateText()
|
||||
{
|
||||
FString txt = FString::FromInt((int)(m_parent->value * 100)) + "%";
|
||||
m_text->SetText(FText::FromString(txt));
|
||||
}
|
||||
|
||||
void UMenuSliderButton::SetSelected(bool selected)
|
||||
{
|
||||
if(selected)
|
||||
{
|
||||
m_button->SetBackgroundColor(FLinearColor(0.3f, 0.3f, 1.0f, 0.8f));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_button->SetBackgroundColor(FLinearColor(0.7f, 0.7f, 0.7f, 0.8f));
|
||||
}
|
||||
}
|
||||
|
||||
void UMenuSliderButton::m_OnPressed()
|
||||
{
|
||||
float mouseX, mouseY;
|
||||
if(m_parent)
|
||||
{
|
||||
GetOwningPlayer()->GetMousePosition(mouseX, mouseY);
|
||||
m_dragStart = FVector2D(mouseX, mouseY);
|
||||
m_dragStartValue = m_parent->value;
|
||||
m_dragging = true;
|
||||
m_dragBorder->SetVisibility(ESlateVisibility::Visible);
|
||||
}
|
||||
}
|
||||
|
||||
void UMenuSliderButton::m_EndDrag()
|
||||
{
|
||||
m_dragging = false;
|
||||
m_dragBorder->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
|
||||
}
|
||||
|
||||
FReply UMenuSliderButton::NativeOnMouseButtonUp(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent)
|
||||
{
|
||||
m_EndDrag();
|
||||
return FReply::Unhandled();
|
||||
}
|
||||
|
||||
UMenuSlider::UMenuSlider(const FObjectInitializer& init)
|
||||
: Super(init)
|
||||
{
|
||||
stepGranularity = 1.0f / 25;
|
||||
value = 0.5f;
|
||||
}
|
||||
|
||||
void UMenuSlider::NativeConstruct()
|
||||
{
|
||||
Super::NativeConstruct();
|
||||
|
||||
m_sizeBorder = Cast<USizeBorder>(WidgetTree->FindWidget("SizeBorder"));
|
||||
m_sliderButton = Cast<UMenuSliderButton>(WidgetTree->FindWidget("SliderButton"));
|
||||
m_sliderButton->m_parent = this;
|
||||
}
|
||||
|
||||
void UMenuSlider::SetValue(float _value)
|
||||
{
|
||||
value = FMath::Clamp(_value, 0.0f, 1.0f);
|
||||
m_sliderButton->UpdateText();
|
||||
}
|
||||
|
||||
void UMenuSlider::NativeOnMenuAction(EMenuActionBinding binding)
|
||||
{
|
||||
switch(binding)
|
||||
{
|
||||
case EMenuActionBinding::Left:
|
||||
case EMenuActionBinding::Repeat_Left:
|
||||
SetValue(value - stepGranularity);
|
||||
break;
|
||||
case EMenuActionBinding::Right:
|
||||
case EMenuActionBinding::Repeat_Right:
|
||||
SetValue(value + stepGranularity);
|
||||
break;
|
||||
}
|
||||
Super::NativeOnMenuAction(binding);
|
||||
}
|
||||
|
||||
void UMenuSlider::NativeOnSelectionChanged(bool selected, bool controller)
|
||||
{
|
||||
Super::NativeOnSelectionChanged(selected, controller);
|
||||
if(m_sliderButton)
|
||||
m_sliderButton->SetSelected(selected);
|
||||
}
|
||||
61
Source/UnrealProject/GUI/Menu/MenuSlider.h
Normal file
61
Source/UnrealProject/GUI/Menu/MenuSlider.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include "MenuButton.h"
|
||||
#include "MenuSlider.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UMenuSliderButton : public UMenuItemBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
void NativeConstruct() override ;
|
||||
void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;
|
||||
|
||||
void UpdateText();
|
||||
|
||||
void SetSelected(bool selected);
|
||||
|
||||
private:
|
||||
UFUNCTION()
|
||||
void m_OnPressed();
|
||||
void m_EndDrag();
|
||||
|
||||
FReply NativeOnMouseButtonUp(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override;
|
||||
|
||||
friend class UMenuSlider;
|
||||
class UMenuSlider* m_parent;
|
||||
UBorder* m_dragBorder;
|
||||
UButton* m_button;
|
||||
UTextBlock* m_text;
|
||||
UCanvasPanel* m_panel;
|
||||
FVector2D m_dragStart;
|
||||
float m_dragStartValue;
|
||||
bool m_dragging;
|
||||
};
|
||||
|
||||
UCLASS()
|
||||
class UMenuSlider : public UMenuButton
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UMenuSlider(const FObjectInitializer& init);
|
||||
void NativeConstruct() override;
|
||||
void NativeOnMenuAction(EMenuActionBinding binding) override;
|
||||
|
||||
void NativeOnSelectionChanged(bool selected, bool controller) override;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Slider")
|
||||
void SetValue(float value);
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Slider")
|
||||
float value;
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = "Slider")
|
||||
float stepGranularity;
|
||||
|
||||
private:
|
||||
friend class UMenuSliderButton;
|
||||
class USizeBorder* m_sizeBorder;
|
||||
class UMenuSliderButton* m_sliderButton;
|
||||
|
||||
};
|
||||
78
Source/UnrealProject/GUI/Menu/OverlayMessageBox.cpp
Normal file
78
Source/UnrealProject/GUI/Menu/OverlayMessageBox.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "OverlayMessageBox.h"
|
||||
#include "ScreenOverlay.h"
|
||||
|
||||
void UOverlayMessageBoxItem::NativeConstruct()
|
||||
{
|
||||
m_label = Cast<UTextBlock>(WidgetTree->FindWidget("Label"));
|
||||
onPressed.AddDynamic(this, &UOverlayMessageBoxItem::m_OnPressed);
|
||||
Super::NativeConstruct();
|
||||
}
|
||||
void UOverlayMessageBoxItem::SetText(const FString& text)
|
||||
{
|
||||
if(!m_label)
|
||||
{
|
||||
GERROR("UOverlayMessageBoxItem Label not set on " + GetName());
|
||||
return;
|
||||
}
|
||||
m_label->SetText(FText::FromString(text));
|
||||
}
|
||||
|
||||
void UOverlayMessageBoxItem::m_OnPressed()
|
||||
{
|
||||
//Cast<UOverlayMessageBox>(GetSubMenu())->returnCode = index;
|
||||
//UMenuScreenBase* screen = GetSubMenu()->GetScreen();
|
||||
//check(m_info);
|
||||
m_info->Close(index);
|
||||
//if(screen)
|
||||
// screen->CloseActiveSubMenu();
|
||||
//else
|
||||
// GERROR("screen == nullptr, should not happen");
|
||||
}
|
||||
|
||||
void UOverlayMessageBox::NativeConstruct()
|
||||
{
|
||||
Super::NativeConstruct();
|
||||
|
||||
m_buttonContainer = Cast<UHorizontalBox>(WidgetTree->FindWidget("ButtonContainer"));
|
||||
m_caption = Cast<UTextBlock>(WidgetTree->FindWidget("Caption"));
|
||||
m_message = Cast<UTextBlock>(WidgetTree->FindWidget("Message"));
|
||||
}
|
||||
|
||||
void UOverlayMessageBox::SetMessageBoxInfo(class UMsgBoxInfo* info)
|
||||
{
|
||||
if(!buttonItemClass)
|
||||
{
|
||||
GERROR("Button item class not set on " + GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
m_buttonContainer->ClearChildren();
|
||||
|
||||
m_info = info;
|
||||
|
||||
UOverlayMessageBoxItem* selectItem = 0;
|
||||
for(FString option : info->options)
|
||||
{
|
||||
UOverlayMessageBoxItem* item = CreateWidget<UOverlayMessageBoxItem>(GetWorld(), buttonItemClass);
|
||||
item->m_info = info;
|
||||
|
||||
UHorizontalBoxSlot* slot = Cast<UHorizontalBoxSlot>(m_buttonContainer->AddChild(item));
|
||||
slot->SetHorizontalAlignment(HAlign_Fill);
|
||||
slot->SetVerticalAlignment(VAlign_Fill);
|
||||
slot->SetSize(FSlateChildSize(ESlateSizeRule::Fill));
|
||||
item->SetButtonText(option);
|
||||
if(option == info->defaultOption)
|
||||
selectItem = item;
|
||||
else if(!selectItem)
|
||||
selectItem = item;
|
||||
}
|
||||
|
||||
m_caption->SetText(FText::FromString(info->caption));
|
||||
m_message->SetText(FText::FromString(info->message));
|
||||
|
||||
RescanItems();
|
||||
SelectNewItem(selectItem);
|
||||
}
|
||||
46
Source/UnrealProject/GUI/Menu/OverlayMessageBox.h
Normal file
46
Source/UnrealProject/GUI/Menu/OverlayMessageBox.h
Normal file
@@ -0,0 +1,46 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SubMenu.h"
|
||||
#include "MenuButton.h"
|
||||
#include "OverlayMessageBox.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UOverlayMessageBoxItem : public UMenuButton
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
virtual void NativeConstruct() override;
|
||||
void SetText(const FString& text);
|
||||
private:
|
||||
void m_OnPressed();
|
||||
|
||||
friend class UOverlayMessageBox;
|
||||
UTextBlock* m_label;
|
||||
class UMsgBoxInfo* m_info;
|
||||
};
|
||||
|
||||
UCLASS()
|
||||
class UOverlayMessageBox : public USubMenu
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
virtual void NativeConstruct() override;
|
||||
|
||||
void SetMessageBoxInfo(class UMsgBoxInfo* info);
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, Category = "MsgBox")
|
||||
int32 returnCode;
|
||||
UPROPERTY(EditDefaultsOnly, Category = "MsgBox")
|
||||
TSubclassOf<UOverlayMessageBoxItem> buttonItemClass;
|
||||
|
||||
private:
|
||||
UPROPERTY()
|
||||
UHorizontalBox* m_buttonContainer;
|
||||
UPROPERTY()
|
||||
UTextBlock* m_caption;
|
||||
UPROPERTY()
|
||||
UTextBlock* m_message;
|
||||
class UMsgBoxInfo* m_info;
|
||||
};
|
||||
24
Source/UnrealProject/GUI/Menu/OverlayProgressBar.cpp
Normal file
24
Source/UnrealProject/GUI/Menu/OverlayProgressBar.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "OverlayProgressBar.h"
|
||||
#include "ScreenOverlay.h"
|
||||
|
||||
void UOverlayProgressBar::NativeConstruct()
|
||||
{
|
||||
m_text = Cast<UTextBlock>(WidgetTree->FindWidget("Text"));
|
||||
if(!m_text)
|
||||
{
|
||||
GERROR("No \"Text\" element in overlay progress bar");
|
||||
}
|
||||
|
||||
Super::NativeConstruct();
|
||||
}
|
||||
|
||||
void UOverlayProgressBar::SetOverlayInfo(class UOverlayInfo* info)
|
||||
{
|
||||
if(m_text)
|
||||
{
|
||||
m_text->SetText(FText::FromString(info->message));
|
||||
}
|
||||
}
|
||||
23
Source/UnrealProject/GUI/Menu/OverlayProgressBar.h
Normal file
23
Source/UnrealProject/GUI/Menu/OverlayProgressBar.h
Normal file
@@ -0,0 +1,23 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GUI/Menu/SubMenu.h"
|
||||
#include "OverlayProgressBar.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API UOverlayProgressBar : public USubMenu
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
virtual void NativeConstruct();
|
||||
|
||||
// Updates the text,etc. on the progress bar overlay
|
||||
void SetOverlayInfo(class UOverlayInfo* info);
|
||||
|
||||
private:
|
||||
UTextBlock* m_text;
|
||||
};
|
||||
78
Source/UnrealProject/GUI/Menu/ScoreBoard.cpp
Normal file
78
Source/UnrealProject/GUI/Menu/ScoreBoard.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "ScoreBoardSlot.h"
|
||||
#include "DefaultPlayerState.h"
|
||||
#include "GameStateBase.h"
|
||||
#include "TeamData.h"
|
||||
#include "ScoreBoard.h"
|
||||
|
||||
|
||||
UScoreBoard::UScoreBoard(const FObjectInitializer& init) : Super(init)
|
||||
{
|
||||
teamData = ConstructorHelpers::FObjectFinder<UTeamData>(TEXT("/Game/Assets/TeamData")).Object;
|
||||
}
|
||||
|
||||
void UScoreBoard::Init(UVerticalBox* container)
|
||||
{
|
||||
m_container = container;
|
||||
|
||||
// Precreate the widgets so that we can utilize them later
|
||||
if (IsValid(scoreBoardSlot) && IsValid(m_container))
|
||||
{
|
||||
for (int32 i = 0; i < 8; i++)
|
||||
{
|
||||
UScoreBoardSlot* widget = CreateWidget<UScoreBoardSlot>(GetWorld(), scoreBoardSlot);
|
||||
m_container->AddChild(widget);
|
||||
m_slots.Add(widget);
|
||||
widget->SetVisibility(ESlateVisibility::Hidden);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UScoreBoard::UpdateScoreBoard(int32 sort)
|
||||
{
|
||||
UWorld* world = GetWorld();
|
||||
if (!IsValid(world)) return;
|
||||
AGameStateBase* gameState = Cast<AGameStateBase>(world->GetGameState());
|
||||
if (!IsValid(gameState)) return;
|
||||
|
||||
TArray<APlayerStateBase*> players = gameState->GetPlayers();
|
||||
|
||||
// Fetch and update
|
||||
TArray<ADefaultPlayerState*> playersSorted;
|
||||
for (int32 i = 0; i < players.Num(); i++)
|
||||
{
|
||||
ADefaultPlayerState* const state = Cast<ADefaultPlayerState>(players[i]);
|
||||
if (!IsValid(state)) continue;
|
||||
state->UpdatePersona();
|
||||
playersSorted.Add(state);
|
||||
}
|
||||
|
||||
// Sort based on category
|
||||
if(sort == 0)
|
||||
playersSorted.Sort([](const ADefaultPlayerState& i, const ADefaultPlayerState& j)->bool { return i.nickname < j.nickname; });
|
||||
else if(sort == 1)
|
||||
playersSorted.Sort([](const ADefaultPlayerState& i, const ADefaultPlayerState& j)->bool { return i.kills > j.kills; });
|
||||
else if (sort == 2)
|
||||
playersSorted.Sort([](const ADefaultPlayerState& i, const ADefaultPlayerState& j)->bool { return i.deaths > j.deaths; });
|
||||
else if (sort == 3)
|
||||
playersSorted.Sort([](const ADefaultPlayerState& i, const ADefaultPlayerState& j)->bool { return float(i.kills) / float(i.deaths) > float(j.kills) / float(j.deaths); });
|
||||
|
||||
// Activate the slots and set them to the person
|
||||
for (int32 i = 0; i < m_slots.Num(); i++)
|
||||
{
|
||||
if (i >= playersSorted.Num())
|
||||
{
|
||||
m_slots[i]->SetVisibility(ESlateVisibility::Hidden);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
m_slots[i]->SetVisibility(ESlateVisibility::Visible);
|
||||
|
||||
ADefaultPlayerState* const state = playersSorted[i];
|
||||
|
||||
m_slots[i]->SetVisibility(ESlateVisibility::Visible);
|
||||
m_slots[i]->Update(state->avatar, FText::FromString(state->nickname), state->kills, state->deaths, teamData->GetTeamColor(state->GetTeam()));
|
||||
}
|
||||
}
|
||||
34
Source/UnrealProject/GUI/Menu/ScoreBoard.h
Normal file
34
Source/UnrealProject/GUI/Menu/ScoreBoard.h
Normal file
@@ -0,0 +1,34 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Blueprint/UserWidget.h"
|
||||
#include "ScoreBoard.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API UScoreBoard : public UUserWidget
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
|
||||
public:
|
||||
UScoreBoard(const FObjectInitializer& init);
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = "Score Board")
|
||||
TSubclassOf<class UScoreBoardSlot> scoreBoardSlot;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Score Board")
|
||||
void Init(class UVerticalBox* container);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Score Board")
|
||||
void UpdateScoreBoard(int32 sort);
|
||||
|
||||
UPROPERTY(BlueprintReadonly, Category = "SCore Board")
|
||||
class UTeamData* teamData;
|
||||
private:
|
||||
class UVerticalBox* m_container;
|
||||
TArray<class UScoreBoardSlot*> m_slots;
|
||||
};
|
||||
4
Source/UnrealProject/GUI/Menu/ScoreBoardSlot.cpp
Normal file
4
Source/UnrealProject/GUI/Menu/ScoreBoardSlot.cpp
Normal file
@@ -0,0 +1,4 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "ScoreBoardSlot.h"
|
||||
19
Source/UnrealProject/GUI/Menu/ScoreBoardSlot.h
Normal file
19
Source/UnrealProject/GUI/Menu/ScoreBoardSlot.h
Normal file
@@ -0,0 +1,19 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Blueprint/UserWidget.h"
|
||||
#include "ScoreBoardSlot.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API UScoreBoardSlot : public UUserWidget
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = "Score Board Slot")
|
||||
void Update(UTexture2D* image, const FText& name, int32 kills, int32 deaths, const FLinearColor& color);
|
||||
};
|
||||
195
Source/UnrealProject/GUI/Menu/ScreenOverlay.cpp
Normal file
195
Source/UnrealProject/GUI/Menu/ScreenOverlay.cpp
Normal file
@@ -0,0 +1,195 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "ScreenOverlay.h"
|
||||
#include "OverlayMessageBox.h"
|
||||
#include "OverlayProgressBar.h"
|
||||
|
||||
UScreenOverlay::UScreenOverlay(const FObjectInitializer& init)
|
||||
: Super(init)
|
||||
{
|
||||
}
|
||||
void UScreenOverlay::NativeConstruct()
|
||||
{
|
||||
Super::NativeConstruct();
|
||||
m_msgBox = Cast<UOverlayMessageBox>(WidgetTree->FindWidget("MessageBox"));
|
||||
m_progressBar = Cast<UOverlayProgressBar>(WidgetTree->FindWidget("ProgressBar"));
|
||||
m_background = Cast<UBorder>(WidgetTree->FindWidget("Background"));
|
||||
check(m_msgBox);
|
||||
check(m_progressBar);
|
||||
check(m_background);
|
||||
UpdateOverlays();
|
||||
UpdateMsgBoxes();
|
||||
UpdateVisiblity();
|
||||
m_msgBox->onClosed.AddDynamic(this, &UScreenOverlay::OnMessageBoxClosed);
|
||||
}
|
||||
void UScreenOverlay::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
|
||||
{
|
||||
Super::NativeTick(MyGeometry, InDeltaTime);
|
||||
|
||||
// Check all active screen overlays, remove the inactive ones
|
||||
for(int32 i = 0; i < m_overlayItems.Num();)
|
||||
{
|
||||
if(m_overlayItems[i]->m_remove)
|
||||
{
|
||||
m_overlayItems.RemoveAt(i);
|
||||
UpdateOverlays();
|
||||
UpdateVisiblity();
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the currently shown message box, remove it if inactive
|
||||
UMsgBoxInfo* msgBox = GetMessageBoxItem();
|
||||
if(msgBox && msgBox->m_remove)
|
||||
{
|
||||
if(msgBox->onClosed.IsBound())
|
||||
{
|
||||
msgBox->onClosed.Execute(msgBox->m_closeResult);
|
||||
}
|
||||
m_messageBoxItems.Remove(msgBox);
|
||||
UpdateMsgBoxes();
|
||||
UpdateVisiblity();
|
||||
|
||||
// Show remaining message boxes
|
||||
if(m_messageBoxItems.Num() > 0)
|
||||
{
|
||||
OpenSubMenu(m_msgBox);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UOverlayInfo* UScreenOverlay::ShowOverlay(FString message)
|
||||
{
|
||||
// Add a new overlay item to the list
|
||||
UOverlayInfo* info = NewObject<UOverlayInfo>();
|
||||
info->message = message;
|
||||
m_overlayItems.Add(info);
|
||||
|
||||
// Update Widget blueprint
|
||||
UpdateOverlays();
|
||||
UpdateVisiblity();
|
||||
return info;
|
||||
}
|
||||
|
||||
UMsgBoxInfo* UScreenOverlay::ShowMessageBox(FString caption, FString message, TArray<FString> options, FString def /*= FString()*/)
|
||||
{
|
||||
// Add a new message box at the end of the queue
|
||||
UMsgBoxInfo* info = NewObject<UMsgBoxInfo>();
|
||||
info->message = message;
|
||||
info->caption = caption;
|
||||
info->options = options;
|
||||
info->defaultOption = def;
|
||||
m_messageBoxItems.Add(info);
|
||||
|
||||
// Update Widget blueprint
|
||||
UpdateMsgBoxes();
|
||||
UpdateVisiblity();
|
||||
|
||||
OpenSubMenu(m_msgBox);
|
||||
|
||||
return info;
|
||||
}
|
||||
UMsgBoxInfo* UScreenOverlay::ShowMessageBoxCallback(FOverlayItemClosed cb, FString caption, FString message, TArray<FString> options, FString def /*= ""*/)
|
||||
{
|
||||
// Add a new message box at the end of the queue
|
||||
UMsgBoxInfo* info = NewObject<UMsgBoxInfo>();
|
||||
info->message = message;
|
||||
info->caption = caption;
|
||||
info->options = options;
|
||||
info->onClosed = cb;
|
||||
info->defaultOption = def;
|
||||
m_messageBoxItems.Add(info);
|
||||
|
||||
// Update Widget blueprint
|
||||
UpdateMsgBoxes();
|
||||
UpdateVisiblity();
|
||||
|
||||
OpenSubMenu(m_msgBox);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void UScreenOverlay::OnMessageBoxClosed()
|
||||
{
|
||||
m_messageBoxItems.Last()->Close(m_msgBox->returnCode);
|
||||
}
|
||||
|
||||
TArray<UOverlayInfo*>& UScreenOverlay::GetOverlayItems()
|
||||
{
|
||||
return m_overlayItems;
|
||||
}
|
||||
|
||||
UMsgBoxInfo* UScreenOverlay::GetMessageBoxItem()
|
||||
{
|
||||
if(m_messageBoxItems.Num() == 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return m_messageBoxItems[0];
|
||||
}
|
||||
void UScreenOverlay::UpdateOverlays()
|
||||
{
|
||||
if(m_overlayItems.Num() != 0)
|
||||
{
|
||||
m_progressBar->SetVisibility(ESlateVisibility::Visible);
|
||||
m_progressBar->SetOverlayInfo(m_overlayItems.Last());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_progressBar->SetVisibility(ESlateVisibility::Hidden);
|
||||
}
|
||||
}
|
||||
void UScreenOverlay::UpdateMsgBoxes()
|
||||
{
|
||||
if(m_messageBoxItems.Num() != 0)
|
||||
{
|
||||
m_msgBox->SetMessageBoxInfo(GetMessageBoxItem());
|
||||
m_msgBox->SetVisibility(ESlateVisibility::Visible);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_msgBox->SetVisibility(ESlateVisibility::Hidden);
|
||||
}
|
||||
}
|
||||
void UScreenOverlay::UpdateVisiblity()
|
||||
{
|
||||
if(m_messageBoxItems.Num() != 0 || m_overlayItems.Num() != 0)
|
||||
{
|
||||
m_background->SetVisibility(ESlateVisibility::Visible);
|
||||
blockInput = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_background->SetVisibility(ESlateVisibility::Hidden);
|
||||
blockInput = false;
|
||||
}
|
||||
}
|
||||
|
||||
UOverlayQueueItem::UOverlayQueueItem(const FObjectInitializer& init)
|
||||
: Super(init)
|
||||
{
|
||||
m_remove = false;
|
||||
}
|
||||
void UOverlayQueueItem::Close(int32 result)
|
||||
{
|
||||
m_remove = true;
|
||||
m_closeResult = result;
|
||||
}
|
||||
|
||||
UMsgBoxInfo::UMsgBoxInfo(const FObjectInitializer& init)
|
||||
: Super(init)
|
||||
{
|
||||
message = "nothing";
|
||||
options.Add("OK");
|
||||
}
|
||||
|
||||
UOverlayInfo::UOverlayInfo(const FObjectInitializer& init)
|
||||
: Super(init)
|
||||
{
|
||||
blockInput = true;
|
||||
message = "nothing";
|
||||
}
|
||||
104
Source/UnrealProject/GUI/Menu/ScreenOverlay.h
Normal file
104
Source/UnrealProject/GUI/Menu/ScreenOverlay.h
Normal file
@@ -0,0 +1,104 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
#include "MenuScreenBase.h"
|
||||
#include "ScreenOverlay.generated.h"
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EMessageBoxType : uint8
|
||||
{
|
||||
Ok,
|
||||
OkCancel,
|
||||
YesNo
|
||||
};
|
||||
|
||||
UCLASS()
|
||||
class UOverlayQueueItem : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UOverlayQueueItem(const FObjectInitializer& init);
|
||||
// Close this overlay item
|
||||
UFUNCTION(BlueprintCallable, Category = "Overlay")
|
||||
void Close(int32 result = 0);
|
||||
|
||||
UPROPERTY()
|
||||
FOverlayItemClosed onClosed;
|
||||
|
||||
private:
|
||||
friend class UScreenOverlay;
|
||||
bool m_remove;
|
||||
int32 m_closeResult;
|
||||
};
|
||||
|
||||
UCLASS()
|
||||
class UMsgBoxInfo : public UOverlayQueueItem
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UMsgBoxInfo(const FObjectInitializer& init);
|
||||
UPROPERTY(BlueprintReadOnly, Category = "MsgBox")
|
||||
FString caption;
|
||||
UPROPERTY(BlueprintReadOnly, Category = "MsgBox")
|
||||
FString message;
|
||||
UPROPERTY(BlueprintReadOnly, Category = "MsgBox")
|
||||
TArray<FString> options;
|
||||
UPROPERTY(BlueprintReadOnly, Category = "MsgBox")
|
||||
FString defaultOption;
|
||||
|
||||
};
|
||||
UCLASS()
|
||||
class UOverlayInfo : public UOverlayQueueItem
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UOverlayInfo(const FObjectInitializer& init);
|
||||
UPROPERTY(BlueprintReadOnly, Category = "MsgBox")
|
||||
FString message;
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Overlay")
|
||||
bool blockInput;
|
||||
|
||||
};
|
||||
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API UScreenOverlay : public UMenuScreenBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UScreenOverlay(const FObjectInitializer& init);
|
||||
virtual void NativeConstruct() override;
|
||||
virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Overlay")
|
||||
UOverlayInfo* ShowOverlay(FString message);
|
||||
UMsgBoxInfo* ShowMessageBox(FString caption, FString message, TArray<FString> options, FString def = "");
|
||||
UMsgBoxInfo* ShowMessageBoxCallback(FOverlayItemClosed cb, FString caption, FString message, TArray<FString> options, FString def);
|
||||
//UFUNCTION(BlueprintCallable, Category = "Overlay")
|
||||
//UMsgBoxInfo* ShowMessageBox(FOnOverlayItemClosedSingle cb, FString caption, FString message, TArray<FString> options, FString def = "");
|
||||
|
||||
UFUNCTION()
|
||||
void OnMessageBoxClosed();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Overlay")
|
||||
TArray<UOverlayInfo*>& GetOverlayItems();
|
||||
UFUNCTION(BlueprintCallable, Category = "Overlay")
|
||||
UMsgBoxInfo* GetMessageBoxItem();
|
||||
|
||||
private:
|
||||
void UpdateOverlays();
|
||||
void UpdateMsgBoxes();
|
||||
void UpdateVisiblity();
|
||||
|
||||
UPROPERTY()
|
||||
class UOverlayMessageBox* m_msgBox;
|
||||
UPROPERTY()
|
||||
class UOverlayProgressBar* m_progressBar;
|
||||
UPROPERTY()
|
||||
class UBorder* m_background;
|
||||
|
||||
UPROPERTY()
|
||||
TArray<UOverlayInfo*> m_overlayItems;
|
||||
UPROPERTY()
|
||||
TArray<UMsgBoxInfo*> m_messageBoxItems;
|
||||
|
||||
};
|
||||
10
Source/UnrealProject/GUI/Menu/SelectButton.cpp
Normal file
10
Source/UnrealProject/GUI/Menu/SelectButton.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "SelectButton.h"
|
||||
|
||||
|
||||
USelectButton::USelectButton(const FObjectInitializer& init) : UMenuButton(init)
|
||||
{
|
||||
selected = 0;
|
||||
}
|
||||
22
Source/UnrealProject/GUI/Menu/SelectButton.h
Normal file
22
Source/UnrealProject/GUI/Menu/SelectButton.h
Normal file
@@ -0,0 +1,22 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MenuButton.h"
|
||||
#include "SelectButton.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API USelectButton : public UMenuButton
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
USelectButton(const FObjectInitializer& init);
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, Category = "SelectButton")
|
||||
int32 selected;
|
||||
|
||||
};
|
||||
130
Source/UnrealProject/GUI/Menu/SkillSelector.cpp
Normal file
130
Source/UnrealProject/GUI/Menu/SkillSelector.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "SkillSelector.h"
|
||||
#include "SkillTreeObject.h"
|
||||
#include "SkillObject.h"
|
||||
#include "SkillWidget.h"
|
||||
#include "SkillSelectorItem.h"
|
||||
#include "SkillTreeWidget.h"
|
||||
#include "BaseSkillObject.h"
|
||||
#include "AbilityInfo.h"
|
||||
|
||||
TSubclassOf<class USkillSelector> defaultSkillSelector;
|
||||
|
||||
USkillSelector::USkillSelector(const FObjectInitializer& init)
|
||||
: Super(init)
|
||||
{
|
||||
defaultSkillSelector = ConstructorHelpers::FClassFinder<USkillSelector>(L"/Game/Assets/GUI/Components/WEEGEE_SkillSelector").Class;
|
||||
}
|
||||
void USkillSelector::NativeConstruct()
|
||||
{
|
||||
Super::NativeConstruct();
|
||||
|
||||
m_selectedItem = 0;
|
||||
|
||||
TArray<UWidget*> swidgets;
|
||||
m_scrollBox = WidgetTree->FindWidget<UScrollBox>("ScrollBox");
|
||||
m_border = WidgetTree->FindWidget<UBorder>("Border");
|
||||
m_sizeRoot = WidgetTree->FindWidget<USizeBox>("SizeRoot");
|
||||
if(!m_sizeRoot)
|
||||
{
|
||||
GWERROR(L"USkillSelector doesn't have a SizeRoot set");
|
||||
}
|
||||
if(!m_scrollBox)
|
||||
{
|
||||
GWERROR(L"USkillSelector doesn't have a ScrollBox set");
|
||||
}
|
||||
if(!ItemWidgetTemplate)
|
||||
{
|
||||
GWERROR(L"USkillSelector doesn't have a Item Widget Template set");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void USkillSelector::NativeOnMenuAction(EMenuActionBinding binding)
|
||||
{
|
||||
switch(binding)
|
||||
{
|
||||
case EMenuActionBinding::Left:
|
||||
SetSelection(m_selectedItem - 1);
|
||||
break;
|
||||
case EMenuActionBinding::Right:
|
||||
SetSelection(m_selectedItem + 1);
|
||||
break;
|
||||
default:
|
||||
Super::NativeOnMenuAction(binding);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void USkillSelector::SetSelection(int32 idx)
|
||||
{
|
||||
if(idx < 0 || idx >= m_scrollBox->GetChildrenCount())
|
||||
return;
|
||||
|
||||
if(m_selectedItem < m_scrollBox->GetChildrenCount())
|
||||
SetItemSelected(m_selectedItem, false);
|
||||
SetItemSelected(idx, true);
|
||||
|
||||
m_selectedItem = idx;
|
||||
|
||||
if(m_sizeRoot && m_scrollBox)
|
||||
{
|
||||
m_scrollBox->ScrollWidgetIntoView(m_items[m_selectedItem], true);
|
||||
}
|
||||
}
|
||||
|
||||
void USkillSelector::SetItemSelected(int32 item, bool selected)
|
||||
{
|
||||
m_items[item]->NativeOnSelectionChanged(selected, false);
|
||||
if(selected)
|
||||
onSkillSelectionChanged.Broadcast(m_items[item]);
|
||||
}
|
||||
|
||||
void USkillSelector::SetSkillTree(class USkillTreeWidget* skillTree)
|
||||
{
|
||||
if(!skillTree)
|
||||
return;
|
||||
this->skillTree = skillTree;
|
||||
USkillTreeObject* treeObject = skillTree->skillTreeAsset;
|
||||
if(!m_scrollBox)
|
||||
return;
|
||||
if(!ItemWidgetTemplate)
|
||||
return;
|
||||
|
||||
m_scrollBox->ClearChildren();
|
||||
m_items.SetNum(0);
|
||||
|
||||
uint32 itemIndex = 0;
|
||||
for(int32 i = 0; i < treeObject->skills.Num(); i++)
|
||||
{
|
||||
UBaseSkillObject* skill = treeObject->skills[i]->GetDefaultObject<UBaseSkillObject>();
|
||||
if(!skillShapeFilter.Contains(skill->skillShapeType))
|
||||
continue;
|
||||
|
||||
USkillSelectorItem* widget = CreateWidget<USkillSelectorItem>(GetWorld(), ItemWidgetTemplate);
|
||||
widget->baseSkillObject = skill;
|
||||
widget->index = itemIndex++;
|
||||
widget->parent = this;
|
||||
widget->skillTree = skillTree;
|
||||
m_scrollBox->AddChild(widget);
|
||||
m_items.Add(widget);
|
||||
}
|
||||
|
||||
SetSelection(FMath::Min(m_selectedItem, m_items.Num() - 1));
|
||||
}
|
||||
|
||||
USkillWidget* USkillSelector::GetSelectedSkillWidget()
|
||||
{
|
||||
if(m_selectedItem >= m_items.Num())
|
||||
return nullptr;
|
||||
return m_items[m_selectedItem]->GetSkillWidget();
|
||||
}
|
||||
|
||||
UBaseSkillObject* USkillSelector::GetSelectedSkillAsset()
|
||||
{
|
||||
if(m_selectedItem >= m_items.Num())
|
||||
return nullptr;
|
||||
return m_items[m_selectedItem]->baseSkillObject;
|
||||
}
|
||||
54
Source/UnrealProject/GUI/Menu/SkillSelector.h
Normal file
54
Source/UnrealProject/GUI/Menu/SkillSelector.h
Normal file
@@ -0,0 +1,54 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GUI/Menu/MenuButton.h"
|
||||
#include "BaseSkillObject.h"
|
||||
#include "SkillSelector.generated.h"
|
||||
|
||||
extern TSubclassOf<class USkillSelector> defaultSkillSelector;
|
||||
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API USkillSelector : public UMenuButton
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
USkillSelector(const FObjectInitializer& init);
|
||||
void NativeConstruct() override;
|
||||
virtual void NativeOnMenuAction(EMenuActionBinding binding) override;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Skill Selector")
|
||||
void SetSkillTree(class USkillTreeWidget* skillTree);
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "UI")
|
||||
class USkillTreeWidget* skillTree;
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = "UI")
|
||||
TArray<ESkillShapeType> skillShapeFilter;
|
||||
|
||||
int32 GetSelection() const { return m_selectedItem; }
|
||||
void SetSelection(int32 idx);
|
||||
void SetItemSelected(int32 item, bool selected);
|
||||
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnSkillSelectionChanged, USkillSelectorItem*, item);
|
||||
UPROPERTY(BlueprintAssignable)
|
||||
FOnSkillSelectionChanged onSkillSelectionChanged;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI")
|
||||
TSubclassOf<class USkillSelectorItem> ItemWidgetTemplate;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = UI)
|
||||
class USkillWidget* GetSelectedSkillWidget();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = UI)
|
||||
class UBaseSkillObject* GetSelectedSkillAsset();
|
||||
private:
|
||||
UPROPERTY()
|
||||
TArray<class USkillSelectorItem*> m_items;
|
||||
int32 m_selectedItem;
|
||||
|
||||
USizeBox* m_sizeRoot;
|
||||
UScrollBox* m_scrollBox;
|
||||
UBorder* m_border;
|
||||
};
|
||||
76
Source/UnrealProject/GUI/Menu/SkillSelectorItem.cpp
Normal file
76
Source/UnrealProject/GUI/Menu/SkillSelectorItem.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "SkillSelectorItem.h"
|
||||
#include "SkillSelector.h"
|
||||
#include "SkillWidget.h"
|
||||
#include "SkillTreeWidget.h"
|
||||
|
||||
void USkillSelectorItem::NativeConstruct()
|
||||
{
|
||||
Super::NativeConstruct();
|
||||
|
||||
m_skillWidget = WidgetTree->FindWidget<USkillWidget>("InnerSkillWidget");
|
||||
if(!m_skillWidget)
|
||||
{
|
||||
GWERROR(L"InnerSkillWidget not found on " + GetName());
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_skillWidget->skillAsset = baseSkillObject;
|
||||
m_skillWidget->parent = skillTree;
|
||||
m_skillWidget->UpdateSkill();
|
||||
}
|
||||
|
||||
if(m_button)
|
||||
{
|
||||
m_button->OnPressed.AddDynamic(this, &USkillSelectorItem::m_OnPressed1);
|
||||
}
|
||||
else
|
||||
{
|
||||
GWERROR(L"No button found on " + GetName());
|
||||
}
|
||||
}
|
||||
|
||||
void USkillSelectorItem::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
|
||||
{
|
||||
if(skillTree->IsUsingSkill(baseSkillObject))
|
||||
{
|
||||
this->SetIsEnabled(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->SetIsEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void USkillSelectorItem::NativeOnSelectionChanged(bool selected, bool controller)
|
||||
{
|
||||
if(selected)
|
||||
{
|
||||
m_button->SetBackgroundColor(FLinearColor(1.0f, 1.0f, 1.0f, 0.5f));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_button->SetBackgroundColor(FLinearColor(1.0f, 1.0f, 1.0f, 0.0f));
|
||||
}
|
||||
}
|
||||
|
||||
void USkillSelectorItem::m_OnPressed1()
|
||||
{
|
||||
if(!GetIsEnabled())
|
||||
return;
|
||||
|
||||
if(parent)
|
||||
{
|
||||
USubMenu* menu = parent->GetSubMenu();
|
||||
if(menu)
|
||||
menu->SelectNewItem(parent);
|
||||
|
||||
//if(parent->GetSelection() == index)
|
||||
skillTree->NewSkill(m_skillWidget);
|
||||
parent->SetSelection(index);
|
||||
//else
|
||||
}
|
||||
}
|
||||
50
Source/UnrealProject/GUI/Menu/SkillSelectorItem.h
Normal file
50
Source/UnrealProject/GUI/Menu/SkillSelectorItem.h
Normal file
@@ -0,0 +1,50 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MenuButton.h"
|
||||
#include "SkillSelectorItem.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API USkillSelectorItem : public UMenuButton
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
virtual void NativeConstruct() override;
|
||||
virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;
|
||||
|
||||
virtual void NativeOnSelectionChanged(bool selected, bool controller) override;
|
||||
//virtual FReply NativeOnMouseButtonDown(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override;
|
||||
|
||||
int32 index;
|
||||
class USkillSelector* parent;
|
||||
class UBaseSkillObject* baseSkillObject;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = UI)
|
||||
class USkillTreeWidget* skillTree;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, Category = UI)
|
||||
TSubclassOf<class USkillWidget> skillWidget;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = UI)
|
||||
USkillSelector* GetSelector() const
|
||||
{
|
||||
return parent;
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = UI)
|
||||
class USkillWidget* GetSkillWidget()
|
||||
{
|
||||
return m_skillWidget;
|
||||
}
|
||||
|
||||
private:
|
||||
UFUNCTION()
|
||||
void m_OnPressed1();
|
||||
|
||||
class USkillWidget* m_skillWidget;
|
||||
};
|
||||
96
Source/UnrealProject/GUI/Menu/SplashScreen.cpp
Normal file
96
Source/UnrealProject/GUI/Menu/SplashScreen.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "SplashScreen.h"
|
||||
#include "SplashScreenItem.h"
|
||||
#include "DefaultGameInstance.h"
|
||||
#include "SessionManager.h"
|
||||
|
||||
USplashScreen::USplashScreen(const FObjectInitializer& init)
|
||||
: Super(init)
|
||||
{
|
||||
}
|
||||
|
||||
void USplashScreen::NativeConstruct()
|
||||
{
|
||||
m_currentItem = -1;
|
||||
Super::NativeConstruct();
|
||||
}
|
||||
void USplashScreen::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
|
||||
{
|
||||
Super::NativeTick(MyGeometry, InDeltaTime);
|
||||
if(m_currentItem == -1)
|
||||
return;
|
||||
|
||||
if(m_currentItem >= m_activeScreens.Num())
|
||||
{
|
||||
OnEnd();
|
||||
// Send done event
|
||||
onDone.Broadcast();
|
||||
m_currentItem = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_switcher->SetActiveWidget(m_activeScreens[m_currentItem]);
|
||||
if(m_activeScreens[m_currentItem]->GetRate() >= 1.0f)
|
||||
{
|
||||
m_activeScreens[m_currentItem]->End();
|
||||
m_currentItem++;
|
||||
if(m_currentItem < m_activeScreens.Num())
|
||||
{
|
||||
m_activeScreens[m_currentItem]->Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void USplashScreen::NativeOnMenuAction(EMenuActionBinding binding)
|
||||
{
|
||||
if(binding == EMenuActionBinding::Start)
|
||||
{
|
||||
if(m_currentItem >= 0 && m_currentItem < m_activeScreens.Num())
|
||||
{
|
||||
m_activeScreens[m_currentItem]->Skip();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void USplashScreen::OnEnd_Implementation()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void USplashScreen::Init(UWidgetSwitcher* witcher)
|
||||
{
|
||||
m_switcher = witcher;
|
||||
m_currentItem = 0;
|
||||
|
||||
for(int32 i = 0; i < splashItems.Num(); i++)
|
||||
{
|
||||
USplashScreenItem* item = CreateWidget<USplashScreenItem>(GetWorld(), splashItems[i]);
|
||||
m_activeScreens.Add(item);
|
||||
m_switcher->AddChild(item);
|
||||
if(i == 0)
|
||||
{
|
||||
item->Start();
|
||||
if((i + 1) == splashItems.Num())
|
||||
item->fadeEnabled = false;
|
||||
m_switcher->SetActiveWidget(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float USplashScreen::GetFade() const
|
||||
{
|
||||
if(m_currentItem == -1)
|
||||
return 0.0f;
|
||||
if(m_currentItem >= m_activeScreens.Num())
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
if((m_currentItem + 1) == m_activeScreens.Num())
|
||||
{
|
||||
return m_activeScreens[m_currentItem]->GetFadeOut();
|
||||
}
|
||||
return 1.0f;
|
||||
}
|
||||
45
Source/UnrealProject/GUI/Menu/SplashScreen.h
Normal file
45
Source/UnrealProject/GUI/Menu/SplashScreen.h
Normal file
@@ -0,0 +1,45 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MenuScreenBase.h"
|
||||
#include "SplashScreen.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API USplashScreen : public UMenuScreenBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
USplashScreen(const FObjectInitializer& init);
|
||||
|
||||
virtual void NativeConstruct() override;
|
||||
virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;
|
||||
|
||||
virtual void NativeOnMenuAction(EMenuActionBinding binding) override;
|
||||
|
||||
UFUNCTION(BlueprintNativeEvent, Category = "Splash")
|
||||
void OnEnd();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Splash")
|
||||
void Init(UWidgetSwitcher* witcher);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Splash")
|
||||
float GetFade() const;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditDefaultsOnly, Category="Splash")
|
||||
TArray<TSubclassOf<class USplashScreenItem>> splashItems;
|
||||
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnSplashScreenDone);
|
||||
UPROPERTY(BlueprintAssignable, Category = "Splash")
|
||||
FOnSplashScreenDone onDone;
|
||||
|
||||
public:
|
||||
UPROPERTY()
|
||||
TArray<class USplashScreenItem*> m_activeScreens;
|
||||
int32 m_currentItem;
|
||||
UWidgetSwitcher* m_switcher;
|
||||
};
|
||||
104
Source/UnrealProject/GUI/Menu/SplashScreenItem.cpp
Normal file
104
Source/UnrealProject/GUI/Menu/SplashScreenItem.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "SplashScreenItem.h"
|
||||
#include "MediaTexture.h"
|
||||
|
||||
USplashScreenItem::USplashScreenItem(const FObjectInitializer& init)
|
||||
: Super(init)
|
||||
{
|
||||
duration = 2.0f;
|
||||
fadeDuration = 0.5f;
|
||||
m_lifetime = 0.0f;
|
||||
fadeEnabled = true;
|
||||
}
|
||||
|
||||
void USplashScreenItem::NativeConstruct()
|
||||
{
|
||||
if(duration <= 0.0f)
|
||||
{
|
||||
GWWARNING(L"Splash screen duration is zero! " + GetName());
|
||||
duration = 1.0f;
|
||||
}
|
||||
if(fadeDuration * 2.0f > duration)
|
||||
{
|
||||
GWWARNING(L"Splash screen fade time is greater than duration! " + GetName());
|
||||
fadeDuration = duration * 0.25f;
|
||||
}
|
||||
|
||||
m_started = false;
|
||||
Super::NativeConstruct();
|
||||
}
|
||||
void USplashScreenItem::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
|
||||
{
|
||||
if(m_started)
|
||||
m_lifetime += InDeltaTime;
|
||||
Super::NativeTick(MyGeometry, InDeltaTime);
|
||||
}
|
||||
|
||||
void USplashScreenItem::OnStarted_Implementation()
|
||||
{
|
||||
|
||||
}
|
||||
void USplashScreenItem::OnEnd_Implementation()
|
||||
{
|
||||
|
||||
}
|
||||
void USplashScreenItem::Skip()
|
||||
{
|
||||
if((m_lifetime + fadeDuration) < duration)
|
||||
{
|
||||
m_lifetime = duration - fadeDuration;
|
||||
}
|
||||
}
|
||||
|
||||
void USplashScreenItem::Start()
|
||||
{
|
||||
if(!m_started)
|
||||
{
|
||||
m_started = true;
|
||||
m_lifetime = 0.0f;
|
||||
OnStarted();
|
||||
}
|
||||
}
|
||||
void USplashScreenItem::End()
|
||||
{
|
||||
if(m_started)
|
||||
{
|
||||
OnEnd();
|
||||
m_started = false;
|
||||
}
|
||||
}
|
||||
|
||||
FVector2D USplashScreenItem::GetMediaSize(UMediaTexture* mediaTexture) const
|
||||
{
|
||||
if(!mediaTexture)
|
||||
return FVector2D();
|
||||
return FVector2D(mediaTexture->GetSurfaceWidth(), mediaTexture->GetSurfaceHeight());
|
||||
}
|
||||
|
||||
float USplashScreenItem::GetFade() const
|
||||
{
|
||||
float base = GetFadeOut();
|
||||
if(m_lifetime < fadeDuration)
|
||||
{
|
||||
base *= m_lifetime / fadeDuration;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
float USplashScreenItem::GetFadeOut() const
|
||||
{
|
||||
if((duration - m_lifetime) < fadeDuration)
|
||||
{
|
||||
return FMath::Min((duration - m_lifetime) / fadeDuration, 1.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
float USplashScreenItem::GetRate() const
|
||||
{
|
||||
return FMath::Clamp(m_lifetime / duration, 0.0f, 1.0f);
|
||||
}
|
||||
52
Source/UnrealProject/GUI/Menu/SplashScreenItem.h
Normal file
52
Source/UnrealProject/GUI/Menu/SplashScreenItem.h
Normal file
@@ -0,0 +1,52 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MenuItemBase.h"
|
||||
#include "SplashScreenItem.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API USplashScreenItem : public UMenuItemBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
USplashScreenItem(const FObjectInitializer& init);
|
||||
|
||||
virtual void NativeConstruct() override;
|
||||
virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;
|
||||
|
||||
UFUNCTION(BlueprintNativeEvent, Category = "SplashItem")
|
||||
void OnStarted();
|
||||
UFUNCTION(BlueprintNativeEvent, Category = "SplashItem")
|
||||
void OnEnd();
|
||||
UFUNCTION(BlueprintCallable, Category = "SplashItem")
|
||||
void Skip();
|
||||
|
||||
void Start();
|
||||
void End();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Media")
|
||||
FVector2D GetMediaSize(class UMediaTexture* mediaTexture) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="SplashItem")
|
||||
float GetFade() const;
|
||||
UFUNCTION(BlueprintCallable, Category = "SplashItem")
|
||||
float GetFadeOut() const;
|
||||
UFUNCTION(BlueprintCallable, Category="SplashItem")
|
||||
float GetRate() const;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditDefaultsOnly, Category = "SplashItem")
|
||||
float fadeDuration;
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="SplashItem")
|
||||
float duration;
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "SplashItem")
|
||||
bool fadeEnabled;
|
||||
|
||||
private:
|
||||
bool m_started;
|
||||
float m_lifetime;
|
||||
};
|
||||
10
Source/UnrealProject/GUI/Menu/StartPromptScreen.cpp
Normal file
10
Source/UnrealProject/GUI/Menu/StartPromptScreen.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "StartPromptScreen.h"
|
||||
|
||||
void UStartPromptScreen::Close()
|
||||
{
|
||||
onClosed.Broadcast();
|
||||
OnClose();
|
||||
}
|
||||
26
Source/UnrealProject/GUI/Menu/StartPromptScreen.h
Normal file
26
Source/UnrealProject/GUI/Menu/StartPromptScreen.h
Normal file
@@ -0,0 +1,26 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GUI/Menu/MenuScreenBase.h"
|
||||
#include "StartPromptScreen.generated.h"
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API UStartPromptScreen : public UMenuScreenBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintCallable, Category="Start Prompt")
|
||||
void Close();
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent)
|
||||
void OnClose();
|
||||
|
||||
DECLARE_MULTICAST_DELEGATE(FClosedEvent)
|
||||
FClosedEvent onClosed;
|
||||
};
|
||||
319
Source/UnrealProject/GUI/Menu/SubMenu.cpp
Normal file
319
Source/UnrealProject/GUI/Menu/SubMenu.cpp
Normal file
@@ -0,0 +1,319 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#include "UnrealProject.h"
|
||||
#include "SubMenu.h"
|
||||
#include "PlayerControllerBase.h"
|
||||
#include "MenuButton.h"
|
||||
#include "DefaultGameInstance.h"
|
||||
#include "MenuScreenBase.h"
|
||||
#include "EffectFunctionLibrary.h"
|
||||
#include "ScreenOverlay.h"
|
||||
|
||||
USoundBase* confirmAudioClass;
|
||||
USoundBase* backAudioClass;
|
||||
USoundBase* selectionChangedAudioClass;
|
||||
USoundBase* clickAudioClass;
|
||||
|
||||
USubMenu::USubMenu(const FObjectInitializer& init)
|
||||
{
|
||||
selectionChangedAudioClass = ConstructorHelpers::FObjectFinder<USoundBase>(TEXT("/Game/Assets/GUI/Components/InterfaceSounds/Select2")).Object;
|
||||
backAudioClass = ConstructorHelpers::FObjectFinder<USoundBase>(TEXT("/Game/Assets/GUI/Components/InterfaceSounds/Select0")).Object;
|
||||
confirmAudioClass = ConstructorHelpers::FObjectFinder<USoundBase>(TEXT("/Game/Assets/GUI/Components/InterfaceSounds/Select1")).Object;
|
||||
clickAudioClass = ConstructorHelpers::FObjectFinder<USoundBase>(TEXT("/Game/Assets/Sound/T_SkillDrop")).Object;
|
||||
}
|
||||
|
||||
void USubMenu::NativeConstruct()
|
||||
{
|
||||
m_focus = false;
|
||||
m_layoutDirection = 0;
|
||||
container = Cast<UPanelWidget>(WidgetTree->FindWidget("SubMenuContainer"));
|
||||
if(!container)
|
||||
{
|
||||
container = Cast<UPanelWidget>(GetRootWidget());
|
||||
if(!container)
|
||||
{
|
||||
GERROR("No \"Container\" found in widget " + GetName() + ", root widget was not a PanelWidget");
|
||||
}
|
||||
}
|
||||
Super::NativeConstruct();
|
||||
|
||||
m_selectedItem = 0;
|
||||
RescanItems();
|
||||
}
|
||||
void USubMenu::NativeDestruct()
|
||||
{
|
||||
Super::NativeDestruct();
|
||||
}
|
||||
|
||||
void USubMenu::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
|
||||
{
|
||||
Super::NativeTick(MyGeometry, InDeltaTime);
|
||||
if(HasFocus())
|
||||
{
|
||||
for(UMenuItemBase* item : m_items)
|
||||
{
|
||||
item->FocusTick(InDeltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void USubMenu::m_ScanContainer(UWidget* widget, int32 depth /*= 0*/)
|
||||
{
|
||||
// Loop through panel widgets
|
||||
UPanelWidget* panel = Cast<UPanelWidget>(widget);
|
||||
if(panel)
|
||||
{
|
||||
for(int32 i = 0; i < panel->GetChildrenCount(); i++)
|
||||
{
|
||||
m_ScanContainer(panel->GetChildAt(i), depth+1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Process Menu items
|
||||
UMenuItemBase* item = Cast<UMenuItemBase>(widget);
|
||||
if(item)
|
||||
{
|
||||
bool hidden = item->GetVisibility() == ESlateVisibility::Hidden || item->GetVisibility() == ESlateVisibility::Collapsed;
|
||||
if(!hidden)
|
||||
{
|
||||
m_items.Add(item);
|
||||
|
||||
// Assign item to a submenu
|
||||
item->m_subMenu = this;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
UPanelUserWidget* puw = Cast<UPanelUserWidget>(widget);
|
||||
if(puw)
|
||||
{
|
||||
m_ScanContainer(puw->GetRootWidget());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void USubMenu::RescanItems()
|
||||
{
|
||||
m_items.SetNum(0);
|
||||
if(container)
|
||||
{
|
||||
if(Cast<UHorizontalBox>(container))
|
||||
{
|
||||
m_layoutDirection = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_layoutDirection = 0;
|
||||
}
|
||||
|
||||
// Scan for buttons
|
||||
m_ScanContainer(container);
|
||||
|
||||
int32 childCount = m_items.Num();
|
||||
|
||||
// Clamp selection
|
||||
m_selectedItem = FMath::Clamp(m_selectedItem, 0, childCount - 1);
|
||||
|
||||
// Set active selection
|
||||
for(int32 i = 0; i < childCount; i++)
|
||||
{
|
||||
UMenuItemBase* item = m_items[i];
|
||||
item->index = i;
|
||||
|
||||
if(i == m_selectedItem)
|
||||
{
|
||||
item->NativeOnSelectionChanged(true, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
item->NativeOnSelectionChanged(false, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Reselect single items
|
||||
if(childCount == 1)
|
||||
{
|
||||
m_items[0]->NativeOnSelectionChanged(false, true);
|
||||
m_items[0]->NativeOnSelectionChanged(true, true);
|
||||
}
|
||||
|
||||
if(childCount > 0)
|
||||
{
|
||||
// Selection event
|
||||
onItemSelected.Broadcast(m_items[m_selectedItem]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GWWARNING(L"SubMenu Container not set");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void USubMenu::CloseSubMenu()
|
||||
{
|
||||
if(m_screen)
|
||||
m_screen->CloseSubMenu(this);
|
||||
}
|
||||
|
||||
void USubMenu::OnEnter(class UMenuScreenBase* screen)
|
||||
{
|
||||
check(screen);
|
||||
m_screen = screen;
|
||||
SetButtonHints();
|
||||
onOpened.Broadcast();
|
||||
m_SetFocus(true);
|
||||
}
|
||||
void USubMenu::OnLeave()
|
||||
{
|
||||
onClosed.Broadcast();
|
||||
m_screen = nullptr;
|
||||
m_SetFocus(false);
|
||||
}
|
||||
|
||||
bool USubMenu::HasFocus() const
|
||||
{
|
||||
return m_focus;
|
||||
}
|
||||
|
||||
void USubMenu::OnSuspend(USubMenu* newSubMenu, bool loseFocus)
|
||||
{
|
||||
if(loseFocus)
|
||||
m_SetFocus(false);
|
||||
onSuspend.Broadcast();
|
||||
}
|
||||
void USubMenu::OnRestore(USubMenu* removedMenu)
|
||||
{
|
||||
SetButtonHints();
|
||||
m_SetFocus(true);
|
||||
onRestore.Broadcast();
|
||||
}
|
||||
|
||||
class UButtonHintBar* USubMenu::GetButtonHintBar() const
|
||||
{
|
||||
return GetScreen()->GetButtonHintBar();
|
||||
}
|
||||
|
||||
class UCharacterSettings* USubMenu::GetCharacterSettings() const
|
||||
{
|
||||
return GetGameInstance()->GetCharacterSettings();
|
||||
}
|
||||
class UPrefs* USubMenu::GetPrefs() const
|
||||
{
|
||||
return GetGameInstance()->GetPrefs();
|
||||
}
|
||||
class UDefaultGameInstance* USubMenu::GetGameInstance() const
|
||||
{
|
||||
return Cast<UDefaultGameInstance>(GetWorld()->GetGameInstance());
|
||||
}
|
||||
void USubMenu::NativeOnMenuAction(EMenuActionBinding binding)
|
||||
{
|
||||
if(m_items.Num() > 0)
|
||||
m_items[m_selectedItem]->NativeOnMenuAction(binding);
|
||||
|
||||
switch(binding)
|
||||
{
|
||||
case EMenuActionBinding::Down:
|
||||
if(m_items.Num() > 0 && m_layoutDirection == 0)
|
||||
SelectNewItemByIndex(FMath::Clamp(m_selectedItem + 1, 0, GetNumItems()-1), true);
|
||||
break;
|
||||
case EMenuActionBinding::Up:
|
||||
if(m_items.Num() > 0 && m_layoutDirection == 0)
|
||||
SelectNewItemByIndex(FMath::Clamp(m_selectedItem - 1, 0, GetNumItems()-1), true);
|
||||
break;
|
||||
case EMenuActionBinding::Left:
|
||||
if(m_items.Num() > 0 && m_layoutDirection == 1)
|
||||
SelectNewItemByIndex(FMath::Clamp(m_selectedItem - 1, 0, GetNumItems() - 1), true);
|
||||
break;
|
||||
case EMenuActionBinding::Right:
|
||||
if(m_items.Num() > 0 && m_layoutDirection == 1)
|
||||
SelectNewItemByIndex(FMath::Clamp(m_selectedItem + 1, 0, GetNumItems() - 1), true);
|
||||
break;
|
||||
case EMenuActionBinding::Confirm:
|
||||
break;
|
||||
case EMenuActionBinding::Back:
|
||||
onBack.Broadcast();
|
||||
UEffectFunctionLibrary::PlaySoundEffect2D(GetWorld(), backAudioClass);
|
||||
break;
|
||||
}
|
||||
|
||||
Super::NativeOnMenuAction(binding);
|
||||
}
|
||||
|
||||
void USubMenu::NativeOnSelectionConfirmed(UMenuItemBase* item)
|
||||
{
|
||||
UEffectFunctionLibrary::PlaySoundEffect2D(GetWorld(), clickAudioClass);
|
||||
onItemSelectionConfirmed.Broadcast(m_items[m_selectedItem]);
|
||||
}
|
||||
|
||||
UMenuItemBase* USubMenu::GetItem(int32 index) const
|
||||
{
|
||||
if(index >= m_items.Num() || index < 0)
|
||||
{
|
||||
GWWARNING(L"Item index out of range");
|
||||
return nullptr;
|
||||
}
|
||||
return m_items[index];
|
||||
}
|
||||
int32 USubMenu::GetNumItems() const
|
||||
{
|
||||
return m_items.Num();
|
||||
}
|
||||
int32 USubMenu::GetSelectedItem() const
|
||||
{
|
||||
return m_selectedItem;
|
||||
}
|
||||
void USubMenu::SelectNewItemByIndex(int32 idx)
|
||||
{
|
||||
SelectNewItemByIndex(idx, false);
|
||||
}
|
||||
void USubMenu::SelectNewItemByIndex(int32 idx, bool controller)
|
||||
{
|
||||
if(idx >= m_items.Num() || idx < 0)
|
||||
{
|
||||
GWWARNING(L"Item index out of range");
|
||||
return;
|
||||
}
|
||||
if(m_selectedItem != idx)
|
||||
{
|
||||
check(m_selectedItem < m_items.Num());
|
||||
m_items[m_selectedItem]->NativeOnSelectionChanged(false, controller);
|
||||
m_items[idx]->NativeOnSelectionChanged(true, controller);
|
||||
m_selectedItem = idx;
|
||||
onItemSelected.Broadcast(m_items[m_selectedItem]);
|
||||
SetButtonHints();
|
||||
UEffectFunctionLibrary::PlaySoundEffect2D(GetWorld(), selectionChangedAudioClass);
|
||||
}
|
||||
}
|
||||
void USubMenu::SelectNewItem(UMenuItemBase* item)
|
||||
{
|
||||
int32 idx = 0;
|
||||
if (m_items.Find(item, idx))
|
||||
{
|
||||
SelectNewItemByIndex(idx);
|
||||
}
|
||||
}
|
||||
int32 USubMenu::GetItemIndex(UMenuItemBase* item)
|
||||
{
|
||||
int32 idx = 0;
|
||||
if (m_items.Find(item, idx))
|
||||
return idx;
|
||||
return -1;
|
||||
}
|
||||
UMenuScreenBase* USubMenu::GetScreen() const
|
||||
{
|
||||
return m_screen;
|
||||
}
|
||||
|
||||
void USubMenu::m_SetFocus(bool focus)
|
||||
{
|
||||
m_focus = focus;
|
||||
|
||||
// Get Selected button
|
||||
UMenuItemBase* item = GetItem(GetSelectedItem());
|
||||
if (item)
|
||||
{
|
||||
item->NativeOnSelectionChanged(true, false);
|
||||
}
|
||||
}
|
||||
127
Source/UnrealProject/GUI/Menu/SubMenu.h
Normal file
127
Source/UnrealProject/GUI/Menu/SubMenu.h
Normal file
@@ -0,0 +1,127 @@
|
||||
// Project Lab - NHTV Igad
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GUI/Menu/MenuItemBase.h"
|
||||
#include "SubMenu.generated.h"
|
||||
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FMenuChange);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FSubMenuItemSelected, UMenuItemBase*, item);
|
||||
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API UPanelUserWidget : public UUserWidget
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
};
|
||||
|
||||
UCLASS()
|
||||
class UNREALPROJECT_API USubMenu : public UMenuItemBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
USubMenu(const FObjectInitializer& init);
|
||||
virtual void NativeConstruct() override;
|
||||
virtual void NativeDestruct() override;
|
||||
virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SubMenu")
|
||||
virtual void RescanItems();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SubMenu")
|
||||
void CloseSubMenu();
|
||||
|
||||
virtual void OnEnter(class UMenuScreenBase* screen);
|
||||
virtual void OnLeave();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SubMenu")
|
||||
bool HasFocus() const;
|
||||
|
||||
virtual void OnSuspend(USubMenu* newSubMenu, bool loseFocus);
|
||||
virtual void OnRestore(USubMenu* removedMenu);
|
||||
|
||||
// Callback that gets called whenever the button hits should update when showing this menu
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = "SubMenu")
|
||||
void SetButtonHints();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SubMenu")
|
||||
class UButtonHintBar* GetButtonHintBar() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SubMenu")
|
||||
class UCharacterSettings* GetCharacterSettings() const;
|
||||
UFUNCTION(BlueprintCallable, Category = "SubMenu")
|
||||
class UPrefs* GetPrefs() const;
|
||||
UFUNCTION(BlueprintCallable, Category = "SubMenu")
|
||||
class UDefaultGameInstance* GetGameInstance() const;
|
||||
|
||||
virtual void NativeOnMenuAction(EMenuActionBinding binding) override;
|
||||
virtual void NativeOnSelectionConfirmed(UMenuItemBase* item);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="SubMenu")
|
||||
UMenuItemBase* GetItem(int32 itemIndex) const;
|
||||
UFUNCTION(BlueprintCallable, Category = "SubMenu")
|
||||
int32 GetNumItems() const;
|
||||
UFUNCTION(BlueprintCallable, Category = "SubMenu")
|
||||
int32 GetSelectedItem() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SubMenu")
|
||||
void SelectNewItemByIndex(int32 idx);
|
||||
UFUNCTION(BlueprintCallable, Category = "SubMenu")
|
||||
void SelectNewItem(UMenuItemBase* item);
|
||||
void SelectNewItemByIndex(int32 idx, bool controller);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SubMenu")
|
||||
int32 GetItemIndex(UMenuItemBase* item);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SubMenu")
|
||||
UMenuScreenBase* GetScreen() const;
|
||||
|
||||
// Called when an item is selected
|
||||
UPROPERTY(BlueprintAssignable, Category="SubMenu")
|
||||
FSubMenuItemSelected onItemSelected;
|
||||
// Called when a button is pressed
|
||||
UPROPERTY(BlueprintAssignable, Category="SubMenu")
|
||||
FSubMenuItemSelected onItemSelectionConfirmed;
|
||||
|
||||
// Called when the back button is pressed
|
||||
UPROPERTY(BlueprintAssignable, Category = "SubMenu")
|
||||
FMenuChange onBack;
|
||||
|
||||
UPROPERTY(BlueprintAssignable, Category = "SubMenu")
|
||||
FMenuChange onClosed;
|
||||
UPROPERTY(BlueprintAssignable, Category = "SubMenu")
|
||||
FMenuChange onOpened;
|
||||
|
||||
// Called when another menu is opened on top of this menu
|
||||
UPROPERTY(BlueprintAssignable, Category = "SubMenu")
|
||||
FMenuChange onSuspend;
|
||||
// Called when this menu is displayed again after a menu was closed on top of this
|
||||
UPROPERTY(BlueprintAssignable, Category = "SubMenu")
|
||||
FMenuChange onRestore;
|
||||
|
||||
// The panel widget that contains all the buttons selectable in this menu
|
||||
UPROPERTY(BlueprintReadWrite, Category="SubMenu")
|
||||
UPanelWidget* container;
|
||||
|
||||
protected:
|
||||
void m_ScanContainer(UWidget* widget, int32 depth = 0);
|
||||
// Set the allowance of mouse focus & presses of the buttons in this menu
|
||||
void m_SetFocus(bool focus);
|
||||
|
||||
// The list of selectable items in the menu
|
||||
UPROPERTY()
|
||||
TArray<UMenuItemBase*> m_items;
|
||||
|
||||
private:
|
||||
friend class UMenuItemBase;
|
||||
int32 m_selectedItem;
|
||||
|
||||
// Horizontal or vertical input handling
|
||||
int m_layoutDirection;
|
||||
|
||||
UPROPERTY()
|
||||
class UMenuScreenBase* m_screen;
|
||||
|
||||
// True if this is the topmost screen and if the buttons in this screen are allowed to be pressed.
|
||||
bool m_focus;
|
||||
};
|
||||
Reference in New Issue
Block a user