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