Add MVP frontend audio hooks
This commit is contained in:
@@ -847,7 +847,7 @@ Target deliverable: A small group can join a server, spawn into one biome, gathe
|
|||||||
- [x] Add QA coverage for safe campfires, unsafe campfires, vegetation spread, shelter ignition, suppression, and save/load recovery. Added a fire-risk QA coverage document and verifier requiring safe/unsafe campfire, vegetation spread, shelter ignition, suppression, and save/load recovery scenarios plus the supporting fire-risk verification scripts.
|
- [x] Add QA coverage for safe campfires, unsafe campfires, vegetation spread, shelter ignition, suppression, and save/load recovery. Added a fire-risk QA coverage document and verifier requiring safe/unsafe campfire, vegetation spread, shelter ignition, suppression, and save/load recovery scenarios plus the supporting fire-risk verification scripts.
|
||||||
- [x] Add weather sounds. Formalized the existing placed weather audio controller as the MVP weather-sound path, documenting rain, wind, storm, clear ambient, and biome loop slots plus verification that weather playback follows replicated weather state, provider wind speed, and day/night state while remaining silent until assets are assigned.
|
- [x] Add weather sounds. Formalized the existing placed weather audio controller as the MVP weather-sound path, documenting rain, wind, storm, clear ambient, and biome loop slots plus verification that weather playback follows replicated weather state, provider wind speed, and day/night state while remaining silent until assets are assigned.
|
||||||
- [x] Add wildlife sounds. Added spatialized wildlife audio hooks with assignable idle, flee/chase, death, and harvest sound slots plus server-triggered multicast playback from authoritative wildlife state changes and harvest events.
|
- [x] Add wildlife sounds. Added spatialized wildlife audio hooks with assignable idle, flee/chase, death, and harvest sound slots plus server-triggered multicast playback from authoritative wildlife state changes and harvest events.
|
||||||
- [ ] Add UI sounds.
|
- [x] Add UI sounds. Added optional 2D confirm, back, selection, and save/quit sound hooks to the MVP frontend widget, with keyboard and mouse actions sharing the same feedback path while remaining silent until UI audio assets are assigned.
|
||||||
- [ ] Add mix settings.
|
- [ ] Add mix settings.
|
||||||
- [ ] Add volume sliders.
|
- [ ] Add volume sliders.
|
||||||
|
|
||||||
|
|||||||
@@ -323,6 +323,11 @@ Wildlife expose idle, flee/chase, death, and harvest sound slots. The server
|
|||||||
multicasts state-change and harvest cues so clients hear wildlife reactions from
|
multicasts state-change and harvest cues so clients hear wildlife reactions from
|
||||||
the authoritative AI state while the dedicated server remains silent.
|
the authoritative AI state while the dedicated server remains silent.
|
||||||
|
|
||||||
|
UI sounds are optional 2D hooks on `UAgrarianMvpFrontendWidget`. The frontend
|
||||||
|
exposes confirm, back, selection, and save/quit sound slots. Keyboard and mouse
|
||||||
|
actions play the same cues so menu feedback stays consistent across input
|
||||||
|
methods while the widget remains silent until UI assets are assigned.
|
||||||
|
|
||||||
Player movement audio starts with native footstep placeholders on
|
Player movement audio starts with native footstep placeholders on
|
||||||
`AAgrarianGameCharacter`. The character owns a spatialized
|
`AAgrarianGameCharacter`. The character owns a spatialized
|
||||||
`FootstepAudioComponent` plus assignable walk, sprint, crouch, and prone sound
|
`FootstepAudioComponent` plus assignable walk, sprint, crouch, and prone sound
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Verify MVP frontend UI sound hooks are present."""
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
UI_H = ROOT / "Source" / "AgrarianGame" / "AgrarianMvpFrontendWidget.h"
|
||||||
|
UI_CPP = ROOT / "Source" / "AgrarianGame" / "AgrarianMvpFrontendWidget.cpp"
|
||||||
|
TDD = ROOT / "Docs" / "TechnicalDesignDocument.md"
|
||||||
|
ROADMAP = ROOT / "AGRARIAN_DEVELOPMENT_ROADMAP.md"
|
||||||
|
|
||||||
|
REQUIRED = {
|
||||||
|
UI_H: [
|
||||||
|
"TObjectPtr<USoundBase> UiConfirmSound;",
|
||||||
|
"TObjectPtr<USoundBase> UiBackSound;",
|
||||||
|
"TObjectPtr<USoundBase> UiSelectionSound;",
|
||||||
|
"TObjectPtr<USoundBase> UiSaveQuitSound;",
|
||||||
|
"void PlayUiSound(USoundBase* Sound) const;",
|
||||||
|
],
|
||||||
|
UI_CPP: [
|
||||||
|
"#include \"Kismet/GameplayStatics.h\"",
|
||||||
|
"UGameplayStatics::PlaySound2D(this, Sound);",
|
||||||
|
"PlayUiSound(UiConfirmSound);",
|
||||||
|
"PlayUiSound(UiBackSound);",
|
||||||
|
"PlayUiSound(UiSelectionSound);",
|
||||||
|
"PlayUiSound(UiSaveQuitSound);",
|
||||||
|
"HandlePrimaryActionClicked",
|
||||||
|
"HandleBackClicked",
|
||||||
|
"HandleMaleCharacterClicked",
|
||||||
|
"NativeOnKeyDown",
|
||||||
|
],
|
||||||
|
TDD: [
|
||||||
|
"UI sounds are optional 2D hooks",
|
||||||
|
"confirm, back, selection, and save/quit sound",
|
||||||
|
"Keyboard and mouse",
|
||||||
|
],
|
||||||
|
ROADMAP: [
|
||||||
|
"[x] Add UI sounds.",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
missing = []
|
||||||
|
for path, snippets in REQUIRED.items():
|
||||||
|
text = path.read_text(encoding="utf-8")
|
||||||
|
for snippet in snippets:
|
||||||
|
if snippet not in text:
|
||||||
|
missing.append(f"{path.relative_to(ROOT)} missing {snippet!r}")
|
||||||
|
if missing:
|
||||||
|
raise SystemExit("FAILED: " + "; ".join(missing))
|
||||||
|
print("OK: UI sound hooks are shared across keyboard and mouse actions.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
#include "Components/VerticalBoxSlot.h"
|
#include "Components/VerticalBoxSlot.h"
|
||||||
#include "GameFramework/PlayerController.h"
|
#include "GameFramework/PlayerController.h"
|
||||||
#include "InputCoreTypes.h"
|
#include "InputCoreTypes.h"
|
||||||
|
#include "Kismet/GameplayStatics.h"
|
||||||
#include "Styling/CoreStyle.h"
|
#include "Styling/CoreStyle.h"
|
||||||
#include "TimerManager.h"
|
#include "TimerManager.h"
|
||||||
|
|
||||||
@@ -48,18 +49,21 @@ FReply UAgrarianMvpFrontendWidget::NativeOnKeyDown(const FGeometry& InGeometry,
|
|||||||
const FKey Key = InKeyEvent.GetKey();
|
const FKey Key = InKeyEvent.GetKey();
|
||||||
if (Key == EKeys::Left || Key == EKeys::A)
|
if (Key == EKeys::Left || Key == EKeys::A)
|
||||||
{
|
{
|
||||||
|
PlayUiSound(UiSelectionSound);
|
||||||
SetSelectedCharacterArchetype(EAgrarianMvpCharacterArchetype::YoungAdultMale);
|
SetSelectedCharacterArchetype(EAgrarianMvpCharacterArchetype::YoungAdultMale);
|
||||||
return FReply::Handled();
|
return FReply::Handled();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Key == EKeys::Right || Key == EKeys::D)
|
if (Key == EKeys::Right || Key == EKeys::D)
|
||||||
{
|
{
|
||||||
|
PlayUiSound(UiSelectionSound);
|
||||||
SetSelectedCharacterArchetype(EAgrarianMvpCharacterArchetype::YoungAdultFemale);
|
SetSelectedCharacterArchetype(EAgrarianMvpCharacterArchetype::YoungAdultFemale);
|
||||||
return FReply::Handled();
|
return FReply::Handled();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Key == EKeys::Enter || Key == EKeys::SpaceBar)
|
if (Key == EKeys::Enter || Key == EKeys::SpaceBar)
|
||||||
{
|
{
|
||||||
|
PlayUiSound(UiConfirmSound);
|
||||||
ConfirmActiveScreen();
|
ConfirmActiveScreen();
|
||||||
return FReply::Handled();
|
return FReply::Handled();
|
||||||
}
|
}
|
||||||
@@ -69,12 +73,14 @@ FReply UAgrarianMvpFrontendWidget::NativeOnKeyDown(const FGeometry& InGeometry,
|
|||||||
const FKey Key = InKeyEvent.GetKey();
|
const FKey Key = InKeyEvent.GetKey();
|
||||||
if (Key == EKeys::Enter || Key == EKeys::SpaceBar)
|
if (Key == EKeys::Enter || Key == EKeys::SpaceBar)
|
||||||
{
|
{
|
||||||
|
PlayUiSound(UiConfirmSound);
|
||||||
ConfirmActiveScreen();
|
ConfirmActiveScreen();
|
||||||
return FReply::Handled();
|
return FReply::Handled();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Key == EKeys::BackSpace || Key == EKeys::Escape)
|
if (Key == EKeys::BackSpace || Key == EKeys::Escape)
|
||||||
{
|
{
|
||||||
|
PlayUiSound(UiBackSound);
|
||||||
BackFromActiveScreen();
|
BackFromActiveScreen();
|
||||||
return FReply::Handled();
|
return FReply::Handled();
|
||||||
}
|
}
|
||||||
@@ -84,6 +90,7 @@ FReply UAgrarianMvpFrontendWidget::NativeOnKeyDown(const FGeometry& InGeometry,
|
|||||||
const FKey Key = InKeyEvent.GetKey();
|
const FKey Key = InKeyEvent.GetKey();
|
||||||
if (Key == EKeys::Enter || Key == EKeys::SpaceBar)
|
if (Key == EKeys::Enter || Key == EKeys::SpaceBar)
|
||||||
{
|
{
|
||||||
|
PlayUiSound(UiConfirmSound);
|
||||||
ConfirmActiveScreen();
|
ConfirmActiveScreen();
|
||||||
return FReply::Handled();
|
return FReply::Handled();
|
||||||
}
|
}
|
||||||
@@ -93,12 +100,14 @@ FReply UAgrarianMvpFrontendWidget::NativeOnKeyDown(const FGeometry& InGeometry,
|
|||||||
const FKey Key = InKeyEvent.GetKey();
|
const FKey Key = InKeyEvent.GetKey();
|
||||||
if (Key == EKeys::Enter || Key == EKeys::SpaceBar || Key == EKeys::Escape)
|
if (Key == EKeys::Enter || Key == EKeys::SpaceBar || Key == EKeys::Escape)
|
||||||
{
|
{
|
||||||
|
PlayUiSound(UiConfirmSound);
|
||||||
ConfirmActiveScreen();
|
ConfirmActiveScreen();
|
||||||
return FReply::Handled();
|
return FReply::Handled();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Key == EKeys::Q)
|
if (Key == EKeys::Q)
|
||||||
{
|
{
|
||||||
|
PlayUiSound(UiSaveQuitSound);
|
||||||
SaveAndQuit();
|
SaveAndQuit();
|
||||||
return FReply::Handled();
|
return FReply::Handled();
|
||||||
}
|
}
|
||||||
@@ -466,6 +475,14 @@ UButton* UAgrarianMvpFrontendWidget::AddButton(UVerticalBox* Parent, const FText
|
|||||||
return Button;
|
return Button;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UAgrarianMvpFrontendWidget::PlayUiSound(USoundBase* Sound) const
|
||||||
|
{
|
||||||
|
if (Sound)
|
||||||
|
{
|
||||||
|
UGameplayStatics::PlaySound2D(this, Sound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void UAgrarianMvpFrontendWidget::FocusPrimaryButton()
|
void UAgrarianMvpFrontendWidget::FocusPrimaryButton()
|
||||||
{
|
{
|
||||||
if (PrimaryFocusButton)
|
if (PrimaryFocusButton)
|
||||||
@@ -480,26 +497,31 @@ void UAgrarianMvpFrontendWidget::FocusPrimaryButton()
|
|||||||
|
|
||||||
void UAgrarianMvpFrontendWidget::HandlePrimaryActionClicked()
|
void UAgrarianMvpFrontendWidget::HandlePrimaryActionClicked()
|
||||||
{
|
{
|
||||||
|
PlayUiSound(UiConfirmSound);
|
||||||
ConfirmActiveScreen();
|
ConfirmActiveScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UAgrarianMvpFrontendWidget::HandleBackClicked()
|
void UAgrarianMvpFrontendWidget::HandleBackClicked()
|
||||||
{
|
{
|
||||||
|
PlayUiSound(UiBackSound);
|
||||||
BackFromActiveScreen();
|
BackFromActiveScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UAgrarianMvpFrontendWidget::HandleSaveAndQuitClicked()
|
void UAgrarianMvpFrontendWidget::HandleSaveAndQuitClicked()
|
||||||
{
|
{
|
||||||
|
PlayUiSound(UiSaveQuitSound);
|
||||||
SaveAndQuit();
|
SaveAndQuit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UAgrarianMvpFrontendWidget::HandleMaleCharacterClicked()
|
void UAgrarianMvpFrontendWidget::HandleMaleCharacterClicked()
|
||||||
{
|
{
|
||||||
|
PlayUiSound(UiSelectionSound);
|
||||||
SetSelectedCharacterArchetype(EAgrarianMvpCharacterArchetype::YoungAdultMale);
|
SetSelectedCharacterArchetype(EAgrarianMvpCharacterArchetype::YoungAdultMale);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UAgrarianMvpFrontendWidget::HandleFemaleCharacterClicked()
|
void UAgrarianMvpFrontendWidget::HandleFemaleCharacterClicked()
|
||||||
{
|
{
|
||||||
|
PlayUiSound(UiSelectionSound);
|
||||||
SetSelectedCharacterArchetype(EAgrarianMvpCharacterArchetype::YoungAdultFemale);
|
SetSelectedCharacterArchetype(EAgrarianMvpCharacterArchetype::YoungAdultFemale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "AgrarianMvpFrontendWidget.generated.h"
|
#include "AgrarianMvpFrontendWidget.generated.h"
|
||||||
|
|
||||||
class UButton;
|
class UButton;
|
||||||
|
class USoundBase;
|
||||||
class UTextBlock;
|
class UTextBlock;
|
||||||
class UVerticalBox;
|
class UVerticalBox;
|
||||||
|
|
||||||
@@ -57,6 +58,18 @@ public:
|
|||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|MVP UI")
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|MVP UI")
|
||||||
bool bUseHighContrast = false;
|
bool bUseHighContrast = false;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|MVP UI|Audio")
|
||||||
|
TObjectPtr<USoundBase> UiConfirmSound;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|MVP UI|Audio")
|
||||||
|
TObjectPtr<USoundBase> UiBackSound;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|MVP UI|Audio")
|
||||||
|
TObjectPtr<USoundBase> UiSelectionSound;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|MVP UI|Audio")
|
||||||
|
TObjectPtr<USoundBase> UiSaveQuitSound;
|
||||||
|
|
||||||
UFUNCTION(BlueprintCallable, Category = "Agrarian|MVP UI")
|
UFUNCTION(BlueprintCallable, Category = "Agrarian|MVP UI")
|
||||||
void SetActiveScreen(EAgrarianMvpFrontendScreen NewScreen);
|
void SetActiveScreen(EAgrarianMvpFrontendScreen NewScreen);
|
||||||
|
|
||||||
@@ -90,6 +103,7 @@ private:
|
|||||||
void RebuildFrontendTree();
|
void RebuildFrontendTree();
|
||||||
UTextBlock* AddText(UVerticalBox* Parent, const FText& Text, int32 FontSize, bool bBold, const FLinearColor& Color, float BottomPadding);
|
UTextBlock* AddText(UVerticalBox* Parent, const FText& Text, int32 FontSize, bool bBold, const FLinearColor& Color, float BottomPadding);
|
||||||
UButton* AddButton(UVerticalBox* Parent, const FText& Text, const FLinearColor& NormalColor, const FLinearColor& HoveredColor, float BottomPadding);
|
UButton* AddButton(UVerticalBox* Parent, const FText& Text, const FLinearColor& NormalColor, const FLinearColor& HoveredColor, float BottomPadding);
|
||||||
|
void PlayUiSound(USoundBase* Sound) const;
|
||||||
|
|
||||||
UFUNCTION()
|
UFUNCTION()
|
||||||
void FocusPrimaryButton();
|
void FocusPrimaryButton();
|
||||||
|
|||||||
Reference in New Issue
Block a user