using UnityEngine; using Animancer; using System.Collections.Generic; using BaseGames.Player; using BaseGames.Input; using BaseGames.Combat; namespace BaseGames.Skills { /// /// 技能管理器(架构 09_ProgressionModule §9)。 /// 挂在 Player 上,订阅输入事件并处理所有技能施放逻辑。 /// 通过 UpdateSkillSet() 由 FormController 注入当前形态技能。 /// 直接使用 AnimancerComponent 播放动画,无需 SoulSkillState FSM。 /// public class SkillManager : MonoBehaviour { [Header("依赖引用")] [SerializeField] private PlayerStats _stats; [SerializeField] private AnimancerComponent _animancer; [SerializeField] private InputReaderSO _input; [SerializeField] private FormController _formController; [SerializeField] private SkillModifierRegistry _modifiers; [Header("技能挂载点")] [SerializeField] private Transform _skillSocket; // [SkillSocket] 子节点 [Header("形态技能映射")] [SerializeField] private FormSkillSet[] _formSkillSets; // 按 FormType 配置,与 FormConfigSO.forms[] 对应 [System.Serializable] private struct FormSkillSet { public FormType formType; public FormSkillSO soulSkill; public FormSkillSO spiritSkill1; public FormSkillSO spiritSkill2; } // 当前形态技能集(绑定到对应输入槽) private FormSkillSO _soulSkill; private FormSkillSO _spirit1; private FormSkillSO _spirit2; // 冷却字典(FormSkillSO → 剩余冷却秒数),UpdateSkillSet 时重建 private readonly Dictionary _cooldowns = new(3); // 无分配 Update 遍历用的快照数组 private FormSkillSO[] _activeSkills = System.Array.Empty(); // ── 生命周期 ────────────────────────────────────────────────────────── private void OnEnable() { if (_input != null) { _input.SoulSkillEvent += TrySoulSkill; _input.SpiritSkill1StartedEvent += TrySpiritSkill1; _input.SpiritSkill2StartedEvent += TrySpiritSkill2; } if (_formController != null) { _formController.OnFormChanged += OnFormChanged; // 立即同步当前形态的技能集 ApplyFormSkills(_formController.CurrentForm); } } private void OnDisable() { if (_input != null) { _input.SoulSkillEvent -= TrySoulSkill; _input.SpiritSkill1StartedEvent -= TrySpiritSkill1; _input.SpiritSkill2StartedEvent -= TrySpiritSkill2; } if (_formController != null) _formController.OnFormChanged -= OnFormChanged; } private void OnFormChanged() { ApplyFormSkills(_formController.CurrentForm); } private void ApplyFormSkills(FormSO form) { if (form == null || _formSkillSets == null) { UpdateSkillSet(null, null, null); return; } foreach (var s in _formSkillSets) { if (s.formType == form.formType) { UpdateSkillSet(s.soulSkill, s.spiritSkill1, s.spiritSkill2); return; } } UpdateSkillSet(null, null, null); } 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; } } // ── 公共 API ───────────────────────────────────────────────────────── /// 切换形态时由 FormController 调用,注入当前形态的三个技能。 public void UpdateSkillSet(FormSkillSO soul, FormSkillSO spirit1, FormSkillSO spirit2) { _soulSkill = soul; _spirit1 = spirit1; _spirit2 = spirit2; _cooldowns.Clear(); // 构建无分配遍历快照(固定大小数组,避免 List + ToArray GC) int count = (soul != null ? 1 : 0) + (spirit1 != null ? 1 : 0) + (spirit2 != null ? 1 : 0); if (_activeSkills.Length != count) _activeSkills = count > 0 ? new FormSkillSO[count] : System.Array.Empty(); int idx = 0; if (soul != null) { _cooldowns[soul] = 0f; _activeSkills[idx++] = soul; } if (spirit1 != null) { _cooldowns[spirit1] = 0f; _activeSkills[idx++] = spirit1; } if (spirit2 != null) { _cooldowns[spirit2] = 0f; _activeSkills[idx] = spirit2; } } // ── 内部施放逻辑 ───────────────────────────────────────────────────── private void TrySoulSkill() => TryCastSkill(_soulSkill); private void TrySpiritSkill1() => TryCastSkill(_spirit1); private void TrySpiritSkill2() => TryCastSkill(_spirit2); private void TryCastSkill(FormSkillSO skill) { if (skill == null) return; var p = _modifiers != null ? _modifiers.GetEffectiveParams(skill) : EffectiveSkillParams.FromBase(skill); if (!_cooldowns.TryGetValue(skill, out float cooldown) || cooldown > 0f) return; // 消耗资源 bool consumed = skill.resourceType == SkillResourceType.SoulPower ? _stats.ConsumeSoulPower(p.effectiveCost) : _stats.ConsumeSpiritPower(p.effectiveCost); if (!consumed) return; _cooldowns[skill] = p.effectiveCooldown; // 播放动画(优先修改器动画,回退技能默认动画) var clip = p.effectiveAnimation.Clip != null ? p.effectiveAnimation : skill.castAnimation; if (clip.Clip != null && _animancer != null) _animancer.Play(clip); // 生成 HitBox Prefab(近战/爆炸类技能) if (skill.SkillHitBoxPrefab != null) { var socket = _skillSocket != null ? _skillSocket : transform; var go = Object.Instantiate(skill.SkillHitBoxPrefab, socket.position, socket.rotation, socket); var inst = go.GetComponent(); inst?.Activate(skill.damageSource, transform); inst?.AutoDestroyAfter(skill.castLockDuration > 0f ? skill.castLockDuration : 0.5f); } } // ── 属性查询 ───────────────────────────────────────────────────────── public FormSkillSO SoulSkill => _soulSkill; public FormSkillSO Spirit1 => _spirit1; public FormSkillSO Spirit2 => _spirit2; public float SoulCooldownRatio => (_soulSkill != null && _soulSkill.cooldown > 0 && _cooldowns.TryGetValue(_soulSkill, out float cd)) ? Mathf.Clamp01(cd / _soulSkill.cooldown) : 0f; } }