using UnityEngine; namespace Gaia { [RequireComponent(typeof(WindZone))] public class WindManager : MonoBehaviour { #region Variables #region Public Variables public bool m_useWindAudio = true; public float windGlobalMaxDist = 1000f; public Vector4 windGlobals; public Vector4 windGlobalsB; public AudioClip m_windAudioClip; public float m_windTransitionTime = 5f; #endregion #region Private Variables [SerializeField] private WindZone m_windZone; private AudioSource m_windAudioSource; private int m_shaderPropertyIDWindGlobals; private int m_shaderPropertyIDWindGlobalsB; private Vector3 m_windDirection; private Vector4 m_targetWindGlobals; private float m_windTime = 0; private bool m_canProcessWind = false; private float m_currentWindSpeed = 0f; private float m_currentWindVolume = 0f; #endregion #endregion #region Unity Function private void Start() { Setup(); } private void Update() { UpdateWind(); if (m_useWindAudio) { CheckWindVolume(); if (m_canProcessWind) { ProcessWindAudio(); } } } #endregion #region Public Functions /// /// Applies the settings isntantly /// public void InstantWindApply() { Setup(); m_windDirection = m_windZone.transform.forward; m_targetWindGlobals.x = m_windDirection.x; m_targetWindGlobals.y = -Mathf.Max(m_windDirection.y, Vector2.Distance(new Vector2(m_windDirection.x, m_windDirection.z), Vector2.zero) * 0.5f); // force some data into y to give branches some bounce m_targetWindGlobals.z = m_windDirection.z; m_targetWindGlobals.w = Mathf.Clamp(m_windZone.windMain, 0.0f, 1.2f); windGlobals = m_targetWindGlobals; Shader.SetGlobalVector(m_shaderPropertyIDWindGlobals, windGlobals); windGlobalsB.x = windGlobalMaxDist; windGlobalsB.y = Mathf.Pow(windGlobals.w * 0.5f + 0.5f, 3.0f) * 0.1f; Shader.SetGlobalVector(m_shaderPropertyIDWindGlobalsB, windGlobalsB); } /// /// Processes and updates the wind /// public void UpdateWind() { m_windDirection = m_windZone.transform.forward; m_targetWindGlobals.x = m_windDirection.x; m_targetWindGlobals.y = -Mathf.Max(m_windDirection.y, Vector2.Distance(new Vector2(m_windDirection.x, m_windDirection.z), Vector2.zero) * 0.5f); // force some data into y to give branches some bounce m_targetWindGlobals.z = m_windDirection.z; m_targetWindGlobals.w = Mathf.Clamp(m_windZone.windMain, 0.0f, 1.2f); windGlobals = Vector4.Lerp(windGlobals, m_targetWindGlobals, Time.deltaTime * 0.25f); Shader.SetGlobalVector(m_shaderPropertyIDWindGlobals, windGlobals); m_windTime += Time.deltaTime * Mathf.Pow(windGlobals.w * 0.5f + 0.5f, 3.0f) * 0.1f; if (m_windTime > 100.0f) { m_windTime -= 100.0f; } windGlobalsB.x = windGlobalMaxDist; windGlobalsB.y = m_windTime; Shader.SetGlobalVector(m_shaderPropertyIDWindGlobalsB, windGlobalsB); } #endregion #region Private Functions /// /// Sets up the wind manager /// private void Setup() { m_shaderPropertyIDWindGlobals = Shader.PropertyToID("_PW_WindGlobals"); m_shaderPropertyIDWindGlobalsB = Shader.PropertyToID("_PW_WindGlobalsB"); if (m_windZone == null) { m_windZone = GetWindZone(); } if (m_windZone == null) { m_windDirection = m_windZone.transform.forward; windGlobals.x = m_windDirection.x; windGlobals.y = m_windDirection.y; windGlobals.z = m_windDirection.z; windGlobals.w = m_windZone.windMain; m_currentWindSpeed = m_windZone.windMain; m_currentWindVolume = Mathf.Clamp01(m_windZone.windMain); } if (Application.isPlaying) { m_windAudioSource = GetWindAudioSource(); if (m_windAudioSource != null) { m_windAudioSource.clip = m_windAudioClip; m_windAudioSource.volume = m_currentWindVolume; if (!m_windAudioSource.isPlaying) { m_windAudioSource.Play(); } } } } /// /// Checks if the volume needs to be processed /// private void CheckWindVolume() { if (m_windZone.windMain != m_currentWindSpeed) { if (m_windAudioSource != null) { m_currentWindVolume = m_windAudioSource.volume; m_canProcessWind = true; } } } /// /// Processes the volume for the wind to be updated /// private void ProcessWindAudio() { if (m_windAudioClip == null || m_windAudioSource == null) { return; } float clampedWindSpeed = Mathf.Clamp01(m_windZone.windMain); m_windAudioSource.clip = m_windAudioClip; if (!m_windAudioSource.isPlaying) { m_windAudioSource.Play(); } m_windAudioSource.volume = Mathf.Lerp(m_currentWindVolume, clampedWindSpeed, Time.deltaTime / m_windTransitionTime); if (m_currentWindVolume >= clampedWindSpeed) { if (m_windAudioSource.volume <= clampedWindSpeed - 0.05f) { m_windAudioSource.volume = clampedWindSpeed; m_canProcessWind = false; } } else { if (m_windAudioSource.volume >= clampedWindSpeed - 0.05f) { m_windAudioSource.volume = clampedWindSpeed; m_canProcessWind = false; } } } /// /// Gets the wind audio source from the object /// /// private AudioSource GetWindAudioSource() { if (m_windAudioSource != null) { return m_windAudioSource; } AudioSource audioSource = GetComponent(); if (audioSource == null) { audioSource = gameObject.AddComponent(); } audioSource.loop = true; audioSource.playOnAwake = true; audioSource.maxDistance = 100000f; return audioSource; } /// /// Gets the wind zone /// /// private WindZone GetWindZone() { WindZone windZone = gameObject.GetComponent(); if (windZone == null) { windZone = gameObject.AddComponent(); } return windZone; } #endregion #region Public Static Functions /// /// Removes the manager from the scene /// public static void RemoveWindManager() { WindManager manager = FindObjectOfType(); if (manager != null) { DestroyImmediate(manager); } } #endregion } }