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 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.
|
||||
- [ ] 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 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
|
||||
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
|
||||
`AAgrarianGameCharacter`. The character owns a spatialized
|
||||
`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 "GameFramework/PlayerController.h"
|
||||
#include "InputCoreTypes.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
#include "Styling/CoreStyle.h"
|
||||
#include "TimerManager.h"
|
||||
|
||||
@@ -48,18 +49,21 @@ FReply UAgrarianMvpFrontendWidget::NativeOnKeyDown(const FGeometry& InGeometry,
|
||||
const FKey Key = InKeyEvent.GetKey();
|
||||
if (Key == EKeys::Left || Key == EKeys::A)
|
||||
{
|
||||
PlayUiSound(UiSelectionSound);
|
||||
SetSelectedCharacterArchetype(EAgrarianMvpCharacterArchetype::YoungAdultMale);
|
||||
return FReply::Handled();
|
||||
}
|
||||
|
||||
if (Key == EKeys::Right || Key == EKeys::D)
|
||||
{
|
||||
PlayUiSound(UiSelectionSound);
|
||||
SetSelectedCharacterArchetype(EAgrarianMvpCharacterArchetype::YoungAdultFemale);
|
||||
return FReply::Handled();
|
||||
}
|
||||
|
||||
if (Key == EKeys::Enter || Key == EKeys::SpaceBar)
|
||||
{
|
||||
PlayUiSound(UiConfirmSound);
|
||||
ConfirmActiveScreen();
|
||||
return FReply::Handled();
|
||||
}
|
||||
@@ -69,12 +73,14 @@ FReply UAgrarianMvpFrontendWidget::NativeOnKeyDown(const FGeometry& InGeometry,
|
||||
const FKey Key = InKeyEvent.GetKey();
|
||||
if (Key == EKeys::Enter || Key == EKeys::SpaceBar)
|
||||
{
|
||||
PlayUiSound(UiConfirmSound);
|
||||
ConfirmActiveScreen();
|
||||
return FReply::Handled();
|
||||
}
|
||||
|
||||
if (Key == EKeys::BackSpace || Key == EKeys::Escape)
|
||||
{
|
||||
PlayUiSound(UiBackSound);
|
||||
BackFromActiveScreen();
|
||||
return FReply::Handled();
|
||||
}
|
||||
@@ -84,6 +90,7 @@ FReply UAgrarianMvpFrontendWidget::NativeOnKeyDown(const FGeometry& InGeometry,
|
||||
const FKey Key = InKeyEvent.GetKey();
|
||||
if (Key == EKeys::Enter || Key == EKeys::SpaceBar)
|
||||
{
|
||||
PlayUiSound(UiConfirmSound);
|
||||
ConfirmActiveScreen();
|
||||
return FReply::Handled();
|
||||
}
|
||||
@@ -93,12 +100,14 @@ FReply UAgrarianMvpFrontendWidget::NativeOnKeyDown(const FGeometry& InGeometry,
|
||||
const FKey Key = InKeyEvent.GetKey();
|
||||
if (Key == EKeys::Enter || Key == EKeys::SpaceBar || Key == EKeys::Escape)
|
||||
{
|
||||
PlayUiSound(UiConfirmSound);
|
||||
ConfirmActiveScreen();
|
||||
return FReply::Handled();
|
||||
}
|
||||
|
||||
if (Key == EKeys::Q)
|
||||
{
|
||||
PlayUiSound(UiSaveQuitSound);
|
||||
SaveAndQuit();
|
||||
return FReply::Handled();
|
||||
}
|
||||
@@ -466,6 +475,14 @@ UButton* UAgrarianMvpFrontendWidget::AddButton(UVerticalBox* Parent, const FText
|
||||
return Button;
|
||||
}
|
||||
|
||||
void UAgrarianMvpFrontendWidget::PlayUiSound(USoundBase* Sound) const
|
||||
{
|
||||
if (Sound)
|
||||
{
|
||||
UGameplayStatics::PlaySound2D(this, Sound);
|
||||
}
|
||||
}
|
||||
|
||||
void UAgrarianMvpFrontendWidget::FocusPrimaryButton()
|
||||
{
|
||||
if (PrimaryFocusButton)
|
||||
@@ -480,26 +497,31 @@ void UAgrarianMvpFrontendWidget::FocusPrimaryButton()
|
||||
|
||||
void UAgrarianMvpFrontendWidget::HandlePrimaryActionClicked()
|
||||
{
|
||||
PlayUiSound(UiConfirmSound);
|
||||
ConfirmActiveScreen();
|
||||
}
|
||||
|
||||
void UAgrarianMvpFrontendWidget::HandleBackClicked()
|
||||
{
|
||||
PlayUiSound(UiBackSound);
|
||||
BackFromActiveScreen();
|
||||
}
|
||||
|
||||
void UAgrarianMvpFrontendWidget::HandleSaveAndQuitClicked()
|
||||
{
|
||||
PlayUiSound(UiSaveQuitSound);
|
||||
SaveAndQuit();
|
||||
}
|
||||
|
||||
void UAgrarianMvpFrontendWidget::HandleMaleCharacterClicked()
|
||||
{
|
||||
PlayUiSound(UiSelectionSound);
|
||||
SetSelectedCharacterArchetype(EAgrarianMvpCharacterArchetype::YoungAdultMale);
|
||||
}
|
||||
|
||||
void UAgrarianMvpFrontendWidget::HandleFemaleCharacterClicked()
|
||||
{
|
||||
PlayUiSound(UiSelectionSound);
|
||||
SetSelectedCharacterArchetype(EAgrarianMvpCharacterArchetype::YoungAdultFemale);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "AgrarianMvpFrontendWidget.generated.h"
|
||||
|
||||
class UButton;
|
||||
class USoundBase;
|
||||
class UTextBlock;
|
||||
class UVerticalBox;
|
||||
|
||||
@@ -57,6 +58,18 @@ public:
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|MVP UI")
|
||||
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")
|
||||
void SetActiveScreen(EAgrarianMvpFrontendScreen NewScreen);
|
||||
|
||||
@@ -90,6 +103,7 @@ private:
|
||||
void RebuildFrontendTree();
|
||||
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);
|
||||
void PlayUiSound(USoundBase* Sound) const;
|
||||
|
||||
UFUNCTION()
|
||||
void FocusPrimaryButton();
|
||||
|
||||
Reference in New Issue
Block a user