using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; [RequireComponent(typeof(Collider2D))] public class LightDimmer : MonoBehaviour { [Tooltip("Если не указан, будет использован Collider2D на этом же объекте.")] [SerializeField] private Collider2D targetCollider; [Tooltip("Тег игрока (используется для поиска Transform игрока)")] [SerializeField] private string playerTag; [Tooltip("Массив со всеми источниками света, которые нужно изменять")] [SerializeField] private Light2D[] lights; [Tooltip("Использовать прогресс по оси Y вместо оси X")] [SerializeField] private bool useYProgress = false; [Header("Настройки света")] [SerializeField] [Min(0)] private float startIntensity; [SerializeField] [Min(0)] private float endIntensity; [SerializeField] [Min(0)] private float smoothing; [Header("Настройки свечения")] [SerializeField] private bool applyBloom = true; [SerializeField] [Min(0)] private float startBloomIntensity = 0f; [SerializeField] [Min(0)] private float targetBloomIntensity = 1f; private Transform playerTransform; // Храним все коллайдеры игрока, которые в данный момент пересекают триггер private readonly HashSet playerColliders = new HashSet(); private float boundsMin; private float boundsMax; private Volume[] _volumes; private void OnValidate() { if (targetCollider != null) { UpdateBounds(); } if (string.IsNullOrEmpty(playerTag)) playerTag = "Player"; } private void OnEnable() { if (targetCollider == null) targetCollider = GetComponent(); if (targetCollider != null) { UpdateBounds(); } _volumes = new Volume[lights.Length]; if (string.IsNullOrEmpty(playerTag)) playerTag = "Player"; var playerObj = GameObject.FindGameObjectWithTag(playerTag); if (playerObj != null) playerTransform = playerObj.transform; for (int i = 0; i < lights.Length; i++) { Light2D light2D = lights[i]; Volume volume = light2D.GetComponentInParent(); if (volume != null) { volume.enabled = true; } _volumes[i] = volume; } } private void Start() { if (targetCollider == null) { targetCollider = GetComponent(); } UpdateBounds(); if (string.IsNullOrEmpty(playerTag)) playerTag = "Player"; } private void Update() { // Нужна ссылка на игрока и хотя бы один свет и collider if (!playerTransform || lights == null || lights.Length == 0 || targetCollider == null) return; // Проверяем, что игрок действительно внутри триггера (с учётом возможной множественной геометрии) bool playerInside = playerColliders.Count > 0; if (!playerInside) return; Vector3 playerPos = playerTransform.position; // Дополнительная страховка: проверяем AABB bounds if (!targetCollider.bounds.Contains(playerPos)) return; float playerCurrent = useYProgress ? playerPos.y : playerPos.x; float t = 0f; if (!Mathf.Approximately(boundsMax, boundsMin)) { t = Mathf.InverseLerp(boundsMin, boundsMax, playerCurrent); t = Mathf.Clamp01(t); } // Интерполируем интенсивность между startXIntensity и endXIntensity float desiredForPosition = Mathf.Lerp(startIntensity, endIntensity, t); float desiredForBloom = Mathf.Lerp(startBloomIntensity, targetBloomIntensity, t); for (int i = 0; i < lights.Length; i++) { var light2D = lights[i]; _volumes[i].profile.TryGet(out Bloom bloom); if (!light2D) continue; if (smoothing <= 0f) { light2D.intensity = desiredForPosition; if (applyBloom && bloom != null) bloom.intensity.value = desiredForBloom; } else { light2D.intensity = Mathf.MoveTowards(light2D.intensity, desiredForPosition, smoothing * Time.deltaTime); if (applyBloom && bloom != null) bloom.intensity.value = Mathf.MoveTowards(bloom.intensity.value, desiredForBloom, smoothing * Time.deltaTime); } } } private void OnTriggerEnter2D(Collider2D other) { if (!other.CompareTag(playerTag)) return; // Запоминаем коллайдер игрока playerColliders.Add(other); // Сохраняем Transform игрока (на случай, если раньше не найден) if (playerTransform == null) playerTransform = other.transform; } private void OnTriggerExit2D(Collider2D other) { if (!other.CompareTag(playerTag)) return; // Убираем коллайдер из множества; если множество пустое — игрок полностью вышел playerColliders.Remove(other); } private void UpdateBounds() { var b = targetCollider.bounds; boundsMin = b.min.x; boundsMax = b.max.x; if (useYProgress) { boundsMin = b.min.y; boundsMax = b.max.y; } } void OnDrawGizmosSelected() { if (targetCollider == null) return; var b = targetCollider.bounds; Gizmos.color = Color.yellow; Gizmos.DrawLine(new Vector3(b.min.x, b.min.y, 0f), new Vector3(b.max.x, b.min.y, 0f)); Gizmos.DrawLine(new Vector3(b.max.x, b.min.y, 0f), new Vector3(b.max.x, b.max.y, 0f)); Gizmos.DrawLine(new Vector3(b.max.x, b.max.y, 0f), new Vector3(b.min.x, b.max.y, 0f)); Gizmos.DrawLine(new Vector3(b.min.x, b.max.y, 0f), new Vector3(b.min.x, b.min.y, 0f)); if (playerTransform != null) { Gizmos.color = Color.cyan; Vector3 p = playerTransform.position; Gizmos.DrawSphere(new Vector3(p.x, p.y, 0f), 0.05f); } } }