Add MVP footstep audio placeholders
This commit is contained in:
@@ -834,7 +834,7 @@ Target deliverable: A small group can join a server, spawn into one biome, gathe
|
||||
## 0.1.P MVP Audio And Atmosphere
|
||||
|
||||
- [x] Add ambient biome audio. Extended the placed `AAgrarianWeatherAudioController` so its ambient component explicitly owns a Ground Zero coastal-scrub biome loop slot with separate day/night volume targets, keeping the current MVP silent until placeholder or final audio assets are assigned while giving the map a real ambient audio attachment point.
|
||||
- [ ] Add footstep placeholders.
|
||||
- [x] Add footstep placeholders. Added native player-character footstep hooks with assignable walk, sprint, crouch, and prone sound slots plus movement-state cadence, keeping the MVP silent until placeholder or final surface-aware audio assets are assigned.
|
||||
- [ ] Add gathering sounds.
|
||||
- [ ] Add fire sounds.
|
||||
- [ ] Add unattended and poorly maintained fire risk for campfires and other open-flame sources.
|
||||
|
||||
@@ -316,6 +316,13 @@ because the controller is silent until loops are assigned; placeholder or final
|
||||
audio can be added by setting the exposed sound properties on the placed
|
||||
controller or a Blueprint child.
|
||||
|
||||
Player movement audio starts with native footstep placeholders on
|
||||
`AAgrarianGameCharacter`. The character owns a spatialized
|
||||
`FootstepAudioComponent` plus assignable walk, sprint, crouch, and prone sound
|
||||
slots. Cadence is state-aware and driven by horizontal movement, so the MVP can
|
||||
remain silent until placeholder or final surface-aware cues are assigned while
|
||||
still giving designers a real hook for step audio in packaged builds.
|
||||
|
||||
Campfires expose native extinguish logic through `AAgrarianCampfire::Extinguish`.
|
||||
Extinguishing clears remaining fuel, turns off replicated lit state, and reuses
|
||||
the same visual update path as natural fuel depletion.
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Verify MVP footstep placeholder hooks are present."""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
CHAR_H = ROOT / "Source" / "AgrarianGame" / "AgrarianGameCharacter.h"
|
||||
CHAR_CPP = ROOT / "Source" / "AgrarianGame" / "AgrarianGameCharacter.cpp"
|
||||
TDD = ROOT / "Docs" / "TechnicalDesignDocument.md"
|
||||
ROADMAP = ROOT / "AGRARIAN_DEVELOPMENT_ROADMAP.md"
|
||||
|
||||
REQUIRED = {
|
||||
CHAR_H: [
|
||||
"UAudioComponent* FootstepAudioComponent;",
|
||||
"TObjectPtr<USoundBase> WalkFootstepSound;",
|
||||
"TObjectPtr<USoundBase> SprintFootstepSound;",
|
||||
"TObjectPtr<USoundBase> CrouchFootstepSound;",
|
||||
"TObjectPtr<USoundBase> ProneFootstepSound;",
|
||||
"WalkFootstepIntervalSeconds",
|
||||
"SprintFootstepIntervalSeconds",
|
||||
"CrouchFootstepIntervalSeconds",
|
||||
"ProneFootstepIntervalSeconds",
|
||||
"void UpdateFootstepAudio(float DeltaSeconds);",
|
||||
],
|
||||
CHAR_CPP: [
|
||||
"#include \"Components/AudioComponent.h\"",
|
||||
"FootstepAudioComponent = CreateDefaultSubobject<UAudioComponent>",
|
||||
"FootstepAudioComponent->bAllowSpatialization = true",
|
||||
"UpdateFootstepAudio(DeltaSeconds);",
|
||||
"GetCurrentFootstepSound()",
|
||||
"GetCurrentFootstepIntervalSeconds()",
|
||||
"GetCharacterMovement()->IsFalling()",
|
||||
],
|
||||
TDD: [
|
||||
"native footstep placeholders",
|
||||
"`FootstepAudioComponent`",
|
||||
"walk, sprint, crouch, and prone sound",
|
||||
],
|
||||
ROADMAP: [
|
||||
"[x] Add footstep placeholders.",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
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: footstep placeholder hooks are implemented.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "AgrarianSurvivalComponent.h"
|
||||
#include "Engine/LocalPlayer.h"
|
||||
#include "Camera/CameraComponent.h"
|
||||
#include "Components/AudioComponent.h"
|
||||
#include "Components/CapsuleComponent.h"
|
||||
#include "GameFramework/CharacterMovementComponent.h"
|
||||
#include "GameFramework/SpringArmComponent.h"
|
||||
@@ -64,6 +65,10 @@ AAgrarianGameCharacter::AAgrarianGameCharacter()
|
||||
InventoryComponent = CreateDefaultSubobject<UAgrarianInventoryComponent>(TEXT("InventoryComponent"));
|
||||
CraftingComponent = CreateDefaultSubobject<UAgrarianCraftingComponent>(TEXT("CraftingComponent"));
|
||||
BuildingPlacementComponent = CreateDefaultSubobject<UAgrarianBuildingPlacementComponent>(TEXT("BuildingPlacementComponent"));
|
||||
FootstepAudioComponent = CreateDefaultSubobject<UAudioComponent>(TEXT("FootstepAudioComponent"));
|
||||
FootstepAudioComponent->SetupAttachment(RootComponent);
|
||||
FootstepAudioComponent->bAutoActivate = false;
|
||||
FootstepAudioComponent->bAllowSpatialization = true;
|
||||
|
||||
// Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character)
|
||||
// are set in the derived blueprint asset named ThirdPersonCharacter (to avoid direct content references in C++)
|
||||
@@ -79,6 +84,7 @@ void AAgrarianGameCharacter::Tick(float DeltaSeconds)
|
||||
}
|
||||
|
||||
ApplyMovementSpeed();
|
||||
UpdateFootstepAudio(DeltaSeconds);
|
||||
|
||||
if (!HasAuthority() || !bWantsToSprint)
|
||||
{
|
||||
@@ -474,6 +480,78 @@ float AAgrarianGameCharacter::CalculateStanceMovementMultiplier() const
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
void AAgrarianGameCharacter::UpdateFootstepAudio(float DeltaSeconds)
|
||||
{
|
||||
if (GetNetMode() == NM_DedicatedServer || !FootstepAudioComponent || !SurvivalComponent || !SurvivalComponent->IsAlive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const FVector HorizontalVelocity = FVector(GetVelocity().X, GetVelocity().Y, 0.0f);
|
||||
if (HorizontalVelocity.SizeSquared() < FMath::Square(20.0f) || !GetCharacterMovement() || GetCharacterMovement()->IsFalling())
|
||||
{
|
||||
FootstepIntervalAccumulatorSeconds = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
USoundBase* FootstepSound = GetCurrentFootstepSound();
|
||||
if (!FootstepSound)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FootstepIntervalAccumulatorSeconds += DeltaSeconds;
|
||||
const float Interval = GetCurrentFootstepIntervalSeconds();
|
||||
if (FootstepIntervalAccumulatorSeconds < Interval)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FootstepIntervalAccumulatorSeconds = 0.0f;
|
||||
FootstepAudioComponent->SetSound(FootstepSound);
|
||||
FootstepAudioComponent->Play();
|
||||
}
|
||||
|
||||
USoundBase* AAgrarianGameCharacter::GetCurrentFootstepSound() const
|
||||
{
|
||||
if (bIsProne && ProneFootstepSound)
|
||||
{
|
||||
return ProneFootstepSound;
|
||||
}
|
||||
|
||||
if (bIsCrouched && CrouchFootstepSound)
|
||||
{
|
||||
return CrouchFootstepSound;
|
||||
}
|
||||
|
||||
if (IsSprinting() && SprintFootstepSound)
|
||||
{
|
||||
return SprintFootstepSound;
|
||||
}
|
||||
|
||||
return WalkFootstepSound;
|
||||
}
|
||||
|
||||
float AAgrarianGameCharacter::GetCurrentFootstepIntervalSeconds() const
|
||||
{
|
||||
if (bIsProne)
|
||||
{
|
||||
return FMath::Max(0.1f, ProneFootstepIntervalSeconds);
|
||||
}
|
||||
|
||||
if (bIsCrouched)
|
||||
{
|
||||
return FMath::Max(0.1f, CrouchFootstepIntervalSeconds);
|
||||
}
|
||||
|
||||
if (IsSprinting())
|
||||
{
|
||||
return FMath::Max(0.1f, SprintFootstepIntervalSeconds);
|
||||
}
|
||||
|
||||
return FMath::Max(0.1f, WalkFootstepIntervalSeconds);
|
||||
}
|
||||
|
||||
void AAgrarianGameCharacter::OnRep_SprintState()
|
||||
{
|
||||
ApplyMovementSpeed();
|
||||
|
||||
@@ -14,6 +14,8 @@ class UAgrarianBuildingPlacementComponent;
|
||||
class UAgrarianCraftingComponent;
|
||||
class UAgrarianInventoryComponent;
|
||||
class UAgrarianSurvivalComponent;
|
||||
class UAudioComponent;
|
||||
class USoundBase;
|
||||
struct FInputActionValue;
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogTemplateCharacter, Log, All);
|
||||
@@ -50,6 +52,10 @@ class AAgrarianGameCharacter : public ACharacter
|
||||
/** Server-authoritative primitive building placement component. */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Components", meta = (AllowPrivateAccess = "true"))
|
||||
UAgrarianBuildingPlacementComponent* BuildingPlacementComponent;
|
||||
|
||||
/** Local placeholder footstep playback point; silent until sound assets are assigned. */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Components", meta = (AllowPrivateAccess = "true"))
|
||||
UAudioComponent* FootstepAudioComponent;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -153,6 +159,38 @@ protected:
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, ReplicatedUsing = OnRep_MovementModifierState, Category="Agrarian|Movement|Modifiers", meta = (ClampMin = "0.25", ClampMax = "1.25"))
|
||||
float TerrainMovementMultiplier = 1.0f;
|
||||
|
||||
/** Placeholder walk footstep cue, intended for final surface-aware audio replacement later. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Agrarian|Audio|Footsteps")
|
||||
TObjectPtr<USoundBase> WalkFootstepSound;
|
||||
|
||||
/** Placeholder sprint footstep cue. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Agrarian|Audio|Footsteps")
|
||||
TObjectPtr<USoundBase> SprintFootstepSound;
|
||||
|
||||
/** Placeholder crouch footstep cue. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Agrarian|Audio|Footsteps")
|
||||
TObjectPtr<USoundBase> CrouchFootstepSound;
|
||||
|
||||
/** Placeholder prone shuffle cue. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Agrarian|Audio|Footsteps")
|
||||
TObjectPtr<USoundBase> ProneFootstepSound;
|
||||
|
||||
/** Normal walking step cadence before sprint/crouch/prone modifiers. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Agrarian|Audio|Footsteps", meta = (ClampMin = "0.1"))
|
||||
float WalkFootstepIntervalSeconds = 0.58f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Agrarian|Audio|Footsteps", meta = (ClampMin = "0.1"))
|
||||
float SprintFootstepIntervalSeconds = 0.34f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Agrarian|Audio|Footsteps", meta = (ClampMin = "0.1"))
|
||||
float CrouchFootstepIntervalSeconds = 0.86f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Agrarian|Audio|Footsteps", meta = (ClampMin = "0.1"))
|
||||
float ProneFootstepIntervalSeconds = 1.15f;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Agrarian|Audio|Footsteps", meta = (AllowPrivateAccess = "true"))
|
||||
float FootstepIntervalAccumulatorSeconds = 0.0f;
|
||||
|
||||
/** Third-person spring arm distance used when returning from first person. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Agrarian|Camera", meta = (ClampMin = "0"))
|
||||
float ThirdPersonCameraDistance = 400.0f;
|
||||
@@ -231,6 +269,9 @@ protected:
|
||||
float CalculateSurvivalMovementMultiplier() const;
|
||||
float CalculateCarryWeightMovementMultiplier() const;
|
||||
float CalculateStanceMovementMultiplier() const;
|
||||
void UpdateFootstepAudio(float DeltaSeconds);
|
||||
USoundBase* GetCurrentFootstepSound() const;
|
||||
float GetCurrentFootstepIntervalSeconds() const;
|
||||
|
||||
UFUNCTION()
|
||||
void OnRep_SprintState();
|
||||
|
||||
Reference in New Issue
Block a user