2026-04-13 스킬시스템 진행중
This commit is contained in:
@@ -1,10 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
public class SkillModule : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private int _maxSlots = 4;
|
||||
[SerializeField] private LayerMask _groundLayer; // 바닥 레이캐스트용
|
||||
|
||||
// 범위 지정 시작/종료 이벤트 (외부에서 RotationMode/UI 등 반응)
|
||||
public event Action OnAreaSelectStarted;
|
||||
public event Action OnAreaSelectEnded;
|
||||
|
||||
private PlayerStateMachine _stateMachine;
|
||||
private Animator _anim;
|
||||
private Transform _transform;
|
||||
@@ -37,6 +44,18 @@ public class SkillModule : MonoBehaviour
|
||||
public bool IsCasting => _castingSlot >= 0;
|
||||
public bool IsChanneling => _channelingSlot >= 0;
|
||||
|
||||
[SerializeField] private List<WeaponSkillSet> _weaponSkills;
|
||||
[SerializeField] private Weapon _equippedWeapon;
|
||||
|
||||
private Dictionary<WeaponType, WeaponSkillSet> _dicSkills = new Dictionary<WeaponType, WeaponSkillSet>();
|
||||
|
||||
// 슬롯 이름 → 런타임 매핑 (Dispatcher 테이블)
|
||||
private Dictionary<string, IUseableRuntime> _skillBindData = new Dictionary<string, IUseableRuntime>();
|
||||
|
||||
// 퀵슬롯에 바인딩할 슬롯 이름 목록 (스킬용)
|
||||
private static readonly string[] SkillSlotNames =
|
||||
{ "UseSlot_Q", "UseSlot_E", "UseSlot_R", "UseSlot_T" };
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_stateMachine = GetComponent<PlayerStateMachine>();
|
||||
@@ -47,6 +66,55 @@ private void Awake()
|
||||
_skillEffects = new ISkillEffect[_maxSlots];
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// 무기별 스킬셋 테이블 구성
|
||||
foreach (WeaponSkillSet wss in _weaponSkills)
|
||||
{
|
||||
_dicSkills[wss.WeaponType] = wss;
|
||||
}
|
||||
|
||||
// 현재 장착 무기의 스킬셋 로드 (무기 미장착 시 스킬 없음)
|
||||
if (_equippedWeapon != null
|
||||
&& _dicSkills.TryGetValue(_equippedWeapon.WType, out WeaponSkillSet out_wss)
|
||||
&& out_wss != null)
|
||||
{
|
||||
LoadWeaponSkills(out_wss);
|
||||
RegisterSkillsToQuickslot(out_wss);
|
||||
}
|
||||
|
||||
// 각 슬롯에 dispatcher를 한 번만 바인딩 (이후 내용물만 _skillBindData로 교체)
|
||||
foreach (string slotName in SkillSlotNames)
|
||||
{
|
||||
string captured = slotName;
|
||||
GameManager.Instance.Level.BindSlotAction(captured, (state) => DispatchSlot(captured, state));
|
||||
}
|
||||
}
|
||||
|
||||
private void DispatchSlot(string slotName, InputState state)
|
||||
{
|
||||
if (!_skillBindData.TryGetValue(slotName, out IUseableRuntime runtime) || runtime == null)
|
||||
return;
|
||||
|
||||
runtime.Execute(new UseContext
|
||||
{
|
||||
Caster = gameObject,
|
||||
Target = null,
|
||||
UseInputState = state
|
||||
});
|
||||
}
|
||||
|
||||
private void RegisterSkillsToQuickslot(WeaponSkillSet wss)
|
||||
{
|
||||
for (int i = 0; i < SkillSlotNames.Length; i++)
|
||||
{
|
||||
if (i < wss.Skills.Count && wss.Skills[i] != null)
|
||||
_skillBindData[SkillSlotNames[i]] = wss.Skills[i].CreateRuntime();
|
||||
else
|
||||
_skillBindData.Remove(SkillSlotNames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
TickCooldowns();
|
||||
@@ -149,9 +217,6 @@ public void AreaConfirmInput(InputState inputState)
|
||||
#endregion
|
||||
|
||||
#region 발동 분기
|
||||
/// <summary>
|
||||
/// ActivationType에 따라 적절한 흐름을 시작
|
||||
/// </summary>
|
||||
private void BeginActivation(int slotIndex)
|
||||
{
|
||||
SkillInstance skill = _equippedSkills[slotIndex];
|
||||
@@ -220,6 +285,22 @@ private void ExecuteSkill(int slotIndex)
|
||||
skill.StartCooldown();
|
||||
_chargeTimer = 0f;
|
||||
_chargingSlot = -1;
|
||||
|
||||
// ActionDuration 경과 후 Idle 복귀
|
||||
float duration = skill.CurrentLevelData.ActionDuration;
|
||||
if (duration > 0f)
|
||||
{
|
||||
_ = Util.RunDelayed(duration, () =>
|
||||
{
|
||||
if (this != null && _stateMachine != null
|
||||
&& _stateMachine.CurrentState == PlayerState.Attack)
|
||||
_stateMachine.ChangeState(PlayerState.Idle);
|
||||
}, default);
|
||||
}
|
||||
else
|
||||
{
|
||||
_stateMachine.ChangeState(PlayerState.Idle);
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearRemoteTarget()
|
||||
@@ -416,13 +497,21 @@ private void StartAreaSelect(int slotIndex)
|
||||
float range = skill.CurrentLevelData.Range;
|
||||
_areaIndicator.transform.localScale = new Vector3(range * 2f, range * 2f, range * 2f);
|
||||
}
|
||||
|
||||
// 범위 지정 중에는 좌클릭이 확정 용도로 쓰이므로 기본 공격 차단
|
||||
InputManager.Instance.SuppressNormalAttack = true;
|
||||
|
||||
// 이벤트 발행 — 구독자(PlayerCharacterController 등)가 회전모드 등 처리
|
||||
OnAreaSelectStarted?.Invoke();
|
||||
}
|
||||
|
||||
private void TickAreaSelect()
|
||||
{
|
||||
if (_areaSelectSlot < 0 || _areaIndicator == null) return;
|
||||
|
||||
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
|
||||
if (Mouse.current == null) return;
|
||||
Vector2 mousePos = Mouse.current.position.ReadValue();
|
||||
Ray ray = Camera.main.ScreenPointToRay(mousePos);
|
||||
if (Physics.Raycast(ray, out RaycastHit hit, 200f, _groundLayer))
|
||||
{
|
||||
_areaIndicator.transform.position = hit.point;
|
||||
@@ -444,6 +533,10 @@ private void ConfirmAreaSelect()
|
||||
_areaIndicator = null;
|
||||
_areaSelectSlot = -1;
|
||||
|
||||
// 범위 지정 종료 → 기본 공격 복구
|
||||
InputManager.Instance.SuppressNormalAttack = false;
|
||||
OnAreaSelectEnded?.Invoke();
|
||||
|
||||
// ActivationType에 따라 흐름 시작
|
||||
BeginActivation(slotIndex);
|
||||
}
|
||||
@@ -455,6 +548,10 @@ public void CancelAreaSelect()
|
||||
|
||||
_areaIndicator = null;
|
||||
_areaSelectSlot = -1;
|
||||
|
||||
// 범위 지정 종료 → 기본 공격 복구
|
||||
InputManager.Instance.SuppressNormalAttack = false;
|
||||
OnAreaSelectEnded?.Invoke();
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -488,6 +585,23 @@ public SkillInstance GetSkill(int slotIndex)
|
||||
return _equippedSkills[slotIndex];
|
||||
}
|
||||
|
||||
public void SkillInputByData(SkillData data, InputState inputState)
|
||||
{
|
||||
int slotIndex = FindSlotByData(data);
|
||||
if (slotIndex < 0) return;
|
||||
SkillInput(slotIndex, inputState);
|
||||
}
|
||||
|
||||
private int FindSlotByData(SkillData data)
|
||||
{
|
||||
for (int i = 0; i < _maxSlots; i++)
|
||||
{
|
||||
if (_equippedSkills[i] != null && _equippedSkills[i].Data == data)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int MaxSlots => _maxSlots;
|
||||
#endregion
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user