diff --git a/Assets/Scripts/Skills/SkillController.cs b/Assets/Scripts/Skills/SkillController.cs index cab2f714..e0398b93 100644 --- a/Assets/Scripts/Skills/SkillController.cs +++ b/Assets/Scripts/Skills/SkillController.cs @@ -21,6 +21,10 @@ namespace Colosseum.Skills [Header("설정")] [SerializeField] private bool debugMode = false; + [Tooltip("공격 범위 시각화 (Scene 뷰에서 확인)")] + [SerializeField] private bool showAreaDebug = true; + [Tooltip("범위 표시 지속 시간")] + [Min(0.1f)] [SerializeField] private float debugDrawDuration = 1f; // 현재 실행 중인 스킬 private SkillData currentSkill; @@ -207,6 +211,12 @@ namespace Colosseum.Skills var effect = effects[index]; if (debugMode) Debug.Log($"[Effect] {effect.name} (index {index})"); + // 공격 범위 시각화 + if (showAreaDebug) + { + effect.DrawDebugRange(gameObject, debugDrawDuration); + } + effect.ExecuteOnCast(gameObject); } diff --git a/Assets/Scripts/Skills/SkillEffect.cs b/Assets/Scripts/Skills/SkillEffect.cs index ed46dba2..e5de1a58 100644 --- a/Assets/Scripts/Skills/SkillEffect.cs +++ b/Assets/Scripts/Skills/SkillEffect.cs @@ -18,12 +18,28 @@ namespace Colosseum.Skills [Tooltip("범위 내에서 공격할 대상 필터")] [SerializeField] protected TargetTeam targetTeam = TargetTeam.Enemy; [SerializeField] protected AreaCenterType areaCenter = AreaCenterType.Caster; - [Min(0.1f)] [SerializeField] protected float areaRadius = 3f; + [SerializeField] protected AreaShapeType areaShape = AreaShapeType.Sphere; [SerializeField] protected LayerMask targetLayers; + [Header("Sphere Settings")] + [Min(0.1f)] [SerializeField] protected float areaRadius = 3f; + + [Header("Fan Settings")] + [Tooltip("부채꼴 원점이 캐릭터로부터 떨어진 거리")] + [Min(0f)] [SerializeField] protected float fanOriginDistance = 1f; + [Tooltip("부채꼴 반지름")] + [Min(0.1f)] [SerializeField] protected float fanRadius = 3f; + [Tooltip("부채꼴 좌우 각도 (각 방향으로 이 각도만큼 벌어짐, 총 각도 = 2배)")] + [Range(0f, 180f)] [SerializeField] protected float fanHalfAngle = 45f; + // Properties public TargetType TargetType => targetType; public TargetTeam TargetTeam => targetTeam; + public AreaShapeType AreaShape => areaShape; + public float AreaRadius => areaRadius; + public float FanOriginDistance => fanOriginDistance; + public float FanRadius => fanRadius; + public float FanHalfAngle => fanHalfAngle; /// /// 스킬 시전 시 호출 @@ -89,17 +105,51 @@ namespace Colosseum.Skills private void ExecuteArea(GameObject caster) { Vector3 center = GetAreaCenter(caster); - Collider[] hits = Physics.OverlapSphere(center, areaRadius, targetLayers); + Collider[] hits = Physics.OverlapSphere(center, Mathf.Max(areaRadius, fanRadius), targetLayers); foreach (var hit in hits) { if (hit.gameObject == caster) continue; if (!IsCorrectTeam(caster, hit.gameObject)) continue; + // 부채꼴 판정 + if (areaShape == AreaShapeType.Fan) + { + if (!IsInFanShape(caster, hit.transform.position)) + continue; + } + ApplyEffect(caster, hit.gameObject); } } + /// + /// 타겟이 부채꼴 범위 내에 있는지 확인 + /// + private bool IsInFanShape(GameObject caster, Vector3 targetPosition) + { + Vector3 casterPos = caster.transform.position; + Vector3 casterForward = caster.transform.forward; + + // 부채꼴 원점 계산 + Vector3 fanOrigin = casterPos + casterForward * fanOriginDistance; + + // 원점에서 타겟까지의 방향과 거리 + Vector3 toTarget = targetPosition - fanOrigin; + float distance = toTarget.magnitude; + + // 거리 체크 + if (distance > fanRadius) + return false; + + // 각도 체크 (Y축 무시) + Vector3 toTargetFlat = new Vector3(toTarget.x, 0f, toTarget.z).normalized; + Vector3 casterForwardFlat = new Vector3(casterForward.x, 0f, casterForward.z).normalized; + + float angle = Vector3.Angle(casterForwardFlat, toTargetFlat); + return angle <= fanHalfAngle; + } + private Vector3 GetAreaCenter(GameObject caster) { if (caster == null) return Vector3.zero; @@ -111,6 +161,83 @@ namespace Colosseum.Skills _ => caster.transform.position }; } + + #region Debug Visualization + /// + /// 공격 범위 시각화 (런타임 디버그용) + /// + public void DrawDebugRange(GameObject caster, float duration = 1f) + { + if (targetType != TargetType.Area) return; + + Vector3 casterPos = caster.transform.position; + Vector3 forward = caster.transform.forward; + + if (areaShape == AreaShapeType.Sphere) + { + Vector3 center = GetAreaCenter(caster); + DebugDrawSphere(center, areaRadius, Color.red, duration); + } + else if (areaShape == AreaShapeType.Fan) + { + DebugDrawFan(casterPos, forward, fanOriginDistance, fanRadius, fanHalfAngle, Color.red, duration); + } + } + + private void DebugDrawSphere(Vector3 center, float radius, Color color, float duration) + { + int segments = 32; + float step = 360f / segments; + + // XZ 평면 원 + Vector3 prevPoint = center + new Vector3(radius, 0, 0); + for (int i = 1; i <= segments; i++) + { + float angle = i * step * Mathf.Deg2Rad; + Vector3 newPoint = center + new Vector3(Mathf.Cos(angle) * radius, 0, Mathf.Sin(angle) * radius); + Debug.DrawLine(prevPoint, newPoint, color, duration); + prevPoint = newPoint; + } + + // 수직선 (높이 표시) + Debug.DrawLine(center + Vector3.up * 0.1f, center + Vector3.up * 2f, color, duration); + } + + private void DebugDrawFan(Vector3 casterPos, Vector3 forward, float originDistance, float radius, float halfAngle, Color color, float duration) + { + Vector3 fanOrigin = casterPos + forward * originDistance; + Vector3 forwardFlat = new Vector3(forward.x, 0f, forward.z).normalized; + + // 부채꼴의 양끝 방향 계산 + Quaternion leftRot = Quaternion.Euler(0, -halfAngle, 0); + Quaternion rightRot = Quaternion.Euler(0, halfAngle, 0); + Vector3 leftDir = leftRot * forwardFlat; + Vector3 rightDir = rightRot * forwardFlat; + + // 부채꼴 호 그리기 + int arcSegments = Mathf.Max(8, Mathf.CeilToInt(halfAngle * 2 / 5f)); // 5도당 1세그먼트 + Vector3 prevPoint = fanOrigin + leftDir * radius; + + for (int i = 1; i <= arcSegments; i++) + { + float t = (float)i / arcSegments; + float angle = -halfAngle + t * halfAngle * 2; + Quaternion rot = Quaternion.Euler(0, angle, 0); + Vector3 dir = rot * forwardFlat; + Vector3 newPoint = fanOrigin + dir * radius; + + Debug.DrawLine(prevPoint, newPoint, color, duration); + prevPoint = newPoint; + } + + // 부채꼴 경계선 + Debug.DrawLine(fanOrigin, fanOrigin + leftDir * radius, color, duration); + Debug.DrawLine(fanOrigin, fanOrigin + rightDir * radius, color, duration); + + // 원점 표시 + Debug.DrawLine(fanOrigin + Vector3.up * 0.1f, fanOrigin + Vector3.up * 1.5f, color, duration); + } + #endregion } public enum TargetType @@ -131,4 +258,10 @@ namespace Colosseum.Skills Caster, CasterForward } + + public enum AreaShapeType + { + Sphere, // 원형 범위 + Fan // 부채꼴 범위 + } } diff --git a/Assets/Scripts/Stats.meta b/Assets/Scripts/Stats.meta new file mode 100644 index 00000000..74ab4885 --- /dev/null +++ b/Assets/Scripts/Stats.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 16ccc0cabc79ab349804827c78c5f38a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Stats/CharacterStat.cs.meta b/Assets/Scripts/Stats/CharacterStat.cs.meta new file mode 100644 index 00000000..caa906bf --- /dev/null +++ b/Assets/Scripts/Stats/CharacterStat.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 6f06303e1f173c04b82ef0d6bb561bc1 \ No newline at end of file diff --git a/Assets/Scripts/Stats/CharacterStats.cs.meta b/Assets/Scripts/Stats/CharacterStats.cs.meta new file mode 100644 index 00000000..9230cc20 --- /dev/null +++ b/Assets/Scripts/Stats/CharacterStats.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: fae0149926eea244dad932b67ee76f7b \ No newline at end of file diff --git a/Assets/Scripts/Stats/StatModifier.cs.meta b/Assets/Scripts/Stats/StatModifier.cs.meta new file mode 100644 index 00000000..d7915d32 --- /dev/null +++ b/Assets/Scripts/Stats/StatModifier.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f947563a48624434b8f7851592571324 \ No newline at end of file diff --git a/Assets/Scripts/Stats/StatType.cs.meta b/Assets/Scripts/Stats/StatType.cs.meta new file mode 100644 index 00000000..84fb97cc --- /dev/null +++ b/Assets/Scripts/Stats/StatType.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 6d826b3dfc0d45042ae01c2def537568 \ No newline at end of file diff --git a/Assets/Skills/NewDamageEffect.asset b/Assets/Skills/Effects/Melee_Slash_0.asset similarity index 94% rename from Assets/Skills/NewDamageEffect.asset rename to Assets/Skills/Effects/Melee_Slash_0.asset index 781b2441..b10aa886 100644 --- a/Assets/Skills/NewDamageEffect.asset +++ b/Assets/Skills/Effects/Melee_Slash_0.asset @@ -10,7 +10,7 @@ MonoBehaviour: m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 58efb3c775496fa40b801b21127a011e, type: 3} - m_Name: NewDamageEffect + m_Name: Melee_Slash_0 m_EditorClassIdentifier: Colosseum.Game::Colosseum.Skills.Effects.DamageEffect description: damageAmount: 10 diff --git a/Assets/Skills/NewDamageEffect.asset.meta b/Assets/Skills/Effects/Melee_Slash_0.asset.meta similarity index 100% rename from Assets/Skills/NewDamageEffect.asset.meta rename to Assets/Skills/Effects/Melee_Slash_0.asset.meta