using UnityEngine; using UnityEngine.Rendering.Universal; namespace RR.Common.Entities { public class LightActionsController : MonoBehaviour { private enum Mode { Blink, Pulse, Noise, Curve } [Header("Target")] [SerializeField] private Light[] lights3D; [SerializeField] private Light2D[] lights2D; [Tooltip("Доп. вариант — крутить эмиссию материала (опционально)")] [SerializeField] private Renderer emissiveRenderer; private static readonly int EmissionColorID = Shader.PropertyToID("_EmissionColor"); [Header("Mode")] [SerializeField] private Mode mode = Mode.Blink; [Header("Intensity")] [SerializeField] private float minIntensity = 0f; [SerializeField] private float maxIntensity = 1f; [Header("Timings")] [SerializeField] private float frequency = 2f; // Гц для Pulse/Noise, миганий/сек для Blink [SerializeField, Range(0f, 1f)] private float duty = 0.2f; // Доля времени ON для Blink [0..1] [SerializeField] private AnimationCurve curve = AnimationCurve.EaseInOut(0, 0, 1, 1); [SerializeField] private bool useUnscaledTime = false; [Header("Randomness (optional)")] [SerializeField, Range(0f, 1f)] private float noiseAmplitude = 0.3f; // для Noise (0..1) [SerializeField] private float noiseSpeed = 1.0f; // скорость «пламени» [SerializeField] private Vector2 blinkJitter = new(-0.1f, 0.1f); // случайный сдвиг фазы Blink [Header("Color (optional)")] [SerializeField] private bool modulateColor = false; [SerializeField] private Gradient colorOverCycle; private float _blinkOffset; private Material _matInstance; private Color _baseEmission = Color.white; private void Reset() { lights3D = GetComponentsInChildren(); lights2D = GetComponentsInChildren(); emissiveRenderer = GetComponent(); } private void Awake() { if (emissiveRenderer && emissiveRenderer.sharedMaterial && _matInstance == null) { _matInstance = emissiveRenderer.material; if (_matInstance.HasProperty(EmissionColorID)) { _baseEmission = _matInstance.GetColor(EmissionColorID); _matInstance.EnableKeyword("_EMISSION"); } } _blinkOffset = Random.Range(blinkJitter.x, blinkJitter.y); } private void Update() { float time = useUnscaledTime ? Time.unscaledTime : Time.time; float phase; float k; // 0..1 switch (mode) { case Mode.Blink: // пила с джиттером phase = Mathf.Repeat((time + _blinkOffset) * Mathf.Max(0.0001f, frequency), 1f); k = phase < Mathf.Clamp01(duty) ? 1f : 0f; break; case Mode.Pulse: // синус → 0..1 k = 0.5f * (1f + Mathf.Sin(time * Mathf.PI * 2f * frequency)); break; case Mode.Noise: // Perlin: базовый уровень + шум float u = time * noiseSpeed; float n = Mathf.PerlinNoise(u, 0.123f); // 0..1 float baseK = 0.5f * (1f + Mathf.Sin(time * Mathf.PI * 2f * frequency)); // мягкий пульс k = Mathf.Clamp01(baseK * (1f - noiseAmplitude) + n * noiseAmplitude); break; case Mode.Curve: // цикл 0..1 по частоте, кривой задаём форму phase = Mathf.Repeat(time * Mathf.Max(0.0001f, frequency), 1f); k = Mathf.Clamp01(curve.Evaluate(phase)); break; default: k = 1f; break; } float intensity = Mathf.Lerp(minIntensity, maxIntensity, k); ApplyIntensity(intensity); if (modulateColor && colorOverCycle != null) { ApplyColor(colorOverCycle.Evaluate(k)); } } private void ApplyIntensity(float value) { if (lights3D != null) foreach (var t in lights3D) if (t) t.intensity = value; if (lights2D != null) foreach (var t in lights2D) if (t) t.intensity = value; if (_matInstance && _matInstance.HasProperty(EmissionColorID)) _matInstance.SetColor(EmissionColorID, _baseEmission * value); } private void ApplyColor(Color c) { if (lights3D != null) foreach (var t in lights3D) if (t) t.color = c; if (lights2D != null) foreach (var t in lights2D) if (t) t.color = c; if (_matInstance && _matInstance.HasProperty(EmissionColorID)) _matInstance.SetColor(EmissionColorID, c * Mathf.Max(0.0001f, _matInstance.GetColor(EmissionColorID).maxColorComponent)); } void OnDestroy() { if (_matInstance) Destroy(_matInstance); } } }