203 lines
5.3 KiB
C#
203 lines
5.3 KiB
C#
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<PlayerStateMachine>();
|
|
_anim = GetComponent<Animator>();
|
|
_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<BuffEffect>(),
|
|
TargetType.Single => GetComponent<DamageEffect>(),
|
|
TargetType.Area => GetComponent<AreaEffect>(),
|
|
TargetType.Projectile => GetComponent<ProjectileEffect>(),
|
|
_ => 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
|
|
}
|