115 lines
4.5 KiB
C#
115 lines
4.5 KiB
C#
using System;
|
|
using System.Collections;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering.Universal;
|
|
using BaseGames.Core.Events;
|
|
|
|
namespace BaseGames.VFX
|
|
{
|
|
/// <summary>
|
|
/// 区域进出时平滑切换 Global Light 2D 颜色和强度。
|
|
/// 挂在 Persistent 场景 [Lighting] GameObject 上,监听 OnRegionEntered 事件频道。
|
|
/// </summary>
|
|
public class RegionLightController : MonoBehaviour
|
|
{
|
|
[SerializeField] private Light2D _globalLight;
|
|
[SerializeField] private RegionLightCatalogSO _catalog;
|
|
[SerializeField] private StringEventChannelSO _onRegionEntered;
|
|
[SerializeField] private float _transitionDuration = 1.5f;
|
|
|
|
private Coroutine _colorCoroutine;
|
|
private Coroutine _intensityCoroutine;
|
|
private readonly CompositeDisposable _subs = new();
|
|
|
|
private void Awake()
|
|
{
|
|
Debug.Assert(_catalog != null, "[RegionLightController] _catalog 未赋值,请在 Inspector 中指定 RegionLightCatalogSO。", this);
|
|
Debug.Assert(_globalLight != null, "[RegionLightController] _globalLight 未赋值,请在 Inspector 中绑定 Light2D。", this);
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
_onRegionEntered?.Subscribe(OnRegionEntered).AddTo(_subs);
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
_subs.Clear();
|
|
}
|
|
|
|
private void OnRegionEntered(string regionId)
|
|
{
|
|
if (!_catalog.TryGet(regionId, out var config)) return;
|
|
|
|
if (_colorCoroutine != null) StopCoroutine(_colorCoroutine);
|
|
if (_intensityCoroutine != null) StopCoroutine(_intensityCoroutine);
|
|
|
|
_colorCoroutine = StartCoroutine(TweenColor(_globalLight.color, config.Color, _transitionDuration));
|
|
_intensityCoroutine = StartCoroutine(TweenIntensity(_globalLight.intensity, config.Intensity, _transitionDuration));
|
|
}
|
|
|
|
// ── Coroutine helpers ────────────────────────────────────────────────────
|
|
private IEnumerator TweenColor(Color from, Color to, float duration)
|
|
{
|
|
float elapsed = 0f;
|
|
while (elapsed < duration)
|
|
{
|
|
elapsed += Time.deltaTime;
|
|
_globalLight.color = Color.Lerp(from, to, Mathf.Clamp01(elapsed / duration));
|
|
yield return null;
|
|
}
|
|
_globalLight.color = to;
|
|
_colorCoroutine = null;
|
|
}
|
|
|
|
private IEnumerator TweenIntensity(float from, float to, float duration)
|
|
{
|
|
float elapsed = 0f;
|
|
while (elapsed < duration)
|
|
{
|
|
elapsed += Time.deltaTime;
|
|
_globalLight.intensity = Mathf.Lerp(from, to, Mathf.Clamp01(elapsed / duration));
|
|
yield return null;
|
|
}
|
|
_globalLight.intensity = to;
|
|
_intensityCoroutine = null;
|
|
}
|
|
}
|
|
|
|
// ────────────────────────────────────────────────────────────────────────────
|
|
// RegionLightCatalogSO
|
|
// ────────────────────────────────────────────────────────────────────────────
|
|
|
|
/// <summary>
|
|
/// 区域 ID → Global Light 2D 颜色 + 强度映射表。
|
|
/// 资产路径:Assets/ScriptableObjects/VFX/VFX_RegionLightCatalog.asset
|
|
/// </summary>
|
|
[CreateAssetMenu(menuName = "BaseGames/VFX/RegionLightCatalog")]
|
|
public class RegionLightCatalogSO : ScriptableObject
|
|
{
|
|
[Serializable]
|
|
public struct RegionLightConfig
|
|
{
|
|
public string regionId;
|
|
public Color Color;
|
|
[Range(0f, 1f)] public float Intensity;
|
|
}
|
|
|
|
[SerializeField] private RegionLightConfig[] _entries;
|
|
|
|
/// <summary>根据 regionId 查找对应的灯光配置。</summary>
|
|
public bool TryGet(string regionId, out RegionLightConfig cfg)
|
|
{
|
|
if (_entries != null)
|
|
{
|
|
foreach (var e in _entries)
|
|
{
|
|
if (e.regionId == regionId) { cfg = e; return true; }
|
|
}
|
|
}
|
|
cfg = default;
|
|
return false;
|
|
}
|
|
}
|
|
}
|