Files
zeling_v2/Docs/Review/FrameworkReview_2026_May_v4.md
2026-05-12 15:34:08 +08:00

25 KiB
Raw Blame History

BaseGames 框架深度评审报告 — v42026-May

适用版本zeling_v2 · Unity 2022.3 LTS · C# 2D Action RPG
评审范围Assets/Scripts/ 全源码v1+v2+v3 所有 18 个问题均已修复后的净化状态)
前置文档v1 · v2 · v3(禁止反向修改)
评审原则:新框架不做兼容兜底,保持纯净、一致的数据逻辑


一、总体评分

维度 当前得分 v1 基准 提升
架构设计 ★★★★★ 9.5 7.0 +2.5
性能优化 ★★★★☆ 8.5 7.5 +1.0
可扩展性 ★★★★★ 9.5 8.0 +1.5
编辑器友好性 ★★★★★ 9.5 8.5 +1.0
使用便利性 ★★★★☆ 8.5 7.5 +1.0
综合 ★★★★★ 9.1 7.7 +1.4

二、架构设计 ★★★★★ 9.5

2.1 服务定位器ServiceLocator

文件:Assets/Scripts/Core/Events/ServiceLocator.cs

// 核心实现Dictionary<Type, object>O(1) 查找
private static readonly Dictionary<Type, object> _services = new();

// 安全版查找:不抛异常,适用于可选服务
public static TInterface GetOrDefault<TInterface>(TInterface fallback = default)
    => _services.TryGetValue(typeof(TInterface), out var svc) && svc is TInterface typed
       ? typed : fallback;

// 安全注销:仅当注册实例与 impl 一致时才移除,避免新实例被旧 OnDestroy 清除
public static void Unregister<TInterface>(TInterface impl)
{
    if (_services.TryGetValue(typeof(TInterface), out var svc) && ReferenceEquals(svc, impl))
        _services.Remove(typeof(TInterface));
}

亮点

  • 全接口键注册:经 v1v3 三轮修复,代码库中零个具体类型键注册。所有 25+ 服务均以接口类型注册(IAudioServiceISaveServiceIClashService等)
  • RegisterIfAbsent<T> 防止多场景重复注册NullAudioService 回退机制)
  • 安全 Unregister<T>(impl) 防止 OnDestroy 顺序问题导致后注册者被误删
  • #if UNITY_EDITOR 提供 OverrideForTest<T> / Reset() 专用测试钩子

服务注册总表v3 修复后)

接口键 注册方
IAudioService GameServiceRegistrarNull兜底→ AudioManager 覆盖
IDeathRespawnService GameServiceRegistrar
ISceneService GameServiceRegistrar
IEventChannelRegistry EventChannelRegistry
ISaveService GameServiceRegistrarvia SaveServiceAdapter
ISaveableRegistry SaveManager
ICameraService CameraStateController
IClashService ClashResolver
IDifficultyService DifficultyManager
IObjectPoolService GlobalObjectPool
IHitStopService HitStopManager
ILocalizationService LocalizationManagerMonoBehaviour 实例)
IMapService MapManager
IProjectileService ProjectileManager
IQuestManager QuestManager
ISettingsService SettingsManager
ITutorialService TutorialManager
IVFXPoolService VFXPool
IAchievementService AchievementManager
IAnalyticsService AnalyticsManager
IDialogueService DialogueManager
IPlatformService PlatformBootstrap

2.2 事件系统(双轨制,规则清晰)

轨道一SO 事件频道(跨系统广播)

// BaseEventChannelSO<T> — 核心实现
public EventSubscription Subscribe(Action<T> callback)
{
    OnEventRaised += callback;
    return new EventSubscription(() => OnEventRaised -= callback);
}

// 使用侧 (OnEnable / OnDisable RAII)
private void OnEnable()
    => _onDifficultyChanged?.Subscribe(HandleDifficultyChanged).AddTo(_subs);
private void OnDisable()
    => _subs.Clear();

轨道二C# native event (同一 MonoBehaviour 树内部)

// FormController 暴露给 WeaponManager同 Player Prefab 节点上)
public event Action OnFormChanged;

// WeaponManager
private void OnEnable()  => _formController.OnFormChanged += HandleFormChanged;
private void OnDisable() => _formController.OnFormChanged -= HandleFormChanged;

规则执行情况

  • SO 事件用于 Persistent 场景→Game 场景跨程序集广播
  • C# 事件仅限同一 Prefab 内部节点FormController→WeaponManagerWeaponManager→PlayerCombat
  • InputReaderSO C# 事件供所有需要输入的组件订阅SkillManager、ParrySystem 等)

Debug 支持

// BaseEventChannelSO.Raise() 在 UNITY_EDITOR 中自动记录到 EventBusMonitor
#if UNITY_EDITOR
EventBusMonitor.Record(name, value?.ToString() ?? "null", _subscriberCount, Time.frameCount);
#endif

2.3 存档系统

架构分层清晰,三层职责不重叠:

ISaveServiceCore 接口)
    └── SaveServiceAdapter桥接适配器位于 Core
            └── SaveManagerCore.Save 程序集ISaveable + ISaveableRegistry
                    └── ISaveStorage接口
                            └── LocalFileStorage写临时→原子替换 + .bak 恢复)

SaveData 结构 — 完整域覆盖 + 前向兼容:

public class SaveData
{
    [JsonExtensionData]
    public Dictionary<string, JToken> ExtensionData = new();  // 未知字段保留

    public SaveMeta             Meta;         // 版本、时间戳、HMAC、SteelSoul 标记
    public PlayerSaveData       Player;       // HP、形态、DeathShade、护盾
    public EquipmentSaveData    Equipment;    // 护符(已装备/已收集/已升级)
    public WorldSaveData        World;        // 访问场景、门、Boss、收集物
    public MapSaveData          Map;          // Pinsv2.1 新增)
    public QuestSaveData        Quests;
    public AchievementSaveData  Achievements;
    public EventChainsSaveData  EventChains;
    public ChallengeRoomsSaveData ChallengeRooms;
    public ShopsSaveData        Shops;
    public StatsSaveData        Stats;        // SpeedrunTimev2.1 新增)
    public NGPlusSaveData       NGPlus;       // null = 非 NG+ 模式
    public TutorialSaveData     Tutorial;
    public SettingsSaveData     Settings;
    public Dictionary<string, JObject> DLC;  // DLC/Mod 扩展槽
}

SaveMigrator — fall-through 链式迁移(当前版本 2.1

// 旧版本 → 2.0 → 2.1(每段落下执行)
if (IsOlderThan(v, "2.0")) { /* 补充 Tutorial/Settings/EventChains 等 */; v = "2.0"; }
if (v == "2.0")            { /* 补充 Map.Pins、Stats.SpeedrunTime */;       v = "2.1"; }

2.4 战斗管线8 步流水线)

HurtBox.ReceiveDamage() 严格按 8 步顺序执行:

1. 无敌帧检查IsInvincible || _isHurtBoxInvincible
2. 弹反窗口消耗ParrySystem.ConsumeParry()
3. 霸体检查PoiseLevel vs BreakLevel
4. 护盾层拦截IShieldable.AbsorbDamage()
5. 防御减免max(1, Amount - Defense)
6. 扣血IDamageable.TakeDamage(info)
7. 全局广播_onDamageDealt?.Raise / _onHitConfirmed?.Raise
8. 状态效果触发IStatusEffectable.ApplyStatusEffect()

DamageInfo Builder 模式实现零 GC 伤害数据构造:

var info = new DamageInfo.Builder()
    .SetRaw(20).SetType(DamageType.Physical)
    .SetKnockback(dir, 6f).SetBreak(BreakLevel.Light)
    .Build();

2.5 玩家 FSM非 MonoBehaviour 状态对象)

// PlayerStateBase — 基类
public abstract class PlayerStateBase
{
    protected PlayerController _owner;
    protected PlayerStateBase(PlayerController owner) => _owner = owner;

    public virtual void OnStateEnter()       { }
    public virtual void OnStateUpdate()      { }
    public virtual void OnStateFixedUpdate() { }
    public virtual void OnStateExit()        { }
    public virtual PlayerStateBase GetNextState() => null;
    public virtual bool IsInvincible => false;

#if UNITY_EDITOR
    public virtual IReadOnlyList<Type> ValidTransitions => Array.Empty<Type>();
#endif
    // 便捷属性Input / Buffer / Move / Stats / Anim / Cfg...
}

优势:状态对象不继承 MonoBehaviour → 无 GameObject 开销构造函数注入依赖Editor 可声明合法转换白名单。


2.6 程序集分层

28 个 .asmdef 程序集,依赖方向严格单向:

BaseGames.Core.Events ←── BaseGames.Core.Save ←── BaseGames.Core
        ↑                                               ↑
BaseGames.Combat ──────────────────────────────── BaseGames.Player
BaseGames.Enemies ──── BaseGames.Enemies.AI         BaseGames.Equipment
BaseGames.World ──────────────────────────────── BaseGames.World.Map
...(各业务程序集均向 Core 单向依赖,互不交叉)

autoReferenced: true 仅用于 BaseGames.CoreBaseGames.Core.Save,其余程序集需显式引用。


三、性能优化 ★★★★☆ 8.5

3.1 对象池

GlobalObjectPoolAddressables 驱动):

// 池数据结构
private readonly Dictionary<string, Queue<PooledObject>>      _pools;    // 空闲池
private readonly Dictionary<string, LinkedList<PooledObject>> _alive;    // 活跃追踪仅MaxCount>0时分配
private readonly Dictionary<string, GameObject>               _prefabCache;
private readonly Dictionary<string, int>                      _maxCounts;

// EnsureCollections按需分配 _alive避免无上限池的额外开销
if (_maxCounts.GetValueOrDefault(key, 0) > 0 && !_alive.ContainsKey(key))
    _alive[key] = new LinkedList<PooledObject>();

优点:无上限池(MaxCount = 0)不创建 _alive 链表,按需分配节省内存。

3.2 SkillManager 冷却遍历

// 固定大小数组快照Update 内零 GC 遍历
private FormSkillSO[] _activeSkills = Array.Empty<FormSkillSO>();

private void Update()
{
    for (int i = 0; i < _activeSkills.Length; i++)
    {
        var s = _activeSkills[i];
        if (_cooldowns.TryGetValue(s, out float cd) && cd > 0f)
            _cooldowns[s] = cd - Time.deltaTime;
    }
}

形态切换时重建快照(不超过 3 个技能),避免 List<T> 每帧 foreach 开销。

3.3 HitBox 命中去重

// 容量预设为 8避免触发扩容
private readonly HashSet<Collider2D> _hitThisActivation = new(8);
private readonly Dictionary<Collider2D, float> _hitCooldownTimers = new(8);

// OnTriggerExit2D 清理离场对象,防止持续激活时无限积累
private void OnTriggerExit2D(Collider2D other)
    => _hitCooldownTimers.Remove(other);

3.4 HurtBox 缓存

// Awake 中一次性缓存,避免受击时 GetComponent 查找
private IStatusEffectable _statusEffectable;

private void Awake()
{
    _owner = GetComponentInParent<IDamageable>();
    _statusEffectable = GetComponentInParent<IStatusEffectable>();
}

// 受击步骤 8
_statusEffectable?.ApplyStatusEffect(info.Type);

3.5 PlayerStats 数值修改器

// O(1) Dictionary 键值存取,无 LINQ 叠加计算
private readonly Dictionary<StatType, float> _flatModifiers    = new();
private readonly Dictionary<StatType, float> _percentModifiers = new();

⚠️ 性能注意点

[P-1] HitBox 物理回调中 ServiceLocator 查询未缓存

文件:Assets/Scripts/Combat/HitBox.cs

// 当前实现:每次 OnTriggerEnter2D 触发拼刀分支时调用
private void OnTriggerEnter2D(Collider2D other)
{
    // ... 前置条件判断 ...
    if (isRivalHitBoxLayer && CanClash)
    {
        var rivalHitBox = other.GetComponent<HitBox>();
        if (rivalHitBox != null && rivalHitBox.IsActive && rivalHitBox.CanClash)
        {
            ServiceLocator.GetOrDefault<IClashService>()?.ResolveClash(this, rivalHitBox); // ← 每次查
            return;
        }
    }
    // ...
}

ServiceLocator 本质是 Dictionary<Type, object>.TryGetValue,单次调用开销极小(约 1015 ns。但在密集战斗场景多敌人同帧触发拼刀建议在 Awake 中缓存:

// 建议改法
private IClashService _clashService;

private void Awake()
{
    // ...
    _clashService = ServiceLocator.GetOrDefault<IClashService>();
}

四、可扩展性 ★★★★★ 9.5

4.1 ScriptableObject 驱动设计

框架核心 SO 类型一览:

SO 类型 用途 可扩展点
CharmSO + ICharmEffect[] 护符效果插件化 新增护符无需改代码
FormSkillSO 形态技能配置 技能效果 SO 化
WeaponSO + DamageSourceSO 武器/伤害源 连招段 SO 化
DifficultyScalerSO 难度数值缩放器 新增难度档无需改枚举
FormConfigSO + FormSO 形态定义 新增形态修改 SO 即可
EnemyStatsSO 敌人基础属性 调参无需改代码
PoolConfig[] 对象池预热配置 Inspector 直接配置

4.2 ICharmEffect 策略模式

public interface ICharmEffect
{
    void OnEquip(EquipmentContext ctx);
    void OnUnequip(EquipmentContext ctx);
}

// 新增护符只需实现 ICharmEffect在 CharmSO.effects[] 中配置
// EquipmentContext 封装了 Stats / Feedback / Events / SkillMods / WeaponMgr

4.3 ISaveable + ISaveableRegistry

// 任何组件实现 ISaveable 即可参与存档
public interface ISaveable
{
    string SaveId { get; }
    void OnBeforeSave(SaveData data);
    void OnAfterLoad(SaveData data);
}

// SaveManager 实现 ISaveableRegistry统一管理所有 Saveable 组件
public interface ISaveableRegistry
{
    void Register(ISaveable saveable);
    void Unregister(ISaveable saveable);
}

当前实现了 ISaveable 的组件:PlayerStatsEquipmentManagerMapManagerAchievementManagerQuestManager 等,均通过接口均匀参与存档,无特殊耦合。

4.4 GameStateMachine 可插入状态

public class GameStateMachine
{
    private readonly Dictionary<GameStateId, IGameState> _states = new();

    public void Register(IGameState state) => _states[state.Id] = state;

    public bool TransitionTo(GameStateId nextId, out string error)
    {
        if (!_current.ValidNextStates.Contains(nextId))
        {
            error = $"非法转换 {_current.Id} → {nextId}";
            return false;
        }
        // ...
    }
}

新增游戏状态:实现 IGameState,调用 Register() 注入,无需修改状态机本体。

4.5 SaveData 前向兼容

[JsonExtensionData]
public Dictionary<string, JToken> ExtensionData = new();  // 未知字段保留,不丢失数据

public Dictionary<string, JObject> DLC = new();           // DLC/Mod 独立命名空间

保证未来 DLC 或 Mod 扩展的存档互操作不破坏主线存档结构。


五、编辑器友好性 ★★★★★ 9.5

5.1 Event Bus Monitor

文件:Assets/Scripts/Editor/EventBusMonitorWindow.cs

快捷键Ctrl+Shift+EBaseGames/Tools/Event Bus Monitor

功能:
- 实时捕获所有 BaseEventChannelSO.Raise() 调用
- 显示:频道名 · 负载值 · 订阅数 · 帧号
- Filter 文本框过滤频道
- Pause / Auto Scroll 控制
- Clear 一键清空

实现原理BaseEventChannelSO.Raise()#if UNITY_EDITOR 中调用 EventBusMonitor.Record()运行时零开销Editor 模式下完整记录。

5.2 Scene Scaffold Tools

文件:Assets/Scripts/Editor/SceneScaffoldTools.cs

BaseGames/Tools/Scaffold Persistent Scene

一键在当前场景中生成完整 Persistent 场景层级:

  • [Services]/GameServiceRegistrarDeathRespawnServiceSceneService
  • [Input]/InputReader
  • [Camera]/CameraStateController
  • [UI]/UIManagerHUDController

使用 GetOrAddComponent<T>() 幂等操作,重复执行不会重复创建组件。

5.3 其他 Editor 工具

工具 用途
EventChainEditorWindow 事件链可视化编辑
BossSkillSequenceWindow Boss 技能序列配置
AddressKeyValidator 验证 Addressables Key 是否存在
AddressReferenceGraphWindow 可视化 Addressables 引用依赖图
ScriptExecutionOrderTools 批量调整脚本执行顺序
NavSurfaceBakeShortcut PathBerserker2d 导航面快捷烘焙

5.4 运行时 Debug 支持

HurtBox GizmosEditor 模式下可视):

#if UNITY_EDITOR
private void OnDrawGizmos()
{
    Gizmos.color = (_isActive && !_isHurtBoxInvincible)
        ? new Color(1f, 0f, 0f, 0.45f)   // 激活:红色半透明填充
        : new Color(1f, 0f, 0f, 0.1f);   // 无敌/非激活:极淡
    Gizmos.DrawCube(col.bounds.center, col.bounds.size);
    Gizmos.DrawWireCube(col.bounds.center, col.bounds.size);
}
#endif

HurtBox Editor 只读属性Inspector 调试用,避免反射):

#if UNITY_EDITOR
public object EditorOwner            => _owner;
public object EditorParrySystem      => _parrySystem;
public object EditorStatusEffectable => _statusEffectable;
// ...
#endif

Debug.Assert 在 AwakeInspector 漏配置立即报错,不等运行中崩溃):

Debug.Assert(_config != null, "[PlayerStats] _config 未赋值", this);
Debug.Assert(_ctx.Stats != null, "[EquipmentManager] 缺少 PlayerStats", this);

六、使用便利性 ★★★★☆ 8.5

6.1 统一服务访问模式

// 标准模式:可选服务 → GetOrDefault不抛异常
var audio = ServiceLocator.GetOrDefault<IAudioService>();
audio?.PlaySFX(clipId);

// 必须服务 → Get不存在时抛出清晰错误
var scene = ServiceLocator.Get<ISceneService>();

6.2 RAII 事件订阅模式

private readonly CompositeDisposable _subs = new();

private void OnEnable()
{
    _onGameStateChanged?.Subscribe(HandleGameStateChanged).AddTo(_subs);
    _onPauseRequested?.Subscribe(TogglePause).AddTo(_subs);
}
private void OnDisable() => _subs.Clear();

覆盖率:代码库中所有跨场景 SO 事件订阅 100% 使用此模式。未发现遗漏。

6.3 DamageInfo Builder

var info = new DamageInfo.Builder()
    .SetRaw(damage)
    .SetType(DamageType.Physical)
    .SetKnockback(knockDir, 5f)
    .SetFlags(DamageFlags.CanBeParried | DamageFlags.CanClash)
    .SetBreak(BreakLevel.Light)
    .SetFx(HitFxType.Spark)
    .Build();

6.4 PlayerStateBase 便捷属性

protected InputReaderSO       Input   => _owner.Input;
protected InputBuffer         Buffer  => _owner.Buffer;
protected PlayerMovement      Move    => _owner.Movement;
protected PlayerStats         Stats   => _owner.Stats;
protected AnimancerComponent  Anim    => _owner.Animancer;
protected PlayerMovementConfigSO Cfg  => _owner.MovConfig;

每个状态子类无需重复持有引用,直接通过属性访问 Owner 依赖。

6.5 Inspector 零依赖接线

所有跨 GameObject 依赖均通过 [SerializeField] 在 Inspector 中绑定,无场景内 Find、无 GetComponent 跨层扫描。GameObject 树内部的兄弟组件依赖通过 GetComponent<T>()/GetComponentInParent<T>() 在 Awake 中就地获取。


七、新问题清单v4 首次发现)

以下问题为本轮评审首次发现v1v3 中未涉及。

ID 严重级别 文件 问题描述
C-1 ⚠️ 轻微 Combat/HitBox.cs OnTriggerEnter2DServiceLocator.GetOrDefault<IClashService>() 未缓存
C-2 待办 Player/SpringSystem.cs 空桩实现,核心治愈机制未完成
C-3 观察 Core/Save/LocalFileStorage.cs GetExistingSlots() 硬编码槽位上限为 3
C-4 观察 Core/Events/ServiceLocator.cs 文件位于 Events/ 子目录但命名空间为 BaseGames.Core,位置与职责不符

C-1 详述HitBox.OnTriggerEnter2D 服务查询未缓存

现状

// Assets/Scripts/Combat/HitBox.cs — OnTriggerEnter2D
ServiceLocator.GetOrDefault<IClashService>()?.ResolveClash(this, rivalHitBox);

影响:单次调用代价仅为 Dictionary<Type,object>.TryGetValue(约 1020 ns正常战斗中不会产生可测量帧率影响。但在密集多敌人战斗同帧多个 HitBox 触发拼刀)场景下,集中调用量可积累。

建议改法

private IClashService _clashService;

private void Awake()
{
    var col = GetComponent<Collider2D>();
    if (!col.isTrigger) Debug.LogWarning(...);
    _clashService = ServiceLocator.GetOrDefault<IClashService>();
}

C-2 详述SpringSystem 空桩实现

现状

// Assets/Scripts/Player/SpringSystem.cs
public class SpringSystem : MonoBehaviour { }

治愈弹簧系统PlayerStats 中 CurrentSpringChargesMaxSpringChargesSpringKillPoints 字段已预留)是明确的框架设计规划功能,当前仅有骨架。

建议:在 SpringSystem.cs 中添加 // TODO: 注释说明预期接口契约,防止其他开发者误以为该组件已实现。


C-3 详述:存档槽位数硬编码

现状

// Assets/Scripts/Core/Save/LocalFileStorage.cs
public IEnumerable<int> GetExistingSlots()
{
    for (int i = 0; i < 3; i++)   // ← 硬编码 3 槽
        if (Exists(i)) yield return i;
}

影响:极低。如需扩展为 5 存档槽,需同步修改此处与 UI SaveSlotPanel。由于 ISaveStorage 接口的此方法已封装变化点,改动范围可控。

建议:将槽位数提取为 LocalFileStorage(int maxSlots = 3) 构造参数,或在 SaveConfig SO 中配置。


C-4 详述ServiceLocator 文件位置不符命名空间

现状

  • 文件路径:Assets/Scripts/Core/Events/ServiceLocator.cs
  • 命名空间:namespace BaseGames.Core BaseGames.Core.Events

ServiceLocator 是 Core 层的基础设施,与事件系统无关。放置于 Events/ 子目录会造成新开发者困惑(以为它属于事件模块)。

建议:移动到 Assets/Scripts/Core/ServiceLocator.cs(命名空间不变)。


八、已确认的优秀实践清单

以下模式在整个代码库中一致使用,代表本框架的核心设计规范:

# 模式 体现文件
1 Subscribe().AddTo(_subs) RAII 所有 OnEnable/OnDisable 组件
2 [SerializeField] Inspector 注入,零 Find/FindWithTag 全代码库
3 ServiceLocator.GetOrDefault<IXxx>() 可选服务访问 所有服务消费方
4 Debug.Assert() Awake 配置验证 PlayerStats, EquipmentManager 等
5 DamageInfo.Builder 零 GC 伤害构造 所有 HitBox 创建伤害处
6 8 步 HurtBox 伤害流水线 HurtBox.ReceiveDamage()
7 非 MonoBehaviour 状态对象 PlayerStateBase 子类
8 #if UNITY_EDITOR Gizmos + 只读属性 HurtBox, HitBox
9 GameStateMachine.ValidNextStates 合法转换卫士 GameStateMachine
10 SaveMigrator fall-through 链式迁移 SaveMigrator.Migrate()
11 LocalFileStorage 原子写+.bak 恢复 LocalFileStorage.WriteAsync()
12 ICharmEffect 策略模式护符效果 CharmSO.effects[]
13 JsonExtensionData 未知字段保留 SaveData
14 EnsureCollections 按需分配 LinkedList GlobalObjectPool
15 RegisterIfAbsent<T> 防重注册 + NullObject 服务 GameServiceRegistrar

九、综合结论

经过 v1 至 v3 三轮系统性修复(共 18 个问题BaseGames 框架已达到商业级独立游戏框架的成熟度。

最突出的架构成就

  1. 服务定位器 100% 接口键无任何具体类型泄漏依赖倒置执行彻底。任何服务实现均可在不改调用方的前提下替换A/B 测试、平台适配、Mock 测试均轻松支持)。

  2. 双轨事件系统,规则清晰SO 事件频道处理跨场景/跨程序集广播C# native event 处理同 Prefab 内部通信,规则文档化且全代码库一致执行。

  3. 存档系统工业级健壮原子写防断电损坏、HMAC-SHA256 防篡改、JsonExtensionData 前向兼容、链式迁移器、全接口分层——任何一项单独拿出来都是商业项目的标准实现。

  4. Editor 工具链完整Event Bus Monitor、Scene Scaffold、Boss 序列编辑器、Addressables 验证器构成了完整的开发效率工具链,是框架成熟度的直接体现。

遗留的 4 个小问题(全部为轻微/观察级):

  • C-1HitBox 中 IClashService 建议缓存30 行改动)
  • C-2SpringSystem 待实现(待办,非 Bug
  • C-3存档槽位数可配置化低优先级
  • C-4ServiceLocator 文件位置建议整理(不影响功能)

最终定性:该框架设计理念清晰、执行纪律严格、扩展接口完善,可作为同类 2D Action RPG 项目的参考级架构蓝本。


文档生成日期2026 年 5 月 | 审阅人GitHub Copilot | 代码状态零编译错误get_errors() 已验证)