using System.Collections;
using UnityEngine;
using UnityEngine.Rendering;
using BaseGames.Core.Events;
namespace BaseGames.VFX
{
///
/// 后处理 Volume 分区管理器,挂在 Persistent 场景 [PostProcess] GameObject 上。
/// 通过 Coroutine 平滑 blend Weight,监听游戏状态/Boss/死亡/胜利事件。
/// 注意:水下后处理由 UnderwaterPostProcessingController(World.Liquid)独立负责,此组件不处理。
///
public class PostProcessManager : MonoBehaviour
{
[Header("Volume 引用(Persistent 场景内)")]
[SerializeField] private Volume _bossArenaVolume;
[SerializeField] private Volume _deathVolume;
[SerializeField] private Volume _victoryVolume;
[Header("事件频道")]
[SerializeField] private VoidEventChannelSO _onBossFightStarted;
[SerializeField] private VoidEventChannelSO _onBossFightEnded;
[SerializeField] private VoidEventChannelSO _onPlayerDied;
[SerializeField] private VoidEventChannelSO _onPlayerRespawned;
[SerializeField] private VoidEventChannelSO _onBossDefeated;
[SerializeField] private float _blendDuration = 0.4f;
private Volume[] _managedVolumes;
private Coroutine _blendCoroutine;
/// 调用 BlendCoroutine / ResetAllCoroutine 时复用的起始权重缓存,避免每次分配新数组。
private float[] _startWeights;
private readonly CompositeDisposable _subs = new();
private void Awake()
{
_managedVolumes = new[] { _bossArenaVolume, _deathVolume, _victoryVolume };
_startWeights = new float[_managedVolumes.Length];
}
private void OnEnable()
{
_onBossFightStarted?.Subscribe(HandleBossFightStarted).AddTo(_subs);
_onBossFightEnded?.Subscribe(HandleBossFightEnded).AddTo(_subs);
_onPlayerDied?.Subscribe(HandlePlayerDied).AddTo(_subs);
_onPlayerRespawned?.Subscribe(HandlePlayerRespawned).AddTo(_subs);
_onBossDefeated?.Subscribe(HandleBossDefeated).AddTo(_subs);
}
private void OnDisable()
{
_subs.Clear();
}
// ── 事件处理 ────────────────────────────────────────────────────────────
private void HandleBossFightStarted() => BlendTo(_bossArenaVolume);
private void HandleBossFightEnded() => ResetAll();
private void HandlePlayerDied() => BlendTo(_deathVolume);
private void HandlePlayerRespawned() => ResetAll();
private void HandleBossDefeated() => BlendTo(_victoryVolume);
// ── 混合逻辑 ─────────────────────────────────────────────────────────────
/// 将目标 Volume 权重渐变为 1,其他管理中的 Volume 渐变为 0。
private void BlendTo(Volume target)
{
if (_blendCoroutine != null)
StopCoroutine(_blendCoroutine);
_blendCoroutine = StartCoroutine(BlendCoroutine(target, 1f));
}
/// 所有受管 Volume 权重渐变回 0(恢复默认后处理)。
private void ResetAll()
{
if (_blendCoroutine != null)
StopCoroutine(_blendCoroutine);
_blendCoroutine = StartCoroutine(ResetAllCoroutine());
}
private IEnumerator BlendCoroutine(Volume target, float targetWeight)
{
float elapsed = 0f;
for (int i = 0; i < _managedVolumes.Length; i++)
_startWeights[i] = _managedVolumes[i] != null ? _managedVolumes[i].weight : 0f;
while (elapsed < _blendDuration)
{
elapsed += Time.unscaledDeltaTime;
float t = Mathf.Clamp01(elapsed / _blendDuration);
for (int i = 0; i < _managedVolumes.Length; i++)
{
if (_managedVolumes[i] == null) continue;
float dest = _managedVolumes[i] == target ? targetWeight : 0f;
_managedVolumes[i].weight = Mathf.Lerp(_startWeights[i], dest, t);
}
yield return null;
}
// 确保精确收敛
for (int i = 0; i < _managedVolumes.Length; i++)
{
if (_managedVolumes[i] == null) continue;
_managedVolumes[i].weight = _managedVolumes[i] == target ? targetWeight : 0f;
}
_blendCoroutine = null;
}
private IEnumerator ResetAllCoroutine()
{
float elapsed = 0f;
for (int i = 0; i < _managedVolumes.Length; i++)
_startWeights[i] = _managedVolumes[i] != null ? _managedVolumes[i].weight : 0f;
while (elapsed < _blendDuration)
{
elapsed += Time.unscaledDeltaTime;
float t = Mathf.Clamp01(elapsed / _blendDuration);
for (int i = 0; i < _managedVolumes.Length; i++)
{
if (_managedVolumes[i] == null) continue;
_managedVolumes[i].weight = Mathf.Lerp(_startWeights[i], 0f, t);
}
yield return null;
}
for (int i = 0; i < _managedVolumes.Length; i++)
{
if (_managedVolumes[i] != null)
_managedVolumes[i].weight = 0f;
}
_blendCoroutine = null;
}
}
}