UI系统优化

This commit is contained in:
2026-05-25 11:54:37 +08:00
parent c7057db27d
commit 3c812cfb41
130 changed files with 4738 additions and 477 deletions

View File

@@ -14,7 +14,8 @@
"BaseGames.Combat",
"BaseGames.Feedback",
"BaseGames.Skills",
"BaseGames.Core.Save"
"BaseGames.Core.Save",
"BaseGames.Localization"
],
"autoReferenced": true,
"overrideReferences": false,

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using UnityEngine;
using BaseGames.Localization;
namespace BaseGames.Equipment
{
@@ -8,7 +9,7 @@ namespace BaseGames.Equipment
/// 资产路径: Assets/ScriptableObjects/Equipment/Charms/Charm_{Name}.asset
/// </summary>
[CreateAssetMenu(menuName = "BaseGames/Equipment/Charm")]
public class CharmSO : ScriptableObject
public class CharmSO : ScriptableObject, ILocalizableAsset
{
[Header("Identity")]
public string charmId; // 全局唯一 ID如 "Charm_QuickSlash"
@@ -31,5 +32,13 @@ namespace BaseGames.Equipment
[Header("Lore")]
public bool isUnique;
public string unlockHint;
public IEnumerable<LocalizationKeyRef> GetLocalizationKeys()
{
if (!string.IsNullOrEmpty(displayNameKey))
yield return new LocalizationKeyRef(displayNameKey, "Items", nameof(displayNameKey));
if (!string.IsNullOrEmpty(descriptionKey))
yield return new LocalizationKeyRef(descriptionKey, "Items", nameof(descriptionKey));
}
}
}

View File

@@ -15,7 +15,7 @@ namespace BaseGames.Equipment
/// 挂在 Player 上,管理护符的装备/卸下及 Notch 容量。
/// 实现 ISaveable 以持久化装备状态。
/// </summary>
public class EquipmentManager : MonoBehaviour, ISaveable
public class EquipmentManager : MonoBehaviour, ISaveable, IEquipmentService
{
[Header("配置")]
[SerializeField] private EquipmentConfigSO _config;
@@ -40,12 +40,14 @@ namespace BaseGames.Equipment
// ── 生命周期 ──────────────────────────────────────────────────────────
private void OnEnable()
{
ServiceLocator.Register<IEquipmentService>(this);
ServiceLocator.GetOrDefault<ISaveableRegistry>()?.Register(this);
_onAchievementNotchGranted?.Subscribe(() => IncreaseNotches(1)).AddTo(_subs);
}
private void OnDisable()
{
ServiceLocator.Unregister<IEquipmentService>(this);
ServiceLocator.GetOrDefault<ISaveableRegistry>()?.Unregister(this);
_subs.Clear();
}

View File

@@ -0,0 +1,31 @@
using System.Collections.Generic;
namespace BaseGames.Equipment
{
/// <summary>
/// 装备管理服务接口。UI 层通过此接口读取护符状态并驱动装备操作,
/// 与 EquipmentManager 具体实现解耦,便于独立测试和跨场景复用。
/// </summary>
public interface IEquipmentService
{
/// <summary>已使用的 Notch 数量(缓存值,避免每帧 LINQ Sum。</summary>
int UsedNotches { get; }
/// <summary>Notch 总容量。</summary>
int TotalNotches { get; }
/// <summary>当前已装备护符列表(只读视图)。</summary>
IReadOnlyList<CharmSO> Equipped { get; }
/// <summary>已收集护符列表(只读视图)。</summary>
IReadOnlyList<CharmSO> Collected { get; }
/// <summary>
/// 装备护符。返回 null 表示成功;返回错误描述字符串表示失败原因。
/// </summary>
string TryEquipCharm(CharmSO charm);
/// <summary>卸下指定护符。</summary>
void UnequipCharm(CharmSO charm);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 475a394eced2eba46b59669695d20446
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,22 @@
namespace BaseGames.Equipment
{
/// <summary>
/// 工具槽查询接口(架构 09_ProgressionModule §7.5)。
/// UI 层通过 ServiceLocator.GetOrDefault&lt;IToolSlotService&gt;() 消费此接口,
/// 避免直接引用 ToolSlotManager 具体类型,保持 UI 与 Equipment 程序集的解耦。
/// </summary>
public interface IToolSlotService
{
/// <summary>返回指定槽位当前装备的 ToolSO槽位为空时返回 null。</summary>
ToolSO GetTool(int slotIndex);
/// <summary>返回指定槽位剩余使用次数;-1 表示无限次;槽位为空时返回 0。</summary>
int GetRemainingUses(int slotIndex);
/// <summary>
/// 返回指定槽位的冷却进度比例,范围 [0, 1]。
/// 0 = 不在冷却中可使用1 = 刚刚使用,冷却刚开始。
/// </summary>
float GetCooldownRatio(int slotIndex);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 28930e99c6de2674bb4f9bedb4a80d60
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using BaseGames.Player.States;
using BaseGames.Localization;
namespace BaseGames.Equipment
{
@@ -36,7 +38,7 @@ namespace BaseGames.Equipment
/// 资产路径: Assets/ScriptableObjects/Equipment/Tools/Tool_{Name}.asset
/// </summary>
[CreateAssetMenu(menuName = "BaseGames/Equipment/Tool")]
public class ToolSO : ScriptableObject
public class ToolSO : ScriptableObject, ILocalizableAsset
{
public string toolId;
public string displayNameKey;
@@ -46,6 +48,12 @@ namespace BaseGames.Equipment
public int maxUses = 1;
[SerializeReference]
public IToolEffect effect; // 工具使用效果(多态)
public IToolEffect effect;
public IEnumerable<LocalizationKeyRef> GetLocalizationKeys()
{
if (!string.IsNullOrEmpty(displayNameKey))
yield return new LocalizationKeyRef(displayNameKey, "Items", nameof(displayNameKey));
}
}
}

View File

@@ -11,7 +11,7 @@ namespace BaseGames.Equipment
/// 管理玩家的 2 个工具槽(装备、使用、冷却)。
/// 实现 ISaveable 以持久化槽位状态。
/// </summary>
public class ToolSlotManager : MonoBehaviour, ISaveable
public class ToolSlotManager : MonoBehaviour, ISaveable, IToolSlotService
{
private const int SlotCount = 2;
@@ -27,8 +27,17 @@ namespace BaseGames.Equipment
Debug.Assert(_toolCatalog != null, "[ToolSlotManager] _toolCatalog 未赋值,请在 Inspector 中指定 ToolCatalogSO。", this);
}
private void OnEnable() => ServiceLocator.GetOrDefault<ISaveableRegistry>()?.Register(this);
private void OnDisable() => ServiceLocator.GetOrDefault<ISaveableRegistry>()?.Unregister(this);
private void OnEnable()
{
ServiceLocator.GetOrDefault<ISaveableRegistry>()?.Register(this);
ServiceLocator.Register<IToolSlotService>(this);
}
private void OnDisable()
{
ServiceLocator.GetOrDefault<ISaveableRegistry>()?.Unregister(this);
ServiceLocator.Unregister<IToolSlotService>(this);
}
// ── 装备 ─────────────────────────────────────────────────────────────
public void EquipTool(int slotIndex, ToolSO tool)