First off I have to say I love what’s posted here. Really nice elegant solution! My thought immediately went to Scriptable Objects and the Serializable Dictionary but I opted to not do that for my v1.
In my v1 (below) I wanted to try without it first to get some of the basics worked out first and see what issues arise.
One issue I seem to have run into is that when multiple sound effects are playing simultaneously some sounds effects don’t play at all. When I turn off the foot steps, I notice the action sequences sound so much more like what I expect which gives me a hint that there’s an issue when greater than some threshold of sound effects are playing.
Anyone know if you have to do anything special in Unity when you have multiple AudioSources? Each instance of this class has three AudioSources and there is one instance per character so there easily could be 20-30 AudioSources in my basic test scene.
using RPG.Attributes;
using RPG.Combat;
using RPG.Movement;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace RPG.Audio
{
[RequireComponent(typeof(Health))]
[RequireComponent(typeof(Fighter))]
[RequireComponent(typeof(Mover))]
public class CharacterAudioManager : MonoBehaviour
{
[SerializeField] private AudioSource mouthAudioSource;
[SerializeField] private AudioSource bodyAudioSource;
[SerializeField] private AudioSource feetAudioSource;
[SerializeField] private AudioClip[] tookDamageAudioClips;
[SerializeField] private AudioClip[] armorStruckAudioClips;
[SerializeField] private AudioClip[] heavyEffortAudioClips;
[SerializeField] private AudioClip[] footstepAudioClips;
[SerializeField] private AudioClip[] deathAudioClips;
private Health health;
private Fighter fighter;
private Mover mover;
//TODO - need some null checks and error handling
private void Awake()
{
health = GetComponent<Health>();
fighter = GetComponent<Fighter>();
mover = GetComponent<Mover>();
}
private void OnEnable()
{
health.CharacterDied += Health_CharacterDied;
health.CharacterTookDamage += Health_CharacterTookDamage;
mover.TookFootStep += Mover_TookFootStep;
fighter.Attacked += Fighter_Attacked;
//future use e.g.
//armorComponent.ArmorStruck += ArmorComponent_ArmorStruck;
}
private void OnDisable()
{
health.CharacterDied -= Health_CharacterDied;
health.CharacterTookDamage -= Health_CharacterTookDamage;
mover.TookFootStep -= Mover_TookFootStep;
fighter.Attacked -= Fighter_Attacked;
//future use e.g.
//armorComponent.ArmorStruck -= ArmorComponent_ArmorStruck;
}
private void Health_CharacterDied()
{
mouthAudioSource.PlayOneShot(GetRandomClip(SoundContext.Death));
}
private void Health_CharacterTookDamage(float damage)
{
mouthAudioSource.PlayOneShot(GetRandomClip(SoundContext.TakeDamage));
}
private void Mover_TookFootStep(float speed)
{
//TODO: Sound volume should be scaled by speed of movement
//TODO: Should probably also not try to play sounds of too far away characters
// since it seems to mess with other sounds.
if (speed > 2f) {
feetAudioSource.PlayOneShot(GetRandomClip(SoundContext.FootStep));
}
}
private void Fighter_Attacked()
{
mouthAudioSource.PlayOneShot(GetRandomClip(SoundContext.HeavyEffort));
}
private AudioClip GetRandomClip(SoundContext context)
{
AudioClip clipToReturn = null;
int randomIndex;
switch (context)
{
case SoundContext.TakeDamage:
randomIndex = Random.Range(0, tookDamageAudioClips.Length);
clipToReturn = tookDamageAudioClips[randomIndex];
break;
case SoundContext.ArmorStruck:
randomIndex = Random.Range(0, armorStruckAudioClips.Length);
clipToReturn = armorStruckAudioClips[randomIndex];
break;
case SoundContext.HeavyEffort:
randomIndex = Random.Range(0, heavyEffortAudioClips.Length);
clipToReturn = heavyEffortAudioClips[randomIndex];
break;
case SoundContext.FootStep:
randomIndex = Random.Range(0, footstepAudioClips.Length);
clipToReturn = footstepAudioClips[randomIndex];
break;
case SoundContext.Death:
randomIndex = Random.Range(0, deathAudioClips.Length);
clipToReturn = deathAudioClips[randomIndex];
break;
default:
Debug.LogWarning("Something went wrong!");
break;
}
return clipToReturn;
}
[System.Serializable]
public struct AudioMapping
{
public SoundContext context;
public AudioClip[] audioClips;
}
public enum SoundContext
{
TakeDamage,
HeavyEffort,
ArmorStruck,
FootStep,
Death
}
}
}