Files
ichni_Official/Assets/Scripts/Game/Base/VFXObject.cs
SoulliesOfficial 9fd5f098ab 设置扩展
2026-07-19 16:44:58 -04:00

114 lines
4.2 KiB
C#
Raw 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.Generic;
using Sirenix.OdinInspector;
using SLSUtilities.LeanPoolAssistance;
using UnityEngine;
namespace Ichni
{
/// <summary>
/// 面向对象池特效的通用质量控制组件。
///
/// 挂载在由 LeanPool 生成与回收的 VFX 根节点上。每次 <see cref="OnSpawn"/> 时会先恢复受管理子对象的
/// Prefab 初始激活状态,再依据当前 <see cref="VfxQuality"/> 关闭非必要的视觉子树。
/// 设置切换仅影响之后新生成的 VFX不会中断正在播放的效果。
/// </summary>
public class VFXObject : PooledObject
{
[Title("VFX Quality")]
[Tooltip("Medium 与 Low 都会关闭的次要视觉子树。应放入高频、长寿命或大面积覆盖的装饰层。")]
public List<GameObject> disableAtMediumAndLower = new List<GameObject>();
[Tooltip("仅 Low 会额外关闭的视觉子树。Medium 仍保留这些效果以维持基本演出层次。")]
public List<GameObject> disableAtLowOnly = new List<GameObject>();
// 仅缓存两个质量列表中出现过的对象。没有被列出的子对象永远不受本组件控制。
private readonly Dictionary<GameObject, bool> originalActiveStates = new Dictionary<GameObject, bool>();
private bool qualityObjectsCached;
private void Awake()
{
CacheOriginalActiveStates();
}
/// <summary>
/// 对象从 LeanPool 取出时执行一次质量裁剪。
/// 先恢复原始状态可避免同一个对象先以 Low 生成、回收后再以 High 生成时仍错误保持隐藏。
/// </summary>
public override void OnSpawn()
{
// LeanPool 的 Broadcast IPoolable 模式或错误的重复通知不应重新裁剪一个已播放的效果。
if (spawnExecuted)
{
return;
}
CacheOriginalActiveStates();
RestoreOriginalActiveStates();
ApplyCurrentQuality();
base.OnSpawn();
}
/// <summary>
/// 读取生成瞬间的 VFX Quality 并关闭对应的完整视觉子树。
/// 未初始化 SettingsManager 的编辑器预览或独立加载流程默认使用 High保持作者配置的完整视觉。
/// </summary>
private void ApplyCurrentQuality()
{
VfxQuality currentQuality = SettingsManager.instance?.settingsSaveData?.vfxQuality ?? VfxQuality.High;
if (currentQuality <= VfxQuality.Medium)
{
SetObjectsActive(disableAtMediumAndLower, false);
}
if (currentQuality == VfxQuality.Low)
{
SetObjectsActive(disableAtLowOnly, false);
}
}
/// <summary>
/// 记录 Quality 列表对象在 Prefab 中的初始激活状态。
/// 这样即使某个对象本来就由作者设为 inactive也不会在下一次 Spawn 时被强制打开。
/// </summary>
private void CacheOriginalActiveStates()
{
if (qualityObjectsCached)
{
return;
}
CacheOriginalActiveStates(disableAtMediumAndLower);
CacheOriginalActiveStates(disableAtLowOnly);
qualityObjectsCached = true;
}
private void CacheOriginalActiveStates(List<GameObject> qualityObjects)
{
foreach (GameObject qualityObject in qualityObjects)
{
if (!originalActiveStates.ContainsKey(qualityObject))
{
originalActiveStates.Add(qualityObject, qualityObject.activeSelf);
}
}
}
private void RestoreOriginalActiveStates()
{
foreach (KeyValuePair<GameObject, bool> originalState in originalActiveStates)
{
originalState.Key.SetActive(originalState.Value);
}
}
private static void SetObjectsActive(List<GameObject> qualityObjects, bool isActive)
{
foreach (GameObject qualityObject in qualityObjects)
{
qualityObject.SetActive(isActive);
}
}
}
}