多轮审查和修复
This commit is contained in:
135
Assets/Scripts/VFX/PostProcessManager.cs
Normal file
135
Assets/Scripts/VFX/PostProcessManager.cs
Normal file
@@ -0,0 +1,135 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user