added main and pause menus

This commit is contained in:
2026-06-05 20:00:33 +03:00
parent 0792f7cdfd
commit 61d5a57d8d
53 changed files with 1402 additions and 49 deletions
@@ -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;
};
+33
View File
@@ -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);
}
}
+27
View File
@@ -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;