Download

Static Audio Library to contain generic sounds?

Hi,

This is my first experience getting my hands dirty with coding for video games. I am in the process of creating an Item system, and so far, I am populating my Structures class (which would be static build/place-able items in the game world).

I am trying to incorporate audio to these items - specifically, generic sounds such as impact and destruction. The class does contain an audio component, but I do not want the class to contain lists or arrays of sound clips to play - it seems like squandered resources when all items use the same set of sounds anyways.

I thought of creating a static class or a bunch of static methods to handle the process - this means, there exists a general static class (i.e AudioManager) that contain all types of impact sounds. When an item needs to play a clip, it calls a static method to fetch an audio clip and proceeds to play it via the Audio Component. I am unaware if this is the go-to way to handle this problem, but nonetheless, I face some uncertainty in the implementation.

  • Where does the Audio Manager class get its audio assets from? Ideally, I will want to create an ItemDataTable row struct that houses a bunch of array for each sound category, but how do I access DataTables when I am in C++? The DataTable object is created and managed inside the editor - I am unaware of the appropriate way to fetch data from DataTables via C++.

  • Could a similar functionality be implemented using Blueprint Function Libraries - is it more recommended? Similar to the above, I am still unsure how to access blueprints from my C++ code.

I will leave my class definition and partial implementation below if that provides any helpful context - just be aware that this is my first attempt with game programming, as such, some definitions, functionalities, and properties might not seem non-intuitive or unjustified.

.HPP


UCLASS()
class PROJECTGINGER_API ABaseStructureItems : public ABaseGameItem
{
    GENERATED_BODY()

    UPROPERTY(EditDefaultsOnly, Category = "Base Structure Properties")
        float totalHealth;

    UPROPERTY(EditDefaultsOnly, Category = "Base Structure Properties")
        float health;

    UPROPERTY(EditDefaultsOnly, Category = "Base Structure Properties")
        UStaticMeshComponent* itemStaticMesh;

    UPROPERTY(EditDefaultsOnly, Category = "Base Structure Properties")
        UBoxComponent* placementBox;

    UPROPERTY(EditDefaultsOnly, Category = "Base Structure Properties")
        UAudioComponent* itemAudio;

    UPROPERTY(EditDefaultsOnly, Category = "Base Structure Properties")
        UParticleSystemComponent* itemParticles;

    UPROPERTY(EditDefaultsOnly, Category = "Base Structure Properties")
        EPhysicalMaterials structureMaterial;


    // Constructor
public:
    ABaseStructureItems();

    // SECTION:
    // Class Main Functions
    UFUNCTION(BlueprintCallable, Category = "Base Structure Functions")
        void InflictDamage(float damage);


    // SECTION:
    // Class Events
    UFUNCTION(BlueprintNativeEvent, Category = "Base Structure Event")
        void OnDeath();

    UFUNCTION(BlueprintNativeEvent, Category = "Base Structure Event")
        void OnHit(FVector hitLocation, float damage);

    // SECTION:
    // Helper Functions. Functions are to be abstracted from Blueprints.
    UFUNCTION()
        void PlayHitSound();

    UFUNCTION()
        void PlayDeathSound();

    UFUNCTION()
        void PlaySpawnSound();

    UFUNCTION()
        void PlayDestroySequence();

    UFUNCTION()
        void PlaySpawnSequence();
};



.CPP


#include "Items/StructureItems/BaseStructureItems.h"

// Default Constructor
ABaseStructureItems::ABaseStructureItems()
{
    totalHealth = 500;
    health = totalHealth;
    structureMaterial = EPhysicalMaterials::M_Stone;

    placementBox = CreateDefaultSubobject<UBoxComponent>(TEXT("Placement Box"));
    placementBox->SetBoxExtent(FVector(200.f, 200.f, 96.f));
    placementBox->bDynamicObstacle = true;
    RootComponent = placementBox;

    itemStaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Structure Mesh"));
    itemStaticMesh->SetupAttachment(GetRootComponent());

    // Initializes the audio system component and de-activates it by default.
    itemAudio = CreateDefaultSubobject<UAudioComponent>(TEXT("Audio Component"));
    itemAudio->SetupAttachment(GetRootComponent());
    itemAudio->Deactivate();

    // Initializes the particle system component and de-activates it by default.
    itemParticles = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("Item Particles"));
    itemParticles->SetupAttachment(GetRootComponent());
    itemParticles->DeactivateSystem();
}



void ABaseStructureItems::InflictDamage(float damage)
{
    health = FMath::Clamp((health-damage), 0.f, 20000.f);

    if (health <= 0)
    {
        OnDeath();
    }
}


void ABaseStructureItems::OnDeath_Implementation()
{
    GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Destroyed Structure!"));
    Destroy();
}


void ABaseStructureItems::OnHit_Implementation(FVector hitLocation, float damage)
{
    InflictDamage(damage);

    // Strong Impact - Use heavy impact sounds and particles.
    if(damage > 0.25*totalHealth)
    { }

    // Medium Impact - Use Medium impact sounds and particles.
    else if(damage > 0.05*totalHealth && damage <= 0.25*totalHealth)
    {}

    // Weak Impact - Use Weak impact sounds and particles.
    else
    { }
}

// SECTION:
// Helper Functions. Functions are to be abstracted from Blueprints.


// FUNCTION: Play Hit Sound
// Activates the Audio components to play the provided sound clip.
// Decativates Audio component when done.
void ABaseStructureItems::PlayHitSound() {}


void ABaseStructureItems::PlayDeathSound() {}


void ABaseStructureItems::PlaySpawnSound() {}


void ABaseStructureItems::PlayDestroySequence() {}


void ABaseStructureItems::PlaySpawnSequence() {}

If I understood you want sort of a database that will hold multiple audio clips and you want to be able to retrieve those clips at any time.
Maybe a DataTable or a DataAsset will be ok for that.

That is exactly what I wanted to initially do. But as stated above, I do not know how to reference the DataTable through C++, knowing that the DataTable was created in the UE4 Editor. Additionally, I just wanted to make sure that this approach to audio handling is wise or fundamentally flawed - as this is my first experience doing this.

I like to setup my datatables in a custom project settings panel if I need them globally or in a custom world settings class if I need them per level.
Just make a UDataTable* UPROPERTY with EditAnywhere specifier.

It’s necessary that you define your datatable struct in C++ like this instead of blueprint struct



USTRUCT(BlueprintType)
struct FYourTableRow : public FTableRowBase
{
    GENERATED_BODY()
};


otherwise you won’t be able to cast your datatable rows to your struct type in C++

You will still be able to use the datatable globally in blueprints as always.