using System.Collections.Generic; using UnityEngine; namespace Architecture { /// /// 共享变量统一接口:所有 Variable 资产实现它,注册表才能统一重置。 /// public interface IVariable { void ResetToDefault(); } /// /// 共享变量注册表 —— 运行时状态防泄漏的核心。 /// /// 问题:ScriptableObject 资产在 Editor 下跨 Play Mode 域重载会持久化其序列化值。 /// 例如 PlayerHealth.Value 在游玩中变为 0 后退出 Play Mode,若残留为 0, /// 下次进入 Play Mode 可能直接触发死亡(或分数残留、开关状态错乱)。 /// /// 解决:每个 Variable 在 OnEnable 时自动注册;每次进入 Play Mode(域加载前) /// 由 [RuntimeInitializeOnLoadMethod] 统一调用 ResetToDefault(), /// 将运行时值恢复到设计器设置的 _defaultValue,杜绝跨局状态泄漏。 /// /// 注意:RuntimeInitializeLoadType.BeforeSceneLoad 在整个 Play Mode 生命周期内只触发一次, /// 因此同一局内跨场景加载(SceneManager.LoadScene)不会重置变量,分数等跨场景共享状态可正常保留。 /// public static class VariableRegistry { private static readonly HashSet _variables = new HashSet(); public static void Register(IVariable variable) { _variables.Add(variable); // 注册即重置:解决 [RuntimeInitializeOnLoadMethod(BeforeSceneLoad)] 在 SO 资产 // 尚未 OnEnable 注册前就执行 ResetAll(此时 _variables 为空)导致重置无效的问题。 // 无论 ResetAll 何时触发,变量在「上线」瞬间都会被恢复到 _defaultValue, // 杜绝退出 Play Mode 后 PlayerHealth 残留 0、再次进入直接触发死亡的跨局泄漏。 variable.ResetToDefault(); } public static void Unregister(IVariable variable) => _variables.Remove(variable); [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] public static void ResetAll() { foreach (var v in _variables) v.ResetToDefault(); } } }