136 lines
5.7 KiB
C#
136 lines
5.7 KiB
C#
using System.Collections;
|
||
using UnityEngine;
|
||
using UnityEngine.Rendering;
|
||
using BaseGames.Core.Events;
|
||
|
||
namespace BaseGames.VFX
|
||
{
|
||
/// <summary>
|
||
/// 后处理 Volume 分区管理器,挂在 Persistent 场景 [PostProcess] GameObject 上。
|
||
/// 通过 Coroutine 平滑 blend Weight,监听游戏状态/Boss/死亡/胜利事件。
|
||
/// 注意:水下后处理由 UnderwaterPostProcessingController(World.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;
|
||
}
|
||
}
|
||
}
|