682 lines
25 KiB
Markdown
682 lines
25 KiB
Markdown
# 17 · 装备系统(魅力/工具槽)
|
||
|
||
> **命名空间** `BaseGames.Equipment`
|
||
> **所属文档集** [← 返回索引](./README.md) · [总览](./00_Overview.md)
|
||
> **依赖** `BaseGames.Core.Events` · `BaseGames.Player`(PlayerStats)· `BaseGames.UI`
|
||
|
||
---
|
||
|
||
## 目录
|
||
|
||
1. [系统总览](#1-系统总览)
|
||
2. [CharmSO — 魅力数据](#2-charmso--魅力数据)
|
||
3. [ICharmEffect — 效果接口](#3-icharmeffect--效果接口)
|
||
4. [内置魅力效果实现](#4-内置魅力效果实现)
|
||
- [4.1 StatModifierEffect](#41-statmodifiereffect--属性加成)
|
||
- [4.2 AttackSpeedEffect](#42-attackspeedeffect--攻击速度加成)
|
||
- [4.3 OnHitEffect](#43-onhiteffect--命中触发效果)
|
||
- [4.4 SoulSpellEffect](#44-soulspelleffect--灵魂法术强化)
|
||
- [4.5 SkillNumericModifierEffect](#45-skillnumericmodifiereffect--技能数值修改)
|
||
- [4.6 SkillSlotOverrideEffect](#46-skillslotoverrideeffect--技能插槽替换)
|
||
- [4.7 WeaponOverrideEffect](#47-weaponoverrideeffect--武器替换)
|
||
5. [EquipmentManager — 槽位管理](#5-equipmentmanager--槽位管理)
|
||
6. [槽位系统与笔记(Notch)](#6-槽位系统与笔记notch)
|
||
7. [ToolSO — 主动工具](#7-toolso--主动工具)
|
||
8. [装备 UI](#8-装备-ui)
|
||
9. [SaveData 集成](#9-savedata-集成)
|
||
10. [事件频道](#10-事件频道)
|
||
11. [编辑器友好设计](#11-编辑器友好设计)
|
||
|
||
---
|
||
|
||
## 1. 系统总览
|
||
|
||
装备系统(Charm/Tool 系统)是银河恶魔城游戏元进度的核心:玩家在世界中收集魅力,在存档点装备,通过组合不同魅力改变战斗风格。对标游戏《丝之歌》中的 Threads 系统。
|
||
|
||
```
|
||
装备系统职责:
|
||
├─ CharmSO → 魅力数据 SO(效果、槽位占用、图标)
|
||
├─ ICharmEffect → 效果注入接口(无脚本级耦合,通过接口多态)
|
||
├─ EquipmentManager → 装备/卸下逻辑、槽位管理、装备状态查询
|
||
├─ ToolSO → 主动工具(有限使用次数的消耗品/无限技能)
|
||
└─ EquipmentUI → 装备槽 HUD、装备面板 UI、收集列表
|
||
```
|
||
|
||
**零耦合原则**:`EquipmentManager` 通过 SO 事件频道发布装备变更通知,`PlayerStats` 等订阅方自行响应;不持有 `PlayerController` 直接引用。
|
||
|
||
---
|
||
|
||
## 2. CharmSO — 魅力数据
|
||
|
||
```csharp
|
||
[CreateAssetMenu(menuName = "Equipment/Charm")]
|
||
public class CharmSO : ScriptableObject
|
||
{
|
||
[Header("基础信息")]
|
||
public string charmId; // 全局唯一 ID,如 "Charm_QuickSlash"
|
||
public string displayName; // 显示名称(本地化 key 或直接填写)
|
||
[TextArea(3, 6)]
|
||
public string description; // 描述文本
|
||
|
||
[Header("外观")]
|
||
public Sprite icon; // 魅力图标
|
||
public Color glowColor; // 魅力光晕颜色
|
||
|
||
[Header("槽位占用")]
|
||
[Range(1, 4)]
|
||
public int notchCost; // 占用的 Notch 数量(1~4)
|
||
|
||
[Header("效果")]
|
||
[SerializeReference] // 支持多态序列化
|
||
public List<ICharmEffect> effects; // 魅力效果列表(可叠加多个)
|
||
|
||
[Header("获得方式")]
|
||
public bool isUnique; // 唯一物品,只能携带一个
|
||
public string unlockHint; // 提示文本(从何处获得)
|
||
}
|
||
```
|
||
|
||
**资产存放路径**:`Assets/ScriptableObjects/Equipment/Charms/`
|
||
**命名规范**:`Charm_{Name}.asset`
|
||
|
||
---
|
||
|
||
## 3. ICharmEffect — 效果接口
|
||
|
||
```csharp
|
||
namespace BaseGames.Equipment
|
||
{
|
||
/// <summary>
|
||
/// 魅力效果接口。装备时 OnEquip,卸下时 OnUnequip。
|
||
/// 所有效果通过修改 PlayerStats 或注册事件监听来生效,不直接引用 PlayerController。
|
||
/// </summary>
|
||
[Serializable]
|
||
public interface ICharmEffect
|
||
{
|
||
void OnEquip(EquipmentContext ctx);
|
||
void OnUnequip(EquipmentContext ctx);
|
||
string GetEffectDescription(); // Inspector 与 UI Tooltip 显示
|
||
}
|
||
|
||
/// <summary>
|
||
/// 效果上下文(注入依赖,避免全局引用)
|
||
/// </summary>
|
||
public struct EquipmentContext
|
||
{
|
||
public PlayerStats Stats;
|
||
public PlayerFeedback Feedback;
|
||
public EventChannelRegistry Events; // SO 事件频道注册表
|
||
public SkillModifierRegistry SkillMods; // 技能修改器注册表(见 21_SpellSystem §5)
|
||
public WeaponManager WeaponMgr; // 武器切换管理器(见 53_WeaponSystem §3)
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 内置魅力效果实现
|
||
|
||
### 4.1 StatModifierEffect — 属性加成
|
||
|
||
```csharp
|
||
[Serializable]
|
||
public class StatModifierEffect : ICharmEffect
|
||
{
|
||
public StatType statType; // MaxHP / AttackDamage / MoveSpeed / JumpHeight / SoulGain
|
||
public float flatBonus; // 固定加成(如 +1 HP)
|
||
public float percentBonus;// 百分比加成(如 +20%)
|
||
|
||
public void OnEquip(EquipmentContext ctx)
|
||
=> ctx.Stats.AddModifier(statType, flatBonus, percentBonus);
|
||
|
||
public void OnUnequip(EquipmentContext ctx)
|
||
=> ctx.Stats.RemoveModifier(statType, flatBonus, percentBonus);
|
||
|
||
public string GetEffectDescription()
|
||
=> $"{statType}: {(flatBonus > 0 ? $"+{flatBonus}" : "")}" +
|
||
$"{(percentBonus > 0 ? $" +{percentBonus*100:0}%" : "")}";
|
||
}
|
||
```
|
||
|
||
**可加成属性列表**:
|
||
|
||
| StatType | 说明 | 示例魅力 |
|
||
|---------|------|---------|
|
||
| `MaxHP` | 最大生命值 | 强心魅(+2 HP)|
|
||
| `AttackDamage` | 攻击伤害 | 利刃魅(+15% 攻击)|
|
||
| `MoveSpeed` | 移动速度 | 疾步魅(+0.5 m/s)|
|
||
| `JumpHeight` | 跳跃高度 | 轻跃魅(+20%)|
|
||
| `SoulGain` | 每次命中获得 Soul | 汲魂魅(+5 Soul/hit)|
|
||
| `Defense` | 减少受到的伤害 | 护甲魅(+1 防御)|
|
||
|
||
### 4.2 AttackSpeedEffect — 攻击速度加成
|
||
|
||
```csharp
|
||
[Serializable]
|
||
public class AttackSpeedEffect : ICharmEffect
|
||
{
|
||
[Range(0.1f, 1.0f)]
|
||
public float speedMultiplier; // 动画速度倍率(如 1.3 = 加速 30%)
|
||
|
||
public void OnEquip(EquipmentContext ctx)
|
||
=> ctx.Stats.AnimatorSpeedMultiplier += (speedMultiplier - 1f);
|
||
|
||
public void OnUnequip(EquipmentContext ctx)
|
||
=> ctx.Stats.AnimatorSpeedMultiplier -= (speedMultiplier - 1f);
|
||
|
||
public string GetEffectDescription()
|
||
=> $"攻击速度 +{(speedMultiplier - 1) * 100:0}%";
|
||
}
|
||
```
|
||
|
||
### 4.3 OnHitEffect — 命中触发效果
|
||
|
||
```csharp
|
||
[Serializable]
|
||
public class OnHitEffect : ICharmEffect
|
||
{
|
||
public OnHitEffectType effectType; // ApplyPoison / ApplyFire / KnockbackBoost
|
||
[Range(0f, 1f)]
|
||
public float chance; // 触发概率(0~1)
|
||
|
||
DamageInfoEventChannelSO _onHitChannel;
|
||
|
||
public void OnEquip(EquipmentContext ctx)
|
||
{
|
||
_onHitChannel = ctx.Events.Get<DamageInfoEventChannelSO>("OnHitConfirmed");
|
||
_onHitChannel.OnEventRaised += HandleHit;
|
||
}
|
||
|
||
public void OnUnequip(EquipmentContext ctx)
|
||
=> _onHitChannel.OnEventRaised -= HandleHit;
|
||
|
||
void HandleHit(DamageInfo info)
|
||
{
|
||
if (Random.value > chance) return;
|
||
// 触发对应效果(由 StatusEffectManager 处理,见 04_CombatSystem §12)
|
||
}
|
||
|
||
public string GetEffectDescription()
|
||
=> $"命中时 {chance*100:0}% 概率附加 {effectType}";
|
||
}
|
||
```
|
||
|
||
### 4.4 SoulSpellEffect — 灵魂法术强化
|
||
|
||
```csharp
|
||
[Serializable]
|
||
public class SoulSpellEffect : ICharmEffect
|
||
{
|
||
public SpellType spellType; // SoulAttack / HealingWave(具体法术)
|
||
public int soulCostReduction; // 减少消耗 Soul 点数
|
||
|
||
public void OnEquip(EquipmentContext ctx)
|
||
=> ctx.Stats.RegisterSpellModifier(spellType, soulCostReduction, 0f);
|
||
|
||
public void OnUnequip(EquipmentContext ctx)
|
||
=> ctx.Stats.UnregisterSpellModifier(spellType, soulCostReduction, 0f);
|
||
|
||
public string GetEffectDescription()
|
||
=> $"{spellType} 消耗减少 {soulCostReduction} Soul";
|
||
}
|
||
```
|
||
|
||
### 4.5 SkillNumericModifierEffect — 技能数值修改
|
||
|
||
修改现有技能的伤害、范围、消耗、冷却和特效(不替换技能本身):
|
||
|
||
```csharp
|
||
[Serializable]
|
||
public class SkillNumericModifierEffect : ICharmEffect
|
||
{
|
||
[Tooltip("数值修改配置,可指定目标技能 ID / 资源类型 / 各倍率 / 特效覆盖")]
|
||
public SkillNumericModifier modifier;
|
||
|
||
public void OnEquip(EquipmentContext ctx) => ctx.SkillMods.AddNumericMod(modifier);
|
||
public void OnUnequip(EquipmentContext ctx) => ctx.SkillMods.RemoveNumericMod(modifier);
|
||
|
||
public string GetEffectDescription()
|
||
{
|
||
var parts = new System.Collections.Generic.List<string>();
|
||
if (!Mathf.Approximately(modifier.damageMult, 1f)) parts.Add($"伤害×{modifier.damageMult:0.##}");
|
||
if (!Mathf.Approximately(modifier.rangeMult, 1f)) parts.Add($"范围×{modifier.rangeMult:0.##}");
|
||
if (!Mathf.Approximately(modifier.costMult, 1f)) parts.Add($"消耗×{modifier.costMult:0.##}");
|
||
if (!Mathf.Approximately(modifier.cooldownMult, 1f)) parts.Add($"冷却×{modifier.cooldownMult:0.##}");
|
||
if (modifier.vfxOverride != null) parts.Add("特效替换");
|
||
if (modifier.animOverride != null) parts.Add("动画替换");
|
||
string target = string.IsNullOrEmpty(modifier.targetSkillId)
|
||
? "全部技能" : modifier.targetSkillId;
|
||
return $"{target}:{string.Join(" / ", parts)}";
|
||
}
|
||
}
|
||
```
|
||
|
||
**配置示例**:
|
||
|
||
```
|
||
// 范例护符:【裂空掌强化符】(+50% 伤害 / +30% 范围,仅对裂空掌)
|
||
modifier.targetSkillId = "sky_soul_skill"
|
||
modifier.damageMult = 1.5
|
||
modifier.rangeMult = 1.3
|
||
modifier.costMult = 1.0
|
||
modifier.cooldownMult = 1.0
|
||
|
||
// 范例护符:【魄元节笔】(所有魄技能消耗 -25%)
|
||
modifier.targetSkillId = "" // 留空 = 匹配所有
|
||
modifier.resourceFilter = SpiritOnly
|
||
modifier.costMult = 0.75
|
||
|
||
// 范例护符:【异形灵踪】(替换灵踪弹特效为火焰弹碗)
|
||
modifier.targetSkillId = "sky_spirit_skill2"
|
||
modifier.vfxOverride = FeedbackPreset_FireballVFX // 刹射物设计不变,只改特效
|
||
```
|
||
|
||
### 4.6 SkillSlotOverrideEffect — 技能插槽替换
|
||
|
||
将某形态某槽位的技能 SO **整体替换**为另一个 FormSkillSO:
|
||
|
||
```csharp
|
||
[Serializable]
|
||
public class SkillSlotOverrideEffect : ICharmEffect
|
||
{
|
||
[Tooltip("插槽替换配置:targetForm(null=全部形态)+ targetSlot + replacementSkill + priority")]
|
||
public SkillSlotOverride overrideData;
|
||
|
||
public void OnEquip(EquipmentContext ctx) => ctx.SkillMods.AddSlotOverride(overrideData);
|
||
public void OnUnequip(EquipmentContext ctx) => ctx.SkillMods.RemoveSlotOverride(overrideData);
|
||
|
||
public string GetEffectDescription()
|
||
{
|
||
string formStr = overrideData.targetForm != null
|
||
? overrideData.targetForm.name : "所有形态";
|
||
string skillName = overrideData.replacementSkill != null
|
||
? overrideData.replacementSkill.displayName : "null";
|
||
return $"{formStr}的 {overrideData.targetSlot} 替换为 [{skillName}]";
|
||
}
|
||
}
|
||
```
|
||
|
||
**配置示例**:
|
||
|
||
```
|
||
// 范例护符:【混元引导符】(天魂形态的魂技能替换为地行术)
|
||
overrideData.targetForm = FormSO_SkyForm
|
||
overrideData.targetSlot = SoulSkill
|
||
overrideData.replacementSkill = FormSkillSO_DiXingShu
|
||
overrideData.priority = 0
|
||
|
||
// 范例护符:【夜行者印记】(任意形态的魄技能2 替换为残阴术)
|
||
overrideData.targetForm = null // 全部形态均生效
|
||
overrideData.targetSlot = SpiritSkill2
|
||
overrideData.replacementSkill = FormSkillSO_CanYinShu
|
||
overrideData.priority = 1 // 高于其他护符,确保生效
|
||
```
|
||
|
||
**冲突解决规则**:
|
||
|
||
| 场景 | 结果 |
|
||
|------|---------|
|
||
| 两个护符替换同一槽位,`priority` 不同 | 高 `priority` 者生效 |
|
||
| 两个护符替换同一槽位,`priority` 相同 | 后装备的护符生效 |
|
||
| 一个替换全部形态,一个替换特定形态 | 特定形态的护符在该形态中优先(targetForm != null 得到额外 +1 优先加成,见 SkillModifierRegistry) |
|
||
|
||
---
|
||
|
||
### 4.7 WeaponOverrideEffect — 武器替换
|
||
|
||
将某形态(或所有形态)的默认武器整体替换为另一个 `WeaponSO`(见 [53_WeaponSystem §6](./53_WeaponSystem.md#6-护符武器覆盖weaponoverrideeffect)):
|
||
|
||
```csharp
|
||
[Serializable]
|
||
public class WeaponOverrideEffect : ICharmEffect
|
||
{
|
||
[Tooltip("目标形态 ID(留空 = 所有形态)")]
|
||
public string targetFormId;
|
||
|
||
[Tooltip("替换武器 SO")]
|
||
public WeaponSO replacementWeapon;
|
||
|
||
public void OnEquip(EquipmentContext ctx)
|
||
=> ctx.WeaponMgr.SetOverride(targetFormId, replacementWeapon);
|
||
|
||
public void OnUnequip(EquipmentContext ctx)
|
||
=> ctx.WeaponMgr.ClearOverride(targetFormId);
|
||
|
||
public string GetEffectDescription()
|
||
{
|
||
string formStr = string.IsNullOrEmpty(targetFormId) ? "所有形态" : targetFormId;
|
||
string wName = replacementWeapon != null ? replacementWeapon.displayName : "null";
|
||
return $"{formStr}的武器替换为 [{wName}]";
|
||
}
|
||
}
|
||
```
|
||
|
||
**配置示例**:
|
||
|
||
```
|
||
// 护符:【命魂刃灵符】(命魂形态改用高速短刃,4 Notch)
|
||
targetFormId = "LifeForm"
|
||
replacementWeapon = Weapon_ShadowDagger
|
||
|
||
// 护符:【混沌铸兵符】(所有形态均使用地魂锤,3 Notch)
|
||
targetFormId = "" // 空 = 全部形态
|
||
replacementWeapon = Weapon_EarthHammer
|
||
```
|
||
|
||
**冲突规则**:若多个护符同时覆盖同一形态武器,**后装备的护符生效**(`Dictionary` 键覆盖语义)。
|
||
|
||
---
|
||
|
||
## 5. EquipmentManager — 槽位管理
|
||
|
||
`EquipmentManager` 常驻 Player GameObject,管理装备状态。
|
||
|
||
```csharp
|
||
namespace BaseGames.Equipment
|
||
{
|
||
public class EquipmentManager : MonoBehaviour
|
||
{
|
||
[Header("配置")]
|
||
[SerializeField] EquipmentConfigSO _config; // 初始 Notch 数量等
|
||
|
||
[Header("事件频道")]
|
||
[SerializeField] CharmEventChannelSO _onCharmEquipped;
|
||
[SerializeField] CharmEventChannelSO _onCharmUnequipped;
|
||
[SerializeField] VoidEventChannelSO _onEquipmentChanged; // 总变更通知
|
||
|
||
// 运行时状态
|
||
readonly List<CharmSO> _collectedCharms = new(); // 已收集魅力库
|
||
readonly List<CharmSO> _equippedCharms = new(); // 当前装备的魅力
|
||
int _currentNotchCapacity; // 当前最大 Notch 数(会随升级增加)
|
||
int _usedNotches => _equippedCharms.Sum(c => c.notchCost);
|
||
|
||
EquipmentContext _ctx;
|
||
|
||
void Awake()
|
||
{
|
||
var stats = GetComponent<PlayerStats>();
|
||
var feedback = GetComponent<PlayerFeedback>();
|
||
_ctx = new EquipmentContext {
|
||
Stats = stats,
|
||
Feedback = feedback,
|
||
Events = EventChannelRegistry.Instance,
|
||
SkillMods = GetComponent<SkillModifierRegistry>(), // 同一 Player GO
|
||
WeaponMgr = GetComponent<WeaponManager>(), // 同一 Player GO
|
||
};
|
||
}
|
||
|
||
// ─────────────── 公开 API ───────────────
|
||
|
||
/// <summary>装备魅力。返回失败原因(null = 成功)</summary>
|
||
public string TryEquipCharm(CharmSO charm)
|
||
{
|
||
if (_equippedCharms.Contains(charm)) return "已经装备";
|
||
if (!_collectedCharms.Contains(charm)) return "尚未收集此魅力";
|
||
|
||
int newUsed = _usedNotches + charm.notchCost;
|
||
if (newUsed > _currentNotchCapacity)
|
||
return $"笔记不足(需要 {charm.notchCost},剩余 {_currentNotchCapacity - _usedNotches})";
|
||
|
||
_equippedCharms.Add(charm);
|
||
foreach (var effect in charm.effects)
|
||
effect.OnEquip(_ctx);
|
||
|
||
_onCharmEquipped.Raise(charm);
|
||
_onEquipmentChanged.Raise();
|
||
return null;
|
||
}
|
||
|
||
public void UnequipCharm(CharmSO charm)
|
||
{
|
||
if (!_equippedCharms.Remove(charm)) return;
|
||
foreach (var effect in charm.effects)
|
||
effect.OnUnequip(_ctx);
|
||
|
||
_onCharmUnequipped.Raise(charm);
|
||
_onEquipmentChanged.Raise();
|
||
}
|
||
|
||
public bool IsEquipped(CharmSO charm) => _equippedCharms.Contains(charm);
|
||
public bool IsCollected(CharmSO charm) => _collectedCharms.Contains(charm);
|
||
public int UsedNotches => _usedNotches;
|
||
public int NotchCapacity => _currentNotchCapacity;
|
||
public IReadOnlyList<CharmSO> EquippedCharms => _equippedCharms;
|
||
public IReadOnlyList<CharmSO> CollectedCharms => _collectedCharms;
|
||
|
||
// ─────────────── 存档集成 ───────────────
|
||
|
||
public void LoadFromSaveData(SaveData data)
|
||
{
|
||
_collectedCharms.Clear();
|
||
_equippedCharms.Clear();
|
||
|
||
// 卸下所有已装备效果(防止重复加载)
|
||
foreach (var c in _equippedCharms)
|
||
foreach (var e in c.effects)
|
||
e.OnUnequip(_ctx);
|
||
|
||
_currentNotchCapacity = data.equipment.notchCapacity;
|
||
|
||
foreach (var id in data.equipment.collectedCharms)
|
||
{
|
||
var charm = CharmDatabase.Instance.GetCharm(id);
|
||
if (charm != null) _collectedCharms.Add(charm);
|
||
}
|
||
|
||
foreach (var id in data.equipment.equippedCharms)
|
||
{
|
||
var charm = CharmDatabase.Instance.GetCharm(id);
|
||
if (charm != null) TryEquipCharm(charm);
|
||
}
|
||
}
|
||
|
||
public void WriteToSaveData(SaveData data)
|
||
{
|
||
data.equipment.notchCapacity = _currentNotchCapacity;
|
||
data.equipment.collectedCharms = _collectedCharms.Select(c => c.charmId).ToList();
|
||
data.equipment.equippedCharms = _equippedCharms.Select(c => c.charmId).ToList();
|
||
}
|
||
|
||
// ─────────────── Notch 升级 ───────────────
|
||
|
||
/// <summary>由 AbilityUnlock / 剧情事件调用,增加 Notch 容量</summary>
|
||
public void AddNotchCapacity(int amount)
|
||
{
|
||
_currentNotchCapacity += amount;
|
||
_onEquipmentChanged.Raise();
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 槽位系统与笔记(Notch)
|
||
|
||
《丝之歌》对标系统:**Notch(笔记)** 而非固定槽位数量。
|
||
|
||
```
|
||
初始 Notch 容量: 3
|
||
可通过以下途径升级:
|
||
├─ 购买特殊 NPC 服务: +1 Notch(每次 Geo 费用递增)
|
||
├─ 隐藏收集物 NotchShard(4 个合 1): +1 Notch
|
||
└─ 最大 Notch 容量: 11(可配置)
|
||
```
|
||
|
||
魅力的 Notch 消耗参考:
|
||
|
||
| 消耗 | 魅力类型示例 |
|
||
|------|------------|
|
||
| 1 Notch | 轻微属性加成(+MoveSpeed、+SoulGain)|
|
||
| 2 Notch | 中等效果(+攻击、命中触发)|
|
||
| 3 Notch | 强力被动(+2 HP、攻速大幅提升)|
|
||
| 4 Notch | 顶级魅力(改变游戏机制)|
|
||
|
||
---
|
||
|
||
## 7. ToolSO — 主动工具
|
||
|
||
主动工具(Tool)是有限使用次数的消耗品或无限施放的技能。
|
||
|
||
```csharp
|
||
[CreateAssetMenu(menuName = "Equipment/Tool")]
|
||
public class ToolSO : ScriptableObject
|
||
{
|
||
[Header("基础信息")]
|
||
public string toolId;
|
||
public string displayName;
|
||
[TextArea(2, 4)]
|
||
public string description;
|
||
public Sprite icon;
|
||
|
||
[Header("使用参数")]
|
||
public ToolType toolType; // Consumable / Skill / Throwable
|
||
public int maxCount; // 最大持有数量(-1 = 无限)
|
||
public int soulCost; // 使用消耗 Soul(0 = 无消耗)
|
||
public float cooldown; // 冷却时间(秒)
|
||
|
||
[Header("效果")]
|
||
[SerializeReference]
|
||
public IToolEffect effect; // 工具使用效果
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 8. 装备 UI
|
||
|
||
### 8.1 装备面板(全屏/暂停中打开)
|
||
|
||
```
|
||
Canvas_Pause
|
||
└── EquipmentPanel
|
||
├── LeftPanel — 魅力收集库
|
||
│ ├── CharmGrid (ScrollView,3列)
|
||
│ │ └── CharmItem(图标 + Notch 数量 + 状态:未收集/已收集/已装备)
|
||
│ └── SearchBar(可选,P2)
|
||
├── RightPanel — 装备槽
|
||
│ ├── NotchBar(可视化 Notch 容量条,已用/总量)
|
||
│ │ ├── NotchCell × N(已用=橙色,剩余=灰色)
|
||
│ │ └── CapacityText "4 / 8"
|
||
│ ├── EquippedSlots(已装备魅力列表,图标 + 卸下按钮)
|
||
│ └── OvercharmWarning(装备超过容量时显示 "过充咒(Overcharmed)" 警告,玩家受到双倍伤害)
|
||
└── BottomBar — 选中魅力详情
|
||
├── CharmIcon(大图)
|
||
├── CharmName + NotchCost
|
||
├── DescriptionText
|
||
├── EffectList(ICharmEffect.GetEffectDescription() 列表)
|
||
└── ActionButton(装备 / 卸下)
|
||
```
|
||
|
||
### 8.2 装备 HUD(游戏中快捷栏)
|
||
|
||
```
|
||
Canvas_HUD
|
||
└── ToolQuickbar (底部中央)
|
||
├── ToolSlot_1 (QuickSlot 1) — 绑定工具1图标 + 剩余数量
|
||
└── ToolSlot_2 (QuickSlot 2) — 绑定工具2图标 + 剩余数量
|
||
```
|
||
|
||
工具快捷栏在装备面板中可拖拽分配;快捷键:手柄 L1/R1,键盘 Q/E。
|
||
|
||
### 8.3 过充咒(Overcharmed)机制
|
||
|
||
参考《空洞骑士》Overcharmed:玩家强行装备超出 Notch 容量的魅力组合时,进入 Overcharmed 状态:
|
||
|
||
```csharp
|
||
// 在 EquipmentManager 中检测
|
||
bool IsOvercharmed => _usedNotches > _currentNotchCapacity;
|
||
|
||
// PlayerStats 订阅 _onEquipmentChanged
|
||
void HandleEquipmentChanged()
|
||
{
|
||
bool overcharmed = _equipmentManager.IsOvercharmed;
|
||
_damageTakenMultiplier = overcharmed ? 2.0f : 1.0f;
|
||
_overcharmedIndicator.SetActive(overcharmed);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 9. SaveData 集成
|
||
|
||
`SaveData` 新增 `equipment` 字段:
|
||
|
||
```json
|
||
{
|
||
"equipment": {
|
||
"notchCapacity": 5,
|
||
"collectedCharms": ["Charm_QuickSlash", "Charm_LifeBlood", "Charm_LongNail"],
|
||
"equippedCharms": ["Charm_QuickSlash", "Charm_LongNail"],
|
||
"quickTools": [
|
||
{ "toolId": "Tool_HealSeed", "count": 3 },
|
||
{ "toolId": null, "count": 0 }
|
||
],
|
||
"notchShardsCollected": 2
|
||
}
|
||
}
|
||
```
|
||
|
||
| 字段 | 说明 |
|
||
|------|------|
|
||
| `notchCapacity` | 当前 Notch 总容量 |
|
||
| `collectedCharms` | 已收集魅力 ID 列表 |
|
||
| `equippedCharms` | 当前装备魅力 ID 列表 |
|
||
| `quickTools` | 两个快捷工具槽(toolId + count)|
|
||
| `notchShardsCollected` | 已收集 Notch 碎片数量 |
|
||
|
||
---
|
||
|
||
## 10. 事件频道
|
||
|
||
| 频道资产 | 类型 | 发布方 | 主要订阅方 |
|
||
|---------|------|--------|----------|
|
||
| `OnCharmCollected.asset` | `CharmEventChannelSO` | `AbilityUnlock / Collectible` | `EquipmentManager`(添加到库)、`EquipmentUI`(刷新)|
|
||
| `OnCharmEquipped.asset` | `CharmEventChannelSO` | `EquipmentManager` | `PlayerStats`(通过效果已注入)、`HUD` |
|
||
| `OnCharmUnequipped.asset` | `CharmEventChannelSO` | `EquipmentManager` | `PlayerStats`、`HUD` |
|
||
| `OnEquipmentChanged.asset` | `VoidEventChannelSO` | `EquipmentManager` | `EquipmentUI`(刷新)、`PlayerStats`(Overcharmed 检测)|
|
||
| `OnNotchCapacityChanged.asset` | `IntEventChannelSO` | `EquipmentManager` | `EquipmentUI`(刷新 Notch 条)|
|
||
| `OnToolUsed.asset` | `ToolEventChannelSO` | `PlayerController` | `EquipmentManager`(扣减数量)、`HUD`(更新计数)|
|
||
|
||
---
|
||
|
||
## 11. 编辑器友好设计
|
||
|
||
### CharmSO 自定义 Inspector
|
||
|
||
```
|
||
┌─ Charm_QuickSlash ─────────────────────────────────────────┐
|
||
│ [图标预览] Quick Slash │
|
||
│ ID: Charm_QuickSlash Notch Cost: ██░░ 2 │
|
||
│ 描述: 大幅提升攻击速度 │
|
||
│ ───────────────────────────────────── │
|
||
│ 效果列表: │
|
||
│ [+] AttackSpeedEffect │
|
||
│ speedMultiplier: 1.35 → "攻击速度 +35%" │
|
||
│ ───────────────────────────────────── │
|
||
│ [+ 添加效果] [在游戏中预览] │
|
||
└────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
- `[SerializeReference]` 使效果列表在 Inspector 中以多态方式折叠展示
|
||
- 每个 `ICharmEffect` 实现类打上 `[Serializable]` 标签,自动出现在添加菜单
|
||
|
||
### EquipmentManager Scene Gizmo
|
||
|
||
- 在 Scene 视图中,玩家头顶显示已装备魅力的小图标(仅 Edit Mode 或暂停时显示),便于调试
|
||
|
||
### CharmDatabase EditorWindow
|
||
|
||
`Tools → Zeling → Charm Database`:
|
||
|
||
```
|
||
┌─ Charm Database ───────────────────────────────────────────┐
|
||
│ [自动扫描所有 CharmSO] 搜索: [____________] │
|
||
│ │
|
||
│ ID | Notch | 收集方式 | 效果数 │
|
||
│ Charm_QuickSlash | 2 | Forest_Cave_Boss | 1 │
|
||
│ Charm_LifeBlood | 2 | Purchase_Shop01 | 1 │
|
||
│ ... │
|
||
└────────────────────────────────────────────────────────────┘
|
||
```
|