166 lines
6.0 KiB
C#
166 lines
6.0 KiB
C#
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using UnityEngine.Rendering.Universal;
|
||
|
||
[RequireComponent(typeof(Collider2D))]
|
||
public class LightDimmer : MonoBehaviour
|
||
{
|
||
[Tooltip("Если не указан, будет использован Collider2D на этом же объекте.")]
|
||
[SerializeField] private Collider2D targetCollider;
|
||
|
||
[Tooltip("Тег игрока (используется для поиска Transform игрока)")]
|
||
[SerializeField] private string playerTag;
|
||
|
||
[Tooltip("Если хотите явно назначить конкретный Light2D для этого экземпляра, укажите его здесь (приоритет).")]
|
||
[SerializeField] private Light2D[] lights;
|
||
|
||
[Tooltip("Интенсивность света у минимального X (bounds.min.x)")]
|
||
[SerializeField] private float startXIntensity;
|
||
|
||
[Tooltip("Интенсивность света у максимального X (bounds.max.x)")]
|
||
[SerializeField] private float endXIntensity;
|
||
|
||
[Tooltip("Опционально: сглаживание изменения (0 мгновенно, >0 — скорость, единицы: интенсивность/сек)")]
|
||
[SerializeField] [Min(0)] private float smoothing;
|
||
|
||
private Transform playerTransform;
|
||
|
||
// Храним все коллайдеры игрока, которые в данный момент пересекают триггер
|
||
private readonly HashSet<Collider2D> playerColliders = new HashSet<Collider2D>();
|
||
|
||
private float boundsMinX;
|
||
private float boundsMaxX;
|
||
|
||
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();
|
||
}
|
||
|
||
if (string.IsNullOrEmpty(playerTag)) playerTag = "Player";
|
||
|
||
var playerObj = GameObject.FindGameObjectWithTag(playerTag);
|
||
if (playerObj != null)
|
||
playerTransform = playerObj.transform;
|
||
}
|
||
|
||
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 playerX = playerPos.x;
|
||
float t = 0f;
|
||
if (!Mathf.Approximately(boundsMaxX, boundsMinX))
|
||
{
|
||
t = Mathf.InverseLerp(boundsMinX, boundsMaxX, playerX);
|
||
t = Mathf.Clamp01(t);
|
||
}
|
||
|
||
// Интерполируем интенсивность между startXIntensity и endXIntensity
|
||
float desiredForPosition = Mathf.Lerp(startXIntensity, endXIntensity, t);
|
||
|
||
for (int i = 0; i < lights.Length; i++)
|
||
{
|
||
var light2D = lights[i];
|
||
if (!light2D) continue;
|
||
|
||
if (smoothing <= 0f)
|
||
{
|
||
light2D.intensity = desiredForPosition;
|
||
}
|
||
else
|
||
{
|
||
light2D.intensity = Mathf.MoveTowards(light2D.intensity, desiredForPosition, 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);
|
||
|
||
// Не затираем playerTransform, оставляем ссылку (чтобы можно было продолжать вычисления при следующем входе).
|
||
// Если нужно — можно дополнительно реагировать на полное выход игрока (playerColliders.Count == 0).
|
||
}
|
||
|
||
private void UpdateBounds()
|
||
{
|
||
var b = targetCollider.bounds;
|
||
boundsMinX = b.min.x;
|
||
boundsMaxX = b.max.x;
|
||
}
|
||
|
||
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);
|
||
}
|
||
}
|
||
}
|