using UnityEngine; using BaseGames.Player; using BaseGames.Input; using BaseGames.Feedback; namespace BaseGames.Spells { /// /// 法术管理器(架构 BaseGames.Spells)。 /// 挂在 Player 上,管理已装备法术的施放、冷却与资源消耗。 /// 装备/卸下法术通过 EquipSpell / UnequipSpell 公共 API 完成(如护符系统调用)。 /// /// 输入事件:订阅 InputReaderSO.SpellCastEvent(对应 InputActionAsset 中的 "Spell" Action)。 /// public class SpellManager : MonoBehaviour { [Header("依赖引用")] [SerializeField] private PlayerStats _stats; [SerializeField] private InputReaderSO _input; [Header("法术挂载点")] [Tooltip("法术 HitBox / 投射物的生成位置")] [SerializeField] private Transform _spellSocket; // 当前装备的法术(单槽;如需多槽可扩展为数组) private SpellSO _equippedSpell; private float _cooldownRemaining; private IFeedbackPlayer _feedback; // ── 生命周期 ────────────────────────────────────────────────────────── private void Awake() { _feedback = GetComponentInChildren() ?? GetComponentInParent() ?? NullFeedbackPlayer.Instance; } private void OnEnable() { if (_input != null) _input.SpellCastEvent += TryCastSpell; } private void OnDisable() { if (_input != null) _input.SpellCastEvent -= TryCastSpell; } private void Update() { if (_cooldownRemaining > 0f) _cooldownRemaining -= Time.deltaTime; } // ── 公共 API ───────────────────────────────────────────────────────── /// 装备一个法术(替换当前已装备的)。 public void EquipSpell(SpellSO spell) { _equippedSpell = spell; _cooldownRemaining = 0f; } /// 卸下当前装备的法术。 public void UnequipSpell() { _equippedSpell = null; _cooldownRemaining = 0f; } /// 返回当前冷却进度(0 = 就绪,1 = 刚施放)。供 UI 血条使用。 public float CooldownFraction => _equippedSpell != null && _equippedSpell.cooldown > 0f ? Mathf.Clamp01(_cooldownRemaining / _equippedSpell.cooldown) : 0f; public SpellSO EquippedSpell => _equippedSpell; public bool IsReady => _equippedSpell != null && _cooldownRemaining <= 0f; // ── 内部施放逻辑 ────────────────────────────────────────────────────── private void TryCastSpell() { if (_equippedSpell == null || _cooldownRemaining > 0f) return; if (_stats == null) return; // 消耗资源(扣除护符提供的灵力减免后计算实际消耗) int cost = Mathf.Max(0, _equippedSpell.baseCost - _stats.SoulCostReduction); bool consumed = _equippedSpell.resourceType == SpellResourceType.SoulPower ? _stats.ConsumeSoulPower(cost) : _stats.ConsumeSpiritPower(cost); if (!consumed) return; _cooldownRemaining = _equippedSpell.cooldown; // 施放反馈 _feedback.TriggerPreset("spell_cast"); ExecuteSpellEffect(_equippedSpell); } private void ExecuteSpellEffect(SpellSO spell) { // 生成 HitBox Prefab(近战/爆炸类法术) if (spell.spellHitBoxPrefab != null) { var socket = _spellSocket != null ? _spellSocket : transform; Instantiate(spell.spellHitBoxPrefab, socket.position, socket.rotation, socket); } // TODO: 根据 spell.effectType 扩展施放逻辑 // SpellEffectType.Projectile → ProjectileManager 发射 // SpellEffectType.AreaOfEffect → AreaOfEffectSpawner 生成 // SpellEffectType.SelfBuff → PlayerStats/StatusEffectManager 施加增益 // SpellEffectType.SummonShade → 召唤投影 Prefab // SpellEffectType.TeleportBlink → 瞬移至光标/方向 } } }