Files
zeling_v2/Assets/_Game/Scripts/VFX/PostProcessManager.cs

136 lines
5.7 KiB
C#
Raw Permalink 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;
using UnityEngine;
using UnityEngine.Rendering;
using BaseGames.Core.Events;
namespace BaseGames.VFX
{
/// <summary>
/// 后处理 Volume 分区管理器,挂在 Persistent 场景 [PostProcess] GameObject 上。
/// 通过 Coroutine 平滑 blend Weight监听游戏状态/Boss/死亡/胜利事件。
/// 注意:水下后处理由 UnderwaterPostProcessingControllerWorld.Liquid独立负责此组件不处理。
/// </summary>
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;
/// <summary>调用 BlendCoroutine / ResetAllCoroutine 时复用的起始权重缓存,避免每次分配新数组。</summary>
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);
// ── 混合逻辑 ─────────────────────────────────────────────────────────────
/// <summary>将目标 Volume 权重渐变为 1其他管理中的 Volume 渐变为 0。</summary>
private void BlendTo(Volume target)
{
if (_blendCoroutine != null)
StopCoroutine(_blendCoroutine);
_blendCoroutine = StartCoroutine(BlendCoroutine(target, 1f));
}
/// <summary>所有受管 Volume 权重渐变回 0恢复默认后处理。</summary>
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;
}
}
}