using System.Collections; using System.Collections.Generic; using UnityEngine; [System.Serializable] public class FlickeringLightData { public Light light; public float maxIntensity; } [System.Serializable] public class FlickeringRendererData { public Renderer renderer; [Range(0f, 10f)] public float flickerFactorMin = 1.2f; [Range(0f, 10f)] public float flickerFactorMax = 0.8f; } [RequireComponent(typeof(AudioSource))] public class LightAnimationUpdate : MonoBehaviour { AudioSource lightFlickerAudioSource; //AudioClip lightFlickerAudioClip; AudioClip lightFlickerAudioClipForThisObject; Animator _lightAnimator; LightBulbEmissionUpdate _lightBulbEmissionUpdate; public List flickeringLightsData; // List of Lights and their maxIntensity public List flickeringRenderersData; // List of Renderers and their maxIntensity public float minIntensity = 0f; public float flickerSpeed = 500f; // Adjust this to control the overall speed of flickering public float intensityVariation = 0.1f; // Adjust this to control the strength of the flickering effect public int flickerSetCount = 25; // Number of flickers in a set before the pause public float flickerSetPause = 1.5f; // Duration of the pause between flicker sets private List originalLightIntensities = new List(); private List originalRendererIntensities = new List(); private List originalEmissiveMaps = new List(); private Dictionary> emissiveMaterialsMap = new Dictionary>(); // Store emissive materials for each Renderer [HideInInspector] public bool isFlickering = false; private SanityActivation[] sanity; private void Start() { lightFlickerAudioSource = GetComponent(); lightFlickerAudioSource.loop = true; lightFlickerAudioSource.spatialBlend = 1f; lightFlickerAudioSource.maxDistance = 10f; //lightFlickerAudioClip = Resources.Load("LightSounds/LightFlickerLoop"); if (flickeringLightsData == null || flickeringLightsData.Count == 0) { Debug.LogError("FlickeringLightsAndEmission script needs a list of lights data to flicker!"); return; } // Store the original intensities of all lights foreach (FlickeringLightData data in flickeringLightsData) { originalLightIntensities.Add(data.light.intensity); } // Store the original emissive maps and intensities of all renderers with emissive materials foreach (FlickeringRendererData data in flickeringRenderersData) { Renderer renderer = data.renderer; List emissiveMaterials = new List(); // Filter out materials with emissive maps foreach (Material material in renderer.materials) { if (material.GetTexture("_EmissiveColorMap")) { emissiveMaterials.Add(material); // Store the original emissive exposure weights for each material originalRendererIntensities.Add(material.GetFloat("_EmissiveExposureWeight")); } } emissiveMaterialsMap.Add(renderer, emissiveMaterials); // Store the original emissive maps for each material foreach (Material emissiveMaterial in emissiveMaterials) { originalEmissiveMaps.Add(emissiveMaterial.GetTexture("_EmissiveColorMap")); } } try { // Get all components in the children of the transform sanity = GetComponentsInChildren(); } catch (System.Exception e) { // Handle exceptions here Debug.LogError($"An error occurred: {e.Message}"); } } public void LightIsFlickering() { _lightAnimator.SetBool("IsFlickering", true); if (!_lightAnimator.enabled) //If light animator is not enabled: { _lightAnimator.enabled = true; //Enable it. } if (!_lightBulbEmissionUpdate.UpdateEmission) { _lightBulbEmissionUpdate.UpdateEmission = true; } _lightBulbEmissionUpdate.IsFlickering = true; } public void LightIsNotFlickering() { _lightAnimator.SetBool("IsFlickering", false); _lightBulbEmissionUpdate.ResetEmission(); if (!_lightAnimator.enabled) //If light animator is not enabled: { _lightAnimator.enabled = true; //Enable it. } _lightBulbEmissionUpdate.IsFlickering = false; } public void StartFlickering() { if (!isFlickering) { isFlickering = true; //lightFlickerAudioSource.clip = lightFlickerAudioClip; //lightFlickerAudioSource.Play(); RandomSoundsManager.GetInstance().PlayLightBussSound(lightFlickerAudioSource); #region Sanity triggers if (sanity.Length > 0) { foreach (var _sanity in sanity) { _sanity.DisableSanityTrigger(); } } #endregion StartCoroutine(FlickerCoroutine()); } } public void StopFlickering() { if (isFlickering) { // Reset intensities of all lights to original values for (int i = 0; i < flickeringLightsData.Count; i++) { if (flickeringLightsData[i] != null) { flickeringLightsData[i].light.intensity = originalLightIntensities[i]; } } // Reset intensities of all renderers to original values for (int i = 0; i < flickeringRenderersData.Count; i++) { if (flickeringRenderersData[i] != null) { flickeringRenderersData[i].renderer.material.SetFloat("_EmissiveExposureWeight", originalRendererIntensities[i]); } } // Reset emissive maps of all renderers to original values for (int i = 0; i < flickeringRenderersData.Count; i++) { if (flickeringRenderersData[i] != null) { flickeringRenderersData[i].renderer.material.SetTexture("_EmissiveColorMap", originalEmissiveMaps[i]); } } //Stop the flickering sound from all the lights StopCoroutine(FlickerCoroutine()); StartCoroutine(StopAudioSourceAfterSeconds()); //lightFlickerAudioSource.clip = null; //lightFlickerAudioSource.Stop(); #region Sanity triggers if (sanity.Length > 0) { foreach (var _sanity in sanity) { _sanity.EnableSanityTrigger(); } } #endregion isFlickering = false; } } private IEnumerator FlickerCoroutine() { int flickerCount = 0; while (isFlickering) { // 1. Υπολογίζουμε μία φορά το noise, κοινό για φως και emissive float noise = Mathf.PerlinNoise(Time.time * flickerSpeed, 0f); // 2. Υπολογισμός της νέας έντασης για τα φώτα float flickerLightIntensity = Mathf.Lerp(minIntensity, flickeringLightsData[0].maxIntensity, noise * intensityVariation); // 3. Εφαρμόζουμε την τιμή σε όλα τα φώτα foreach (FlickeringLightData data in flickeringLightsData) { data.light.intensity = flickerLightIntensity; } // 4. Εφαρμόζουμε flicker στα emissive materials, με τον ίδιο ρυθμό (ίδιο noise) foreach (FlickeringRendererData data in flickeringRenderersData) { Material[] materialsArray = data.renderer.materials; foreach (var lightBulbRendMaterial in materialsArray) { int rendererIndex = flickeringRenderersData.IndexOf(data); float originalEmissionIntensity = originalRendererIntensities[rendererIndex]; // Κρατάμε τον flicker παράγοντα πιο χαμηλό για να αποφεύγουμε υπερφωτισμούς float flickerFactor = Mathf.Lerp(data.flickerFactorMin, data.flickerFactorMax, noise); float flickerEmissionIntensity = originalEmissionIntensity * flickerFactor; lightBulbRendMaterial.SetFloat("_EmissiveExposureWeight", flickerEmissionIntensity); } // Αν έχεις κάνει αλλαγές στα materials, ξαναπέρασέ τα data.renderer.materials = materialsArray; } // 5. Διαχείριση flicker sets και παύσεων flickerCount++; if (flickerCount >= flickerSetCount) { flickerCount = 0; // reset lightFlickerAudioSource.Stop(); yield return new WaitForSeconds(flickerSetPause); float randomTime = Random.Range(0f, lightFlickerAudioSource.clip.length); lightFlickerAudioSource.time = randomTime; lightFlickerAudioSource.Play(); } else { yield return new WaitForSeconds(0.1f); // μικρό delay ανά flicker } } } private IEnumerator StopAudioSourceAfterSeconds() { yield return new WaitForSeconds(0.1f); lightFlickerAudioSource.Stop(); print("Stop light flickering audio source"); } private Texture2D CreateFlickerEmissiveMap(Texture originalEmissiveMap, float flickeringIntensity) { // Copy the original emissive map to a new RenderTexture RenderTexture renderTexture = new RenderTexture(originalEmissiveMap.width, originalEmissiveMap.height, 0); Graphics.Blit(originalEmissiveMap, renderTexture); // Set the active RenderTexture for writing RenderTexture.active = renderTexture; // Create a new Texture2D to store the modified emissive map Texture2D flickerEmissiveMap = new Texture2D(originalEmissiveMap.width, originalEmissiveMap.height); flickerEmissiveMap.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0); flickerEmissiveMap.Apply(); // Apply brightness modification to each pixel in the emissive map Color[] pixels = flickerEmissiveMap.GetPixels(); for (int i = 0; i < pixels.Length; i++) { pixels[i] *= flickeringIntensity; } flickerEmissiveMap.SetPixels(pixels); flickerEmissiveMap.Apply(); // Clean up RenderTexture RenderTexture.active = null; renderTexture.Release(); return flickerEmissiveMap; } }