NLDClient-yudde/ProjectNLD/Assets/Code/Scripts/Framework/Render/FlashEffectStarter.cs

302 lines
9.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using UnityEngine;
using Framework;
public class FlashEffectStarter : MonoBehaviour
{
[Header("设置")]
[Tooltip("是否在OnEnable时自动设置StartTime")]
public bool autoSetOnEnable = true;
[Tooltip("使用 MaterialPropertyBlock推荐支持GPU Instancing还是Material实例")]
public bool usePropertyBlock = true;
[Tooltip("是否也处理子对象的Renderer")]
public bool includeChildren = false;
[Tooltip("是否响应战斗暂停状态")]
public bool respondToFightPause = true;
[Header("效果设置")]
[Tooltip("延迟时间效果会在SetStartTime后延迟这个时间再开始播放")]
public float delay = 0.1f;
private static readonly int StartTimePropertyID = Shader.PropertyToID("_StartTime");
private static readonly int DelayPropertyID = Shader.PropertyToID("_Delay");
private static readonly int PausedPropertyID = Shader.PropertyToID("_Paused");
private static readonly int GameTimePropertyID = Shader.PropertyToID("_GameTime");
private static readonly int GameTimeInitializedPropertyID = Shader.PropertyToID("_GameTimeInitialized");
private static FlashEffectStarter _activeInstance;
private static bool _isFightPaused = false;
private static float _pausedGameTime = 0f;
private MaterialPropertyBlock _propertyBlock;
private Renderer[] _renderers;
// 缓存委托,避免每次注册/注销时创建新委托产生 GC
private System.Action<bool> _onFightPauseChangedDelegate;
private System.Action _onFightPauseChangedNoParamDelegate;
private void Awake()
{
if (usePropertyBlock)
{
_propertyBlock = new MaterialPropertyBlock();
}
if (includeChildren)
{
_renderers = GetComponentsInChildren<Renderer>(true);
}
else
{
var renderer = GetComponent<Renderer>();
_renderers = renderer != null ? new[] { renderer } : new Renderer[0];
}
// 初始化缓存的委托
_onFightPauseChangedDelegate = OnFightPauseChanged;
_onFightPauseChangedNoParamDelegate = OnFightPauseChangedNoParam;
}
private void OnEnable()
{
if (autoSetOnEnable)
{
SetStartTime();
}
// 设置延迟
SetDelay(delay);
// 更新暂停状态
UpdatePausedState();
// 注册为活动实例,负责更新全局时间
if (_activeInstance == null)
{
_activeInstance = this;
}
// 注册战斗暂停事件监听
if (respondToFightPause)
{
EventManager.Instance.Register<bool>(EventManager.EventName.INFIGHT_PAUSE_CHANGED, _onFightPauseChangedDelegate);
EventManager.Instance.Register(EventManager.EventName.INFIGHT_PAUSE_CHANGED, _onFightPauseChangedNoParamDelegate);
}
}
private void OnDisable()
{
// 如果当前实例是活动实例,清除引用
if (_activeInstance == this)
{
_activeInstance = null;
}
// 注销战斗暂停事件监听
if (respondToFightPause)
{
EventManager.Instance.Unregister<bool>(EventManager.EventName.INFIGHT_PAUSE_CHANGED, _onFightPauseChangedDelegate);
EventManager.Instance.Unregister(EventManager.EventName.INFIGHT_PAUSE_CHANGED, _onFightPauseChangedNoParamDelegate);
}
}
private void Update()
{
// 更新暂停状态
UpdatePausedState();
// 只有活动实例才更新全局游戏时间,避免重复更新
if (_activeInstance == this)
{
// 检查暂停状态:优先使用事件状态,如果没有响应事件则检查 Time.timeScale
bool isPaused;
if (respondToFightPause)
{
isPaused = _isFightPaused;
}
else
{
// 如果不响应事件,直接检查 Time.timeScale
bool currentPaused = Time.timeScale == 0f;
if (currentPaused && !_isFightPaused)
{
// 刚刚进入暂停状态,记录当前时间
_pausedGameTime = Time.time;
}
_isFightPaused = currentPaused;
isPaused = currentPaused;
}
// 如果战斗暂停,使用暂停时的时间,否则使用当前时间
float gameTime = isPaused ? _pausedGameTime : Time.time;
Shader.SetGlobalFloat(GameTimePropertyID, gameTime);
// 标记 _GameTime 已初始化
Shader.SetGlobalFloat(GameTimeInitializedPropertyID, 1.0f);
}
}
/// <summary>
/// 战斗暂停状态改变回调带bool参数
/// </summary>
private void OnFightPauseChanged(bool isPaused)
{
_isFightPaused = isPaused;
if (isPaused)
{
// 暂停时记录当前时间
_pausedGameTime = Time.time;
Debug.Log($"[FlashEffectStarter] 战斗暂停,记录时间: {_pausedGameTime}");
}
else
{
Debug.Log($"[FlashEffectStarter] 战斗恢复");
}
UpdatePausedState();
}
/// <summary>
/// 战斗暂停状态改变回调(无参数,通过其他方式判断暂停状态)
/// </summary>
private void OnFightPauseChangedNoParam()
{
// 如果没有参数,通过 Time.timeScale 来判断
bool wasPaused = _isFightPaused;
_isFightPaused = Time.timeScale == 0f;
if (_isFightPaused && !wasPaused)
{
// 刚刚进入暂停状态,记录当前时间
_pausedGameTime = Time.time;
Debug.Log($"[FlashEffectStarter] 战斗暂停(无参数事件),记录时间: {_pausedGameTime}");
}
else if (!_isFightPaused && wasPaused)
{
Debug.Log($"[FlashEffectStarter] 战斗恢复(无参数事件)");
}
UpdatePausedState();
}
public void SetStartTime()
{
SetStartTime(Time.time);
}
public void SetStartTime(float startTime)
{
foreach (var renderer in _renderers)
{
if (renderer == null) continue;
if (usePropertyBlock)
{
renderer.GetPropertyBlock(_propertyBlock);
_propertyBlock.SetFloat(StartTimePropertyID, startTime);
renderer.SetPropertyBlock(_propertyBlock);
}
else
{
renderer.material.SetFloat(StartTimePropertyID, startTime);
}
}
}
public void ResetAnimation()
{
SetStartTime(0f);
}
public void RestartAnimation()
{
SetStartTime(Time.time);
}
/// <summary>
/// 设置延迟时间
/// </summary>
public void SetDelay(float delayValue)
{
delay = delayValue;
foreach (var renderer in _renderers)
{
if (renderer == null) continue;
if (usePropertyBlock)
{
renderer.GetPropertyBlock(_propertyBlock);
_propertyBlock.SetFloat(DelayPropertyID, delayValue);
renderer.SetPropertyBlock(_propertyBlock);
}
else
{
renderer.material.SetFloat(DelayPropertyID, delayValue);
}
}
}
/// <summary>
/// 更新暂停状态到shader
/// </summary>
private void UpdatePausedState()
{
bool isPaused;
if (respondToFightPause)
{
isPaused = _isFightPaused;
}
else
{
isPaused = Time.timeScale == 0f;
}
float pausedValue = isPaused ? 1.0f : 0.0f;
foreach (var renderer in _renderers)
{
if (renderer == null) continue;
if (usePropertyBlock)
{
renderer.GetPropertyBlock(_propertyBlock);
_propertyBlock.SetFloat(PausedPropertyID, pausedValue);
renderer.SetPropertyBlock(_propertyBlock);
}
else
{
renderer.material.SetFloat(PausedPropertyID, pausedValue);
}
}
}
#if UNITY_EDITOR
[ContextMenu("设置StartTime为当前时间")]
private void EditorSetStartTime()
{
if (Application.isPlaying)
{
SetStartTime();
Debug.Log($"已设置 {gameObject.name} 的StartTime为 {Time.time}");
}
else
{
Debug.LogWarning("请在运行时执行此操作");
}
}
[ContextMenu("重置StartTime为0")]
private void EditorResetStartTime()
{
if (Application.isPlaying)
{
ResetAnimation();
Debug.Log($"已重置 {gameObject.name} 的StartTime为0");
}
else
{
Debug.LogWarning("请在运行时执行此操作");
}
}
#endif
}