using UnityEngine; using Cysharp.Threading.Tasks; using System.Threading; using System; using System.Collections.Concurrent; using System.Collections.Generic; public class ReplicasSystem : MonoBehaviour { [SerializeField] AudioSource audioSource; [SerializeField] float delay = 0.5f; private bool initialized = false; private ConcurrentQueue replicas; public void Init() { if (initialized) { Debug.LogWarning("Попытка повторной инициализации системы", this); return; } if (audioSource == null) { Debug.LogError("Не установлен AudioSource", this); return; } replicas = new ConcurrentQueue(); var token = this.GetCancellationTokenOnDestroy(); Process(token).Forget(); initialized = true; } public void EnqueueReplica(Replica replica) { if (!initialized) return; var handledReplica = replica; if (handledReplica.clip == null) return; if (UnityEngine.Random.Range(0f, 1f) >= handledReplica.probability) return; if (handledReplica.playParallel) { audioSource.PlayOneShot(handledReplica.clip); return; } handledReplica.creationTime = Time.time; replicas.Enqueue(handledReplica); } public void EnqueueReplica(ReplicasSequence replicas) => EnqueueReplica(replicas.GetRandomReplica()); private async UniTask Process(CancellationToken token) { while (!token.IsCancellationRequested) { if (replicas.TryDequeue(out Replica replica)) { bool replicaIsFresh = Time.time - replica.creationTime <= replica.lifetime; if (replicaIsFresh) { audioSource.PlayOneShot(replica.clip); await UniTask.Delay(TimeSpan.FromSeconds(replica.clip.length + delay), cancellationToken: token); continue; } } await UniTask.Yield(); } } [Serializable] public struct Replica { public AudioClip clip; public float lifetime; public bool playParallel; [Range(0,1)] public float probability; [HideInInspector] public float creationTime; } [Serializable] public struct ReplicasSequence // для набора однообразных реплик { public List clips; public float lifetime; public bool playParallel; [Range(0, 1)] public float probability; public Replica GetRandomReplica() { if(clips == null || clips.Count == 0) return default(Replica); var clip = clips[UnityEngine.Random.Range(0, clips.Count)]; var replica = new Replica(); replica.clip = clip; replica.lifetime = lifetime; replica.playParallel = playParallel; replica.probability = probability; return replica; } } }