Danro/Assets/Scripts/Behaviour/LightDimmer.cs

194 lines
6.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<Collider2D> playerColliders = new HashSet<Collider2D>();
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<Collider2D>();
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<Volume>();
if (volume != null)
{
volume.enabled = true;
}
_volumes[i] = volume;
}
}
private void Start()
{
if (targetCollider == null)
{
targetCollider = GetComponent<Collider2D>();
}
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);
}
}
}