This commit is contained in:
2026-07-07 03:34:56 +08:00
parent e7891d7e00
commit ecb20cf370
81 changed files with 2108 additions and 293 deletions
@@ -0,0 +1,49 @@
using UnityEngine;
using System;
namespace Architecture.Variables
{
/// <summary>
/// 共享布尔变量(ScriptableObject 资产)。常用于暂停、开关等状态。
/// </summary>
[CreateAssetMenu(menuName = "Architecture/Variables/Bool", fileName = "NewBoolVariable")]
public class BoolVariable : ScriptableObject, Architecture.IVariable
{
[SerializeField] private bool _value;
[Tooltip("进入 Play Mode 时的初始值,由 VariableRegistry 在每次启动游戏时自动恢复,防止跨局状态泄漏")]
[SerializeField] private bool _defaultValue;
public bool Value
{
get => _value;
set
{
if (_value == value) return;
_value = value;
OnValueChanged?.Invoke(value);
}
}
public event Action<bool> OnValueChanged;
public void SetValue(bool value) => Value = value;
/// <summary>将运行时值重置为 _defaultValue(每次进入 Play Mode 时由 VariableRegistry 自动调用)。</summary>
public void ResetToDefault()
{
_value = _defaultValue;
OnValueChanged?.Invoke(_value);
}
[ContextMenu("Reset To Default")]
public void Reset() => ResetToDefault();
private void OnEnable() => VariableRegistry.Register(this);
private void OnDisable()
{
VariableRegistry.Unregister(this);
OnValueChanged = null;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: DXsdsCquB3geiEyhIkY2aFLJpbGuThlr6ky9pgS1Nnrno7aw3ZWk4Uc=
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,52 @@
using UnityEngine;
using System;
namespace Architecture.Variables
{
/// <summary>
/// 共享浮点变量(ScriptableObject 资产)。
/// 任何系统可读取 / 写入,并由 OnValueChanged 事件驱动 UI 刷新,
/// 替代 MonoBehaviour 字段跨系统传递与逐帧反射读取。
/// </summary>
[CreateAssetMenu(menuName = "Architecture/Variables/Float", fileName = "NewFloatVariable")]
public class FloatVariable : ScriptableObject, Architecture.IVariable
{
[SerializeField] private float _value;
[Tooltip("进入 Play Mode 时的初始值,由 VariableRegistry 在每次启动游戏时自动恢复,防止跨局状态泄漏")]
[SerializeField] private float _defaultValue;
public float Value
{
get => _value;
set
{
if (Mathf.Approximately(_value, value)) return;
_value = value;
OnValueChanged?.Invoke(value);
}
}
public event Action<float> OnValueChanged;
public void SetValue(float value) => Value = value;
public void ApplyChange(float amount) => Value += amount;
/// <summary>将运行时值重置为 _defaultValue(每次进入 Play Mode 时由 VariableRegistry 自动调用)。</summary>
public void ResetToDefault()
{
_value = _defaultValue;
OnValueChanged?.Invoke(_value);
}
[ContextMenu("Reset To Default")]
public void Reset() => ResetToDefault();
private void OnEnable() => VariableRegistry.Register(this);
private void OnDisable()
{
VariableRegistry.Unregister(this);
OnValueChanged = null;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: DntJsS6uBnP85uXqLRZji/q5FaD10/2h7b+TePWWB+tWhBvOfF7TELg=
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,50 @@
using UnityEngine;
using System;
namespace Architecture.Variables
{
/// <summary>
/// 共享整数变量(ScriptableObject 资产)。常用于血量、得分、魂灵数等。
/// </summary>
[CreateAssetMenu(menuName = "Architecture/Variables/Int", fileName = "NewIntVariable")]
public class IntVariable : ScriptableObject, Architecture.IVariable
{
[SerializeField] private int _value;
[Tooltip("进入 Play Mode 时的初始值,由 VariableRegistry 在每次启动游戏时自动恢复,防止跨局状态泄漏")]
[SerializeField] private int _defaultValue;
public int Value
{
get => _value;
set
{
if (_value == value) return;
_value = value;
OnValueChanged?.Invoke(value);
}
}
public event Action<int> OnValueChanged;
public void SetValue(int value) => Value = value;
public void ApplyChange(int amount) => Value += amount;
/// <summary>将运行时值重置为 _defaultValue(每次进入 Play Mode 时由 VariableRegistry 自动调用)。</summary>
public void ResetToDefault()
{
_value = _defaultValue;
OnValueChanged?.Invoke(_value);
}
[ContextMenu("Reset To Default")]
public void Reset() => ResetToDefault();
private void OnEnable() => VariableRegistry.Register(this);
private void OnDisable()
{
VariableRegistry.Unregister(this);
OnValueChanged = null;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: W3octHuoWnnZAVrTuCOazcbeHxKYqo5abD3dZ/KJEBmkydHqGDyV9qE=
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,50 @@
using System.Collections.Generic;
using UnityEngine;
namespace Architecture
{
/// <summary>
/// 共享变量统一接口:所有 Variable 资产实现它,注册表才能统一重置。
/// </summary>
public interface IVariable
{
void ResetToDefault();
}
/// <summary>
/// 共享变量注册表 —— 运行时状态防泄漏的核心。
///
/// <b>问题</b>ScriptableObject 资产在 Editor 下跨 Play Mode 域重载会持久化其序列化值。
/// 例如 PlayerHealth.Value 在游玩中变为 0 后退出 Play Mode,若残留为 0,
/// 下次进入 Play Mode 可能直接触发死亡(或分数残留、开关状态错乱)。
///
/// <b>解决</b>:每个 Variable 在 OnEnable 时自动注册;每次进入 Play Mode(域加载前)
/// 由 [RuntimeInitializeOnLoadMethod] 统一调用 ResetToDefault()
/// 将运行时值恢复到设计器设置的 _defaultValue,杜绝跨局状态泄漏。
///
/// 注意:RuntimeInitializeLoadType.BeforeSceneLoad 在整个 Play Mode 生命周期内只触发一次,
/// 因此同一局内跨场景加载(SceneManager.LoadScene)不会重置变量,分数等跨场景共享状态可正常保留。
/// </summary>
public static class VariableRegistry
{
private static readonly HashSet<IVariable> _variables = new HashSet<IVariable>();
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();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: DHMdty+tWygUNpW3ZTnsgECvyUsf7TZS/Bowuhd8nTjV1gGiSvKO6z4=
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,48 @@
using UnityEngine;
using System;
namespace Architecture.Variables
{
/// <summary>
/// 共享 Vector3 变量(ScriptableObject 资产)。常用于位置、回声中心等。
/// </summary>
[CreateAssetMenu(menuName = "Architecture/Variables/Vector3", fileName = "NewVector3Variable")]
public class Vector3Variable : ScriptableObject, Architecture.IVariable
{
[SerializeField] private Vector3 _value;
[Tooltip("进入 Play Mode 时的初始值,由 VariableRegistry 在每次启动游戏时自动恢复,防止跨局状态泄漏")]
[SerializeField] private Vector3 _defaultValue;
public Vector3 Value
{
get => _value;
set
{
_value = value;
OnValueChanged?.Invoke(value);
}
}
public event Action<Vector3> OnValueChanged;
public void SetValue(Vector3 value) => Value = value;
/// <summary>将运行时值重置为 _defaultValue(每次进入 Play Mode 时由 VariableRegistry 自动调用)。</summary>
public void ResetToDefault()
{
_value = _defaultValue;
OnValueChanged?.Invoke(_value);
}
[ContextMenu("Reset To Default")]
public void Reset() => ResetToDefault();
private void OnEnable() => VariableRegistry.Register(this);
private void OnDisable()
{
VariableRegistry.Unregister(this);
OnValueChanged = null;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: BnIa4SyuVyiKWphMPOJ0zNHa5e8eoX06FNossjB+7+Ma8SaSRkVd14E=
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: