using UnityEngine; public class SkillManager : MonoBehaviour { [SerializeField] private int _maxSlots = 4; private PlayerStateMachine _stateMachine; private Animator _anim; private Transform _transform; private SkillInstance[] _equippedSkills; private ISkillEffect[] _skillEffects; private int _chargingSlot = -1; private float _chargeTimer = 0f; private void Awake() { _stateMachine = GetComponent(); _anim = GetComponent(); _transform = transform; _equippedSkills = new SkillInstance[_maxSlots]; _skillEffects = new ISkillEffect[_maxSlots]; } private void Update() { TickCooldowns(); TickCharge(); } #region 스킬 장착 public void LoadWeaponSkills(WeaponSkillSet skillSet) { for (int i = 0; i < _maxSlots; i++) { if (i < skillSet.Skills.Count && skillSet.Skills[i] != null) { _equippedSkills[i] = new SkillInstance(skillSet.Skills[i]); _skillEffects[i] = ResolveEffect(skillSet.Skills[i].TargetType); } else { _equippedSkills[i] = null; _skillEffects[i] = null; } } ApplyPassives(); } private ISkillEffect ResolveEffect(TargetType targetType) { return targetType switch { TargetType.Self => GetComponent(), TargetType.Single => GetComponent(), TargetType.Area => GetComponent(), TargetType.Projectile => GetComponent(), _ => null }; } #endregion #region 입력 public void SkillInput(int slotIndex, InputState inputState) { if (slotIndex < 0 || slotIndex >= _maxSlots) return; SkillInstance skill = _equippedSkills[slotIndex]; if (skill == null) return; if (skill.Data.SkillType == SkillType.Passive) return; if (inputState == InputState.Started) { if (!CanUseSkill(skill)) return; if (skill.Data.ActivationType == ActivationType.Instant) { ExecuteSkill(slotIndex); } else if (skill.Data.ActivationType == ActivationType.Charge) { StartCharge(slotIndex); } } else if (inputState == InputState.Canceled) { if (_chargingSlot == slotIndex) { ReleaseCharge(); } } } #endregion #region 실행 private bool CanUseSkill(SkillInstance skill) { if (skill.IsOnCooldown) return false; PlayerState state = _stateMachine.CurrentState; if (state == PlayerState.Dead || state == PlayerState.Hit || state == PlayerState.Dodge || state == PlayerState.Trans || state == PlayerState.Action) return false; return true; } private void ExecuteSkill(int slotIndex) { SkillInstance skill = _equippedSkills[slotIndex]; ISkillEffect effect = _skillEffects[slotIndex]; _stateMachine.ChangeState(PlayerState.Attack); if (!string.IsNullOrEmpty(skill.Data.AnimTrigger)) _anim.SetTrigger(skill.Data.AnimTrigger); float chargeRatio = 1f; if (skill.Data.ActivationType == ActivationType.Charge) { float maxCharge = skill.CurrentLevelData.ChargeTimeMax; chargeRatio = maxCharge > 0 ? Mathf.Clamp01(_chargeTimer / maxCharge) : 1f; } effect?.Execute(skill, _transform, chargeRatio); skill.StartCooldown(); _chargeTimer = 0f; _chargingSlot = -1; } #endregion #region 차지 private void StartCharge(int slotIndex) { _chargingSlot = slotIndex; _chargeTimer = 0f; _stateMachine.ChangeState(PlayerState.Charge); SkillInstance skill = _equippedSkills[slotIndex]; if (!string.IsNullOrEmpty(skill.Data.AnimTrigger)) _anim.SetTrigger(skill.Data.AnimTrigger); } private void ReleaseCharge() { if (_chargingSlot < 0) return; ExecuteSkill(_chargingSlot); } private void TickCharge() { if (_chargingSlot < 0) return; SkillInstance skill = _equippedSkills[_chargingSlot]; _chargeTimer += Time.deltaTime; if (_chargeTimer >= skill.CurrentLevelData.ChargeTimeMax) { ReleaseCharge(); } } #endregion #region 쿨다운 private void TickCooldowns() { foreach (var skill in _equippedSkills) { skill?.TickCooldown(Time.deltaTime); } } #endregion #region 패시브 private void ApplyPassives() { foreach (var skill in _equippedSkills) { if (skill != null && skill.Data.SkillType == SkillType.Passive) { // PlayerStat에 스탯 보정 적용 } } } #endregion #region 외부 접근 public SkillInstance GetSkill(int slotIndex) { if (slotIndex < 0 || slotIndex >= _maxSlots) return null; return _equippedSkills[slotIndex]; } public int MaxSlots => _maxSlots; #endregion }