using UnityEngine;
using Unheimlich.Features.Portals;
namespace Unheimlich.World.CameraSystem
{
///
/// Dynamically adjusts Unity's shadow rendering distance based on proximity to active portals.
/// When the player is near a portal with a loaded room, shadow distance is extended to ensure
/// shadows from the remote room are visible through the portal. This improves visual quality
/// while maintaining performance when far from portals.
///
public class DynamicShadowDistance : MonoBehaviour
{
private const float PORTAL_CHECK_DISTANCE = 100f;
[Header("Shadow Distance Settings")]
[SerializeField] private float _baseShadowDistance = 50f;
[SerializeField] private float _extendedShadowDistance = 250f;
[SerializeField] private float _transitionSpeed = 2f;
[Header("Detection")]
[SerializeField] private float _checkInterval = 0.5f;
private float _targetShadowDistance;
private float _currentShadowDistance;
private float _nextCheckTime;
private Transform _playerTransform;
private void Awake()
{
_playerTransform = Camera.main != null ? Camera.main.transform : null;
}
private void Start()
{
_currentShadowDistance = _baseShadowDistance;
_targetShadowDistance = _baseShadowDistance;
QualitySettings.shadowDistance = _baseShadowDistance;
}
private void Update()
{
if (Time.time >= _nextCheckTime)
{
_nextCheckTime = Time.time + _checkInterval;
UpdateTargetShadowDistance();
}
if (!Mathf.Approximately(_currentShadowDistance, _targetShadowDistance))
{
_currentShadowDistance = Mathf.Lerp(_currentShadowDistance, _targetShadowDistance, Time.deltaTime * _transitionSpeed);
QualitySettings.shadowDistance = _currentShadowDistance;
}
}
///
/// Checks if any active portal with a loaded room is within range.
/// If found, extends shadow distance to cover the remote room.
///
private void UpdateTargetShadowDistance()
{
bool needsExtendedDistance = false;
foreach (var portal in Portal.AllPortals)
{
if (portal == null || !portal.isActiveAndEnabled)
continue;
if (portal.LoadedRoomInstance != null)
{
float distanceToPortal = Vector3.Distance(_playerTransform.position, portal.transform.position);
if (distanceToPortal < PORTAL_CHECK_DISTANCE)
{
needsExtendedDistance = true;
break;
}
}
}
_targetShadowDistance = needsExtendedDistance ? _extendedShadowDistance : _baseShadowDistance;
}
private void OnValidate()
{
if (_baseShadowDistance < 0)
_baseShadowDistance = 0;
if (_extendedShadowDistance < _baseShadowDistance)
_extendedShadowDistance = _baseShadowDistance;
}
#if UNITY_EDITOR
private void OnDrawGizmosSelected()
{
if (_playerTransform == null)
return;
Gizmos.color = new Color(1f, 1f, 0f, 0.2f);
Gizmos.DrawWireSphere(_playerTransform.position, QualitySettings.shadowDistance);
UnityEditor.Handles.Label(_playerTransform.position + Vector3.up * 2,
$"Shadow Distance: {QualitySettings.shadowDistance:F0}");
}
#endif
}
}