/// <summary> /// Called when the volumes enabled on a layer have changed. /// </summary> /// <param name="layer">The layer to mark dirty.</param> internal void SetLayerDirty(VolumeLayer layer) { m_sortNeeded[layer] = true; }
/// <summary> /// Finds the volumes on a layer that have a non-zero influence given a scene point. /// </summary> /// <param name="target">The transform whose position is used to compute volume distance. /// When null, only global volumes are considred.</param> /// <param name="layer">The volume layer controlling which volumes are evaluated.</param> /// <returns>A list of relevant volumes sorted by decending weight.</returns> public IReadOnlyList <WeightedVolume> Evaluate(Transform target, VolumeLayer layer) { m_weightedVolumes.Clear(); if (layer == null) { return(m_weightedVolumes); } if (!m_volumes.TryGetValue(layer, out var volumes)) { return(m_weightedVolumes); } // update the volume layer if it is dirty if (m_sortNeeded[layer]) { volumes.Sort((a, b) => a.Priority.CompareTo(b.Priority)); m_sortNeeded[layer] = false; } foreach (var volume in volumes) { if (!volume.enabled || volume.Weight <= 0) { continue; } if (volume.IsGlobal) { AddWeightedVolume(new WeightedVolume { volume = volume, weight = volume.Weight, }); continue; } if (target == null || volume.Colliders.Count == 0) { continue; } // find the squared distance from the volume to the point var pos = target.position; var closestDistanceSqr = float.PositiveInfinity; foreach (var collider in volume.Colliders) { if (collider.enabled) { var d = (collider.ClosestPoint(pos) - pos).sqrMagnitude; if (d < closestDistanceSqr) { closestDistanceSqr = d; } } } // check if the volume is close enough to have influence var blendDistSqr = volume.BlendDistance * volume.BlendDistance; if (closestDistanceSqr > blendDistSqr) { continue; } // linearlize the distance and compute the influence var weight = volume.Weight; if (blendDistSqr > 0f) { weight *= 1f - (Mathf.Sqrt(closestDistanceSqr) / Mathf.Sqrt(blendDistSqr)); } AddWeightedVolume(new WeightedVolume { volume = volume, weight = weight, }); } // sort the volumes by decending influence m_weightedVolumes.Sort((a, b) => b.weight.CompareTo(a.weight)); return(m_weightedVolumes); }
/// <inheritdoc/> protected override void UpdateBlending(Transform target, VolumeLayer layer) { foreach (var source in m_sources) { source.volume = 0f; } m_active.Clear(); var profiles = AudioVolumeManager.Instance.Evaluate(target, layer); for (var i = 0; i < profiles.Count; i++) { var profileBlend = profiles[i]; var volume = profileBlend.volume; var profile = volume.Audio; if (profile.Clip != null) { // create an audiosource for this sound if (!m_profileToSources.TryGetValue(profile, out var source)) { source = gameObject.AddComponent <AudioSource>(); source.clip = profile.Clip; source.outputAudioMixerGroup = profile.Mixer; source.playOnAwake = false; source.loop = profile.Loop; source.pitch = profile.Pitch; source.panStereo = profile.Pan; source.spatialBlend = 0f; source.volume = 0f; m_profileToSources.Add(profile, source); m_sources.Add(source); } m_active.Add(source); // set the volume based on the weight var vol = volume.Volume * profileBlend.weight; if (!source.isPlaying && vol > 0) { source.Play(); } source.volume += vol; } } // make sure any sources not in an active volume are not playing foreach (var source in m_sources) { if (source.isPlaying && !m_active.Contains(source)) { if (m_restartWhenActivated) { source.Stop(); } else { source.Pause(); } source.volume = 0f; } } }
/// <summary> /// Evaluates and applies the volume blend. /// </summary> /// <param name="target">The transform position to use.</param> /// <param name="layer">The volume layer controlling which volumes are evaluated.</param> protected abstract void UpdateBlending(Transform target, VolumeLayer layer);
/// <inheritdoc/> protected override void UpdateBlending(Transform target, VolumeLayer layer) { foreach (var source in m_sources) { source.Volume = 0f; } m_active.Clear(); var volumesWeights = MusicVolumeManager.Instance.Evaluate(target, layer); for (var i = 0; i < volumesWeights.Count; i++) { var profileBlend = volumesWeights[i]; var volume = profileBlend.volume; var profile = volume.Music; if (profile != null && profile.Track != null) { if (!m_profileToSources.TryGetValue(profile, out var source)) { source = new MusicPlayer(gameObject, m_pausable) { Volume = 0f }; m_profileToSources.Add(profile, source); m_sources.Add(source); } m_active.Add(source); // set the volume based on the weight var vol = volume.Volume * profileBlend.weight; if (!source.IsPlaying && vol > 0) { source.Play(profile); } source.Volume += vol; } } // make sure any sources not in an active volume are not playing foreach (var source in m_sources) { if (source.IsPlaying && !m_active.Contains(source)) { if (m_restartWhenActivated) { source.Stop(); } else { source.Pause(); } source.Volume = 0f; } source.Update(); } }