added main and pause menus
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Engine/DataAsset.h"
|
||||
#include "AudioSettingsConfig.generated.h"
|
||||
|
||||
class USoundMix;
|
||||
class USoundClass;
|
||||
|
||||
// Data-driven audio routing for the settings sliders (§17.4). The UAudioSettingsSubsystem
|
||||
// pushes per-class volume overrides through SettingsMix when the user changes a slider.
|
||||
// Author one SoundMix + three SoundClasses and assign on UNakedDesireGameInstance::AudioConfig.
|
||||
UCLASS()
|
||||
class NAKEDDESIRE_API UAudioSettingsConfig : public UPrimaryDataAsset
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UPROPERTY(EditDefaultsOnly, Category = "Audio")
|
||||
TObjectPtr<USoundMix> SettingsMix;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, Category = "Audio")
|
||||
TObjectPtr<USoundClass> MasterClass;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, Category = "Audio")
|
||||
TObjectPtr<USoundClass> MusicClass;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, Category = "Audio")
|
||||
TObjectPtr<USoundClass> SfxClass;
|
||||
};
|
||||
@@ -0,0 +1,76 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
|
||||
#include "AudioSettingsSubsystem.h"
|
||||
|
||||
#include "AudioSettingsConfig.h"
|
||||
#include "NakedDesireGameInstance.h"
|
||||
#include "NakedDesireUserSettings.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
#include "Sound/SoundClass.h"
|
||||
#include "Sound/SoundMix.h"
|
||||
#include "UObject/UObjectGlobals.h"
|
||||
|
||||
void UAudioSettingsSubsystem::Initialize(FSubsystemCollectionBase& Collection)
|
||||
{
|
||||
Super::Initialize(Collection);
|
||||
|
||||
if (UNakedDesireUserSettings* Settings = UNakedDesireUserSettings::GetNakedDesireUserSettings())
|
||||
Settings->OnSettingsChanged.AddUniqueDynamic(this, &UAudioSettingsSubsystem::HandleSettingsChanged);
|
||||
|
||||
// SoundMix overrides are world-scoped, so re-push them every time a level finishes loading.
|
||||
MapLoadHandle = FCoreUObjectDelegates::PostLoadMapWithWorld.AddUObject(this, &UAudioSettingsSubsystem::HandleMapLoaded);
|
||||
}
|
||||
|
||||
void UAudioSettingsSubsystem::Deinitialize()
|
||||
{
|
||||
if (UNakedDesireUserSettings* Settings = UNakedDesireUserSettings::GetNakedDesireUserSettings())
|
||||
Settings->OnSettingsChanged.RemoveDynamic(this, &UAudioSettingsSubsystem::HandleSettingsChanged);
|
||||
|
||||
FCoreUObjectDelegates::PostLoadMapWithWorld.Remove(MapLoadHandle);
|
||||
|
||||
Super::Deinitialize();
|
||||
}
|
||||
|
||||
void UAudioSettingsSubsystem::HandleSettingsChanged(UNakedDesireUserSettings* Settings)
|
||||
{
|
||||
ApplyVolumes();
|
||||
}
|
||||
|
||||
void UAudioSettingsSubsystem::HandleMapLoaded(UWorld* LoadedWorld)
|
||||
{
|
||||
ApplyVolumes();
|
||||
}
|
||||
|
||||
void UAudioSettingsSubsystem::ApplyVolumes()
|
||||
{
|
||||
const UNakedDesireGameInstance* GameInstance = Cast<UNakedDesireGameInstance>(GetGameInstance());
|
||||
if (!GameInstance || !GameInstance->AudioConfig)
|
||||
return;
|
||||
|
||||
const UAudioSettingsConfig* Config = GameInstance->AudioConfig;
|
||||
if (!Config->SettingsMix)
|
||||
return;
|
||||
|
||||
UWorld* World = GetWorld();
|
||||
if (!World)
|
||||
return;
|
||||
|
||||
const UNakedDesireUserSettings* Settings = UNakedDesireUserSettings::GetNakedDesireUserSettings();
|
||||
if (!Settings)
|
||||
return;
|
||||
|
||||
auto ApplyClass = [&](USoundClass* SoundClass, float Volume)
|
||||
{
|
||||
if (!SoundClass)
|
||||
return;
|
||||
// Pitch 1.0, no fade — instantaneous so the slider feels responsive.
|
||||
UGameplayStatics::SetSoundMixClassOverride(World, Config->SettingsMix, SoundClass, Volume, 1.0f, 0.0f, true);
|
||||
};
|
||||
|
||||
ApplyClass(Config->MasterClass, Settings->GetGlobalVolume());
|
||||
ApplyClass(Config->MusicClass, Settings->GetMusicVolume());
|
||||
ApplyClass(Config->SfxClass, Settings->GetSfxVolume());
|
||||
|
||||
UGameplayStatics::PushSoundMixModifier(World, Config->SettingsMix);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Subsystems/GameInstanceSubsystem.h"
|
||||
#include "AudioSettingsSubsystem.generated.h"
|
||||
|
||||
class UNakedDesireUserSettings;
|
||||
|
||||
// Applies the master / music / SFX volume settings to SoundClasses via the configured
|
||||
// SoundMix (UNakedDesireGameInstance::AudioConfig). Re-applies whenever settings change
|
||||
// and on each world start so volumes survive level travel.
|
||||
UCLASS()
|
||||
class NAKEDDESIRE_API UAudioSettingsSubsystem : public UGameInstanceSubsystem
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
|
||||
virtual void Deinitialize() override;
|
||||
|
||||
// Pushes the current settings volumes onto the configured SoundMix. Safe to call any time.
|
||||
void ApplyVolumes();
|
||||
|
||||
private:
|
||||
UFUNCTION()
|
||||
void HandleSettingsChanged(UNakedDesireUserSettings* Settings);
|
||||
|
||||
void HandleMapLoaded(UWorld* LoadedWorld);
|
||||
|
||||
FDelegateHandle MapLoadHandle;
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
|
||||
#include "MainMenuHUD.h"
|
||||
|
||||
#include "Blueprint/UserWidget.h"
|
||||
#include "GameFramework/PlayerController.h"
|
||||
#include "NakedDesire/UI/Menu/MainMenuWidget.h"
|
||||
|
||||
void AMainMenuHUD::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
if (!MainMenuWidgetClass)
|
||||
return;
|
||||
|
||||
MainMenuWidget = CreateWidget<UMainMenuWidget>(GetWorld(), MainMenuWidgetClass);
|
||||
if (!MainMenuWidget)
|
||||
return;
|
||||
|
||||
MainMenuWidget->AddToViewport();
|
||||
MainMenuWidget->ActivateWidget();
|
||||
|
||||
if (APlayerController* PC = GetOwningPlayerController())
|
||||
{
|
||||
PC->SetShowMouseCursor(true);
|
||||
|
||||
FInputModeUIOnly InputMode;
|
||||
InputMode.SetWidgetToFocus(MainMenuWidget->TakeWidget());
|
||||
InputMode.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock);
|
||||
PC->SetInputMode(InputMode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/HUD.h"
|
||||
#include "MainMenuHUD.generated.h"
|
||||
|
||||
class UMainMenuWidget;
|
||||
|
||||
// HUD for the main-menu map. Creates the front-end widget and routes input to it.
|
||||
// Assign this (or a BP child) as the HUD class on the MainMenu map's GameMode.
|
||||
UCLASS()
|
||||
class NAKEDDESIRE_API AMainMenuHUD : public AHUD
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
protected:
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, Category = "UI")
|
||||
TSubclassOf<UMainMenuWidget> MainMenuWidgetClass;
|
||||
|
||||
private:
|
||||
UPROPERTY()
|
||||
TObjectPtr<UMainMenuWidget> MainMenuWidget;
|
||||
};
|
||||
@@ -9,6 +9,7 @@ class UStartingSaveData;
|
||||
class UCommissionBoardConfig;
|
||||
class UNPCDirectorConfig;
|
||||
class ULossPresentationConfig;
|
||||
class UAudioSettingsConfig;
|
||||
|
||||
UCLASS()
|
||||
class NAKEDDESIRE_API UNakedDesireGameInstance : public UGameInstance
|
||||
@@ -30,4 +31,8 @@ public:
|
||||
// Cutscene-per-loss-cause map the USessionLossResolver plays before teleporting home (§4.4).
|
||||
UPROPERTY(EditDefaultsOnly, Category = "Session")
|
||||
TObjectPtr<ULossPresentationConfig> LossPresentation;
|
||||
|
||||
// SoundMix / SoundClass routing the UAudioSettingsSubsystem drives from the audio settings sliders.
|
||||
UPROPERTY(EditDefaultsOnly, Category = "Audio")
|
||||
TObjectPtr<UAudioSettingsConfig> AudioConfig;
|
||||
};
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
void UNakedDesireUserSettings::SetGlobalVolume(float Value)
|
||||
{
|
||||
GlobalVolume = Value;
|
||||
GlobalVolume = FMath::Clamp(Value, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
float UNakedDesireUserSettings::GetGlobalVolume() const
|
||||
@@ -13,6 +13,26 @@ float UNakedDesireUserSettings::GetGlobalVolume() const
|
||||
return GlobalVolume;
|
||||
}
|
||||
|
||||
void UNakedDesireUserSettings::SetMusicVolume(float Value)
|
||||
{
|
||||
MusicVolume = FMath::Clamp(Value, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
float UNakedDesireUserSettings::GetMusicVolume() const
|
||||
{
|
||||
return MusicVolume;
|
||||
}
|
||||
|
||||
void UNakedDesireUserSettings::SetSfxVolume(float Value)
|
||||
{
|
||||
SfxVolume = FMath::Clamp(Value, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
float UNakedDesireUserSettings::GetSfxVolume() const
|
||||
{
|
||||
return SfxVolume;
|
||||
}
|
||||
|
||||
void UNakedDesireUserSettings::SetIsCensorshipEnabled(bool Value)
|
||||
{
|
||||
IsCensorshipEnabled = Value;
|
||||
|
||||
@@ -23,6 +23,18 @@ public:
|
||||
UFUNCTION(BlueprintPure)
|
||||
float GetGlobalVolume() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void SetMusicVolume(float Value);
|
||||
|
||||
UFUNCTION(BlueprintPure)
|
||||
float GetMusicVolume() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void SetSfxVolume(float Value);
|
||||
|
||||
UFUNCTION(BlueprintPure)
|
||||
float GetSfxVolume() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void SetIsCensorshipEnabled(bool Value);
|
||||
|
||||
@@ -46,6 +58,12 @@ protected:
|
||||
UPROPERTY(Config)
|
||||
float GlobalVolume = 0.5f;
|
||||
|
||||
UPROPERTY(Config)
|
||||
float MusicVolume = 0.5f;
|
||||
|
||||
UPROPERTY(Config)
|
||||
float SfxVolume = 0.5f;
|
||||
|
||||
UPROPERTY(Config)
|
||||
bool IsCensorshipEnabled = false;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user