diff --git a/Assets/Scripts/Skills/Effectors/LaserSpawner.cs b/Assets/Scripts/Skills/Effectors/LaserSpawner.cs index 721f6ef..25f7ced 100644 --- a/Assets/Scripts/Skills/Effectors/LaserSpawner.cs +++ b/Assets/Scripts/Skills/Effectors/LaserSpawner.cs @@ -24,42 +24,40 @@ namespace EerieVillage.Skills.Effectors Vector2 facing = Vector2.right; var pc = inventory.GetComponent(); if (pc != null) facing = pc.Facing; - float baseAngle = Mathf.Atan2(facing.y, facing.x) * Mathf.Rad2Deg; - float totalAngle = baseAngle + data.FxRotation; - float rad = totalAngle * Mathf.Deg2Rad; - Vector2 forwardDir = new Vector2(Mathf.Cos(rad), Mathf.Sin(rad)); + // PD 지시 2026-05-13 — FxRotation 은 이펙트(시각) 전용. 박스(판정) 은 facing 만 반영. + float baseAngle = Mathf.Atan2(facing.y, facing.x) * Mathf.Rad2Deg; // 박스 회전 = facing 만 (좌/우) + float fxAngle = baseAngle + data.FxRotation; // 이펙트 회전 = facing + FxRotation + Vector2 boxForward = facing.normalized; // 박스 진행 방향 = facing (FxRotation 미적용) Vector2 playerPos = inventory.transform.position; - // PD 정합 2026-05-13 — OffsetDistance = (X, Y) 절대 오프셋. facing+FxRotation 영역 박스 size·rotation 만 영역. - Vector2 hitboxOrigin = playerPos + data.OffsetDistance; - Vector2 fxPos = playerPos + data.OffsetXY; // 이펙트 위치 + Vector2 fxPos = playerPos + data.OffsetXY; // 이펙트 위치 - // 이펙트 spawn — fxPos 영역·facing 회전 + FxRotation·HitFxScale 적용 + // 이펙트 spawn — fxPos·HitFxScale·facing+FxRotation 적용 GameObject fx = null; if (data.OnHitFxPrefab != null) { - fx = Object.Instantiate(data.OnHitFxPrefab, (Vector3)fxPos, Quaternion.Euler(0f, 0f, totalAngle)); - fx.hideFlags = HideFlags.DontSave; // PD 지시 2026-05-13 — Scene 저장 회피 - fx.transform.SetParent(inventory.transform, true); // 캐릭터 이동 시 함께 이동 + fx = Object.Instantiate(data.OnHitFxPrefab, (Vector3)fxPos, Quaternion.Euler(0f, 0f, fxAngle)); + fx.hideFlags = HideFlags.DontSave; + fx.transform.SetParent(inventory.transform, true); fx.transform.localScale *= data.HitFxScale; } float fxLifetime = GetFxLifetime(fx); int damage = Mathf.Max(data.BaseDamage, 1); - float length = Mathf.Max(data.HitboxSize.x, 1f); // 레이저 길이 + float length = Mathf.Max(data.HitboxSize.x, 1f); float width = Mathf.Max(data.HitboxSize.y, 0.5f); - // PD 지시 2026-05-13 — 박스 영역 Player 자식 영역 부착·forwardDir(facing+FxRotation) 정합 + // 박스 = Player 자식 부착·facing 만 회전 (FxRotation 미적용) var boxGo = new GameObject("LaserHitbox_Debug"); - boxGo.hideFlags = HideFlags.DontSave; // PD 지시 2026-05-13 — Scene 저장 회피 + boxGo.hideFlags = HideFlags.DontSave; boxGo.transform.SetParent(inventory.transform, false); float lpx = inventory.transform.lossyScale.x != 0f ? Mathf.Abs(inventory.transform.lossyScale.x) : 1f; float lpy = inventory.transform.lossyScale.y != 0f ? Mathf.Abs(inventory.transform.lossyScale.y) : 1f; - // PD 정합 — 박스 중심 (world) = hitboxOrigin + forwardDir × length/2 - // local 좌표 = OffsetDistance + forwardDir × length/2 (parent lossyScale 보정) - float localX = (data.OffsetDistance.x + forwardDir.x * length * 0.5f) / lpx; - float localY = (data.OffsetDistance.y + forwardDir.y * length * 0.5f) / lpy; + // PD 지시 2026-05-13 — OffsetDistance.x 는 facing sign 반영 (좌/우 반전) + float signX = facing.x < 0f ? -1f : 1f; + float localX = (signX * data.OffsetDistance.x + boxForward.x * length * 0.5f) / lpx; + float localY = (data.OffsetDistance.y + boxForward.y * length * 0.5f) / lpy; boxGo.transform.localPosition = new Vector3(localX, localY, 0f); - boxGo.transform.localRotation = Quaternion.Euler(0f, 0f, totalAngle); + boxGo.transform.localRotation = Quaternion.Euler(0f, 0f, baseAngle); // facing 만 boxGo.transform.localScale = new Vector3(length / lpx, width / lpy, 1f); var sr = boxGo.AddComponent(); sr.sprite = HitboxDebug.GetWhiteSprite(); @@ -90,18 +88,17 @@ namespace EerieVillage.Skills.Effectors } } - // PD 정합 2026-05-13 — OffsetDistanceX = X 절대·OffsetDistance = Y 절대·facing 영역 박스 방향만 영역 + // PD 지시 2026-05-13 — 판정 방향 = facing 만 (FxRotation 은 시각 전용·박스 미적용) static void ApplyLaserDamage(PlayerSkillInventory inventory, ActiveSkillData data, int damage, float length, float width) { if (inventory == null) return; Vector2 facing = Vector2.right; var pc = inventory.GetComponent(); if (pc != null) facing = pc.Facing; - float baseAngle = Mathf.Atan2(facing.y, facing.x) * Mathf.Rad2Deg; - float totalAngle = baseAngle + data.FxRotation; - float rad = totalAngle * Mathf.Deg2Rad; - Vector2 forwardDir = new Vector2(Mathf.Cos(rad), Mathf.Sin(rad)); - Vector2 origin = (Vector2)inventory.transform.position + data.OffsetDistance; + Vector2 forwardDir = facing.normalized; // 판정 진행 방향 = facing 만 + float signX = facing.x < 0f ? -1f : 1f; // OffsetDistance.x 좌/우 반전 + Vector2 origin = (Vector2)inventory.transform.position + + new Vector2(signX * data.OffsetDistance.x, data.OffsetDistance.y); var enemies = Object.FindObjectsByType(FindObjectsSortMode.None); int hits = 0; diff --git a/Assets/Scripts/Skills/Effectors/LightningStrikeSpawner.cs b/Assets/Scripts/Skills/Effectors/LightningStrikeSpawner.cs index 095df09..e91aa9d 100644 --- a/Assets/Scripts/Skills/Effectors/LightningStrikeSpawner.cs +++ b/Assets/Scripts/Skills/Effectors/LightningStrikeSpawner.cs @@ -63,17 +63,16 @@ namespace EerieVillage.Skills.Effectors AutoDestroyFx(fx, fxTotalLifetime); } - // PD 지시 2026-05-13 — 이펙트 생성 시점 영역 판정 영역 영역 캡처 (적 이동 무관 영역 정적) + // PD 지시 2026-05-13 — 이펙트 생성 시점 판정 영역 정적 캡처 (적 이동 무관) + // FxRotation 은 시각(이펙트) 전용 · 박스(판정) 은 rotation=0 · facing 도 적 위치 기준이라 미적용. Vector2 capturedSize = data.HitboxSize; - float capturedRot = data.FxRotation; int capturedDamage = Mathf.Max(data.BaseDamage, 1); - // 박스 즉시 spawn (Trigger 시점 hitboxPos 정적·lifetime = BaseCooldown) - var dbgGo = HitboxDebug.Spawn(hitboxPos, capturedSize, Mathf.Max(data.BaseCooldown, 1f)); - if (dbgGo != null) dbgGo.transform.rotation = Quaternion.Euler(0f, 0f, capturedRot); + // 박스 즉시 spawn (rotation=0 — FxRotation 미적용) + HitboxDebug.Spawn(hitboxPos, capturedSize, Mathf.Max(data.BaseCooldown, 1f)); - // PD 지시 2026-05-13 — ScriptableObject DamageFrameDelay·반복 피해 영역 정합 - inventory.StartCoroutine(FixedHitDamageCoroutine(hitboxPos, capturedSize, capturedRot, capturedDamage, data)); + // PD 지시 2026-05-13 — ScriptableObject DamageFrameDelay·반복 피해 정합 + inventory.StartCoroutine(FixedHitDamageCoroutine(hitboxPos, capturedSize, 0f, capturedDamage, data)); } // PD 지시 2026-05-13 — 고정 발동형 영역 영역 판정 영역 (DamageFrameDelay·EnableRepeatDamage·MaxHitCount·RepeatFrameInterval) diff --git a/Assets/Scripts/Skills/Effectors/MeleeAreaSpawner.cs b/Assets/Scripts/Skills/Effectors/MeleeAreaSpawner.cs index cbf883b..161ab4b 100644 --- a/Assets/Scripts/Skills/Effectors/MeleeAreaSpawner.cs +++ b/Assets/Scripts/Skills/Effectors/MeleeAreaSpawner.cs @@ -47,12 +47,14 @@ namespace EerieVillage.Skills.Effectors float duration = Mathf.Max(data.BaseCooldown, 1f); var boxGo = new GameObject("MeleeHitbox_Debug"); - boxGo.hideFlags = HideFlags.DontSave; // PD 지시 2026-05-13 — Scene 저장 회피 + boxGo.hideFlags = HideFlags.DontSave; boxGo.transform.SetParent(inventory.transform, false); float lpx = inventory.transform.lossyScale.x != 0f ? Mathf.Abs(inventory.transform.lossyScale.x) : 1f; float lpy = inventory.transform.lossyScale.y != 0f ? Mathf.Abs(inventory.transform.lossyScale.y) : 1f; - boxGo.transform.localPosition = new Vector3(data.OffsetDistance.x / lpx, data.OffsetDistance.y / lpy, 0f); - boxGo.transform.localRotation = Quaternion.Euler(0f, 0f, data.FxRotation); + // PD 지시 2026-05-13 — 박스(판정) = facing 좌/우 sign 만 반영 · FxRotation 미적용 (시각 전용) + float signX = facing.x < 0f ? -1f : 1f; + boxGo.transform.localPosition = new Vector3(signX * data.OffsetDistance.x / lpx, data.OffsetDistance.y / lpy, 0f); + boxGo.transform.localRotation = Quaternion.identity; boxGo.transform.localScale = new Vector3(hitboxSize.x / lpx, hitboxSize.y / lpy, 1f); var sr = boxGo.AddComponent(); sr.sprite = HitboxDebug.GetWhiteSprite(); @@ -84,11 +86,17 @@ namespace EerieVillage.Skills.Effectors static void DoOverlapBoxFromPlayer(PlayerSkillInventory inventory, ActiveSkillData data, int damage) { if (inventory == null) return; - Vector2 hitboxPos = (Vector2)inventory.transform.position + data.OffsetDistance; + // PD 지시 2026-05-13 — 박스(판정) = facing 좌/우 sign 만 · FxRotation 미적용 + Vector2 facing = Vector2.right; + var pc = inventory.GetComponent(); + if (pc != null) facing = pc.Facing; + float signX = facing.x < 0f ? -1f : 1f; + Vector2 hitboxPos = (Vector2)inventory.transform.position + + new Vector2(signX * data.OffsetDistance.x, data.OffsetDistance.y); var cf = new ContactFilter2D(); cf.useTriggers = false; var results = new Collider2D[32]; - int n = Physics2D.OverlapBox(hitboxPos, data.HitboxSize, data.FxRotation, cf, results); + int n = Physics2D.OverlapBox(hitboxPos, data.HitboxSize, 0f, cf, results); for (int i = 0; i < n; i++) { var c = results[i]; diff --git a/Assets/Scripts/Skills/Effectors/Projectile.cs b/Assets/Scripts/Skills/Effectors/Projectile.cs index 988db37..7b5d663 100644 --- a/Assets/Scripts/Skills/Effectors/Projectile.cs +++ b/Assets/Scripts/Skills/Effectors/Projectile.cs @@ -47,8 +47,8 @@ namespace EerieVillage.Skills.Effectors _direction = direction.normalized; _hitTargets.Clear(); - // PD 지시 2026-05-13 — 투사체 방향 정렬 + FxRotation 추가 - float angle = Mathf.Atan2(_direction.y, _direction.x) * Mathf.Rad2Deg + _data.FxRotation; + // PD 지시 2026-05-13 — 투사체 root = 박스(판정) 정합. FxRotation 미적용 (시각 전용·박스 회전 금지). + float angle = Mathf.Atan2(_direction.y, _direction.x) * Mathf.Rad2Deg; transform.rotation = Quaternion.Euler(0f, 0f, angle); // BT12-Dev 2026-05-10 (PD #1) — 거리 제한 영역 영역 spawn 위치 저장