Files
chameleon/Assets/Scripts/Audio/SoundEffect.cs
T
adminandClaude Fable 5 0172a1e834 Radar ping taunt sound + per-SoundEffect spatialize opt-in
MatchManager: new Radar Ping Sound property; MsgRadarPing now goes to
all clients (spawnBlips flag keeps blips hunter-only), sound plays 3D
at each pinged hider. Distance-based stagger (speed of sound + 35 ms
min gap) prevents phase cancellation when multiple hiders ping.

SoundEffect: new spatialize toggle (per asset, applied only to 3D
instances -> Steam Audio HRTF); removed unused fade field.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 23:11:39 +02:00

177 lines
5.0 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
namespace Prototype
{
[CreateAssetMenu(menuName = "Prototype/Sound Effect")]
public class SoundEffect : ScriptableObject
{
[SerializeField] SoundEffectDistanceRange distanceRange;
[SerializeField] Vector2 volumeMultiplier = new(1, 1);
[SerializeField] Vector2 pitch = new(.95f, 1.05f);
[Header("Additional Settings")]
public AudioMixerGroup audioMixerGroup;
public float volumeMultiplierFactor = 1;
[SerializeField] bool loop;
[SerializeField] bool spatialize;
[Header("Additional Settings")]
[SerializeField, Range(0, 1)] float defaultVolume = .8f;
[SerializeField, Range(-1, 1)] float additionalGain = 0;
[SerializeField] float maxPlayInterval = .1f;
[Header("Clips")]
[SerializeField] List<AudioClip> clips;
public int ClipCount => clips.Count;
float lastPlayTime;
public SoundEffectOptions ToOptions() => new()
{
audioMixerGroup = audioMixerGroup,
volumeMultiplier = Random.Range(volumeMultiplier.x, volumeMultiplier.y) * volumeMultiplierFactor,
pitch = Random.Range(pitch.x, pitch.y),
loop = loop,
spatialize = spatialize,
distanceRange = distanceRange ? distanceRange.range : null
};
#if UNITY_EDITOR
public void ApplyVolumeMultiplierFactor()
{
volumeMultiplier *= volumeMultiplierFactor;
volumeMultiplierFactor = 1;
}
void OnEnable()
{
Initialize();
UnityEditor.EditorApplication.playModeStateChanged -= PlayModeStateChanged;
UnityEditor.EditorApplication.playModeStateChanged += PlayModeStateChanged;
}
void PlayModeStateChanged(UnityEditor.PlayModeStateChange change)
{
if (change == UnityEditor.PlayModeStateChange.EnteredEditMode)
{
Initialize();
return;
}
if (change == UnityEditor.PlayModeStateChange.ExitingEditMode)
{
Initialize();
return;
}
}
#endif
void Initialize()
{
lastPlayTime = -1;
}
public AudioClip GetClip(int index)
{
return clips[index];
}
public SoundEffectInstance Play()
{
return PlayInternal(Vector3.zero, 0);
}
public SoundEffectInstance Play(Vector3 position)
{
return PlayInternal(position, 0);
}
public SoundEffectInstance Play(Transform transform)
{
return PlayInternal(transform.position, 0);
}
public SoundEffectInstance Play(Vector3 position, float delay)
{
return PlayInternal(position, delay);
}
public SoundEffectInstance Play(Transform transform, float delay)
{
return PlayInternal(transform.position, delay);
}
public SoundEffectInstance PlayFirstClip()
{
return PlayInternal(Vector3.zero, 0, true);
}
public SoundEffectInstance PlayFirstClip(bool destroyOnLoad)
{
return PlayInternal(Vector3.zero, 0, true, destroyOnLoad);
}
public SoundEffectInstance PlayFirstClipAt(Vector3 position)
{
return PlayInternal(position, 0, true);
}
public SoundEffectInstance PlayFirstClipWithDelayAt(Vector3 position, float delay)
{
return PlayInternal(position, delay, true);
}
SoundEffectInstance PlayInternal(Vector3 position, float delay, bool firstClip = false, bool destroyOnLoad = true)
{
var options = ToOptions();
options.delay = delay;
options.destroyOnLoad = destroyOnLoad;
AudioClip clip;
if (firstClip)
{
clip = clips[0];
}
else
{
int rngIndex = Random.Range(0, clips.Count);
clip = clips[rngIndex];
}
var time = Time.time;
if (!Mathf.Approximately(maxPlayInterval, 0))
{
if (time - lastPlayTime < maxPlayInterval)
{
return null;
}
}
lastPlayTime = time;
var gameObject = new GameObject($"{this.name} -- {clip.name}");
gameObject.SetActive(false);
gameObject.transform.position = position;
if (!options.volume.HasValue)
{
options.volume = defaultVolume;
}
options.volume += additionalGain;
var soundEffectInstance = gameObject.AddComponent<SoundEffectInstance>();
soundEffectInstance.clip = clip;
soundEffectInstance.options = options;
gameObject.SetActive(true);
return soundEffectInstance;
}
}
}