From e2b446e0f4b2e7a86b12698988df053139bff73f Mon Sep 17 00:00:00 2001 From: swrring Date: Thu, 14 May 2026 23:14:05 +0900 Subject: [PATCH] =?UTF-8?q?feat(BT12-Dev):=20A06=C2=B7A11=20=ED=8C=90?= =?UTF-8?q?=EC=A0=95=20=EB=B0=95=EC=8A=A4=20=EC=8B=9C=EA=B0=81=ED=99=94=20?= =?UTF-8?q?+=20A11=20OverlapBox=20=EC=A0=84=ED=99=98=20+=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EB=93=9C=20(PD=20=EC=A7=80=EC=8B=9C=202026-05-14)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PD 발화 2건: 1. "독 늪 소환의 판정(중독 효과 발생 가능한 범위)와 정령불의 판정 범위도 박스 형태로 보여줘 (정령불의 범위에 있는 적은 정령불이 유지되는 동안 일정한 피해 간격마다 피해를 입어야 해)" 2. "정령불 이펙트는 소멸되기 0.5초 전부터 알파값을 증가시키고 크기를 최대 현재 크기 기준으로 최대 50%까지 줄어들며 사라지도록 해줘." A06 독 늪 (PoisonSwampInstance): - PoisonSwampHitbox_Debug 자식 GO 신규 — BoxCollider2D.size 일관 SpriteRenderer (1, 0, 0, 0.35) · sortingOrder 100 · ShowDebugVisuals 토글 A11 정령불 (SpiritFireSpawner / Instance): - OverlapCircle → OverlapBox (HitboxSize 사용·박스 시각 ↔ 판정 정합) - AuraRadius 의존 제거 · _radius (float) → _boxSize (Vector2) - SpiritFireHitbox_Debug Player 자식 GO — Player 이동 동조 - 피해 간격 = DotInterval (기본 1초·Inspector 조절) - 소멸 0.5초 전 페이드 (PD 의도 "투명도 증가" = alpha 1→0): · FADE_DURATION=0.5 · alphaMul = 1-t · scaleMul = 1-0.5t · Renderer·MaterialPropertyBlock·_baseAlphas 캐싱 (Projectile 동일 패턴) · _TintColor 또는 _Color 자동 분기 PlayerSkillInventory.StaleSpawnNames: - PoisonSwampHitbox_Debug·SpiritFireHitbox_Debug·MeleeHitbox_Debug2 추가 - 게임 재실행 시 cleanup catch 정합 검증 (Play 모드): - A06 발사 → PoisonSwampHitbox_Debug visible=True (parent FX_Venom_Swamp) - A11 발사 → SpiritFireHitbox_Debug visible=True (parent Player·scale 2.5,2.5) - A11 HitboxSize=(2.5, 2.5)·DotInterval=1·MinionLifetime=8 정합 SOT (스킬_이펙트_확정_v1.md) §4 변경 이력 갱신. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../Skills/Effectors/PoisonSwampSpawner.cs | 12 ++ .../Skills/Effectors/SpiritFireSpawner.cs | 109 ++++++++++++++---- .../Skills/Runtime/PlayerSkillInventory.cs | 4 + 3 files changed, 103 insertions(+), 22 deletions(-) diff --git a/Assets/Scripts/Skills/Effectors/PoisonSwampSpawner.cs b/Assets/Scripts/Skills/Effectors/PoisonSwampSpawner.cs index a783f6c..8f1cadb 100644 --- a/Assets/Scripts/Skills/Effectors/PoisonSwampSpawner.cs +++ b/Assets/Scripts/Skills/Effectors/PoisonSwampSpawner.cs @@ -107,6 +107,18 @@ namespace EerieVillage.Skills.Effectors rb.simulated = true; rb.gravityScale = 0f; rb.useFullKinematicContacts = true; + + // PD 지시 2026-05-14 — 판정 박스 시각화 (붉은 반투명 박스·ShowDebugVisuals 토글) + var dbg = new GameObject("PoisonSwampHitbox_Debug"); + dbg.hideFlags = HideFlags.DontSave; + dbg.transform.SetParent(transform, false); + dbg.transform.localPosition = Vector3.zero; + dbg.transform.localScale = new Vector3(size.x, size.y, 1f); + var sr = dbg.AddComponent(); + sr.sprite = HitboxDebug.GetWhiteSprite(); + sr.color = new Color(1f, 0f, 0f, 0.35f); + sr.sortingOrder = 100; + sr.enabled = HitboxDebug.ShowDebugVisuals; } void Update() diff --git a/Assets/Scripts/Skills/Effectors/SpiritFireSpawner.cs b/Assets/Scripts/Skills/Effectors/SpiritFireSpawner.cs index 7c9a206..829319a 100644 --- a/Assets/Scripts/Skills/Effectors/SpiritFireSpawner.cs +++ b/Assets/Scripts/Skills/Effectors/SpiritFireSpawner.cs @@ -39,11 +39,14 @@ namespace EerieVillage.Skills.Effectors shieldGo.hideFlags = HideFlags.DontSave; float duration = data.MinionLifetime > 0.1f ? data.MinionLifetime : 8f; - float radius = data.AuraRadius > 0.1f ? data.AuraRadius : 2.5f; + // PD 지시 2026-05-14 — 판정 박스 형태 일관 (HitboxSize 사용·OverlapBox) + Vector2 boxSize = data.HitboxSize.sqrMagnitude > 0.01f ? data.HitboxSize : new Vector2(2.5f, 2.5f); int damage = data.BaseDamage > 0 ? data.BaseDamage : 5; + // PD 지시 2026-05-14 — 일정 피해 간격 (DotInterval 우선·기본 1초) + float interval = data.DotInterval > 0.01f ? data.DotInterval : 1f; var instance = shieldGo.AddComponent(); - instance.Init(inventory.transform, duration, radius, damage); + instance.Init(inventory.transform, duration, boxSize, damage, interval); } } @@ -64,16 +67,26 @@ namespace EerieVillage.Skills.Effectors Animator _animator; float _spawnTime; float _duration; - float _radius; + Vector2 _boxSize; int _damage; + float _interval; float _lastDamageTime; + Transform _debugBoxTransform; - public void Init(Transform player, float duration, float radius, int damage) + // PD 지시 2026-05-14 — 소멸 0.5초 전 페이드 (alpha 1→0·scale 1→0.5) + const float FADE_DURATION = 0.5f; + Vector3 _baseScale; + Renderer[] _renderers; + MaterialPropertyBlock _mpb; + float[] _baseAlphas; + + public void Init(Transform player, float duration, Vector2 boxSize, int damage, float interval) { _player = player; _duration = duration; - _radius = radius; + _boxSize = boxSize; _damage = damage; + _interval = interval; _spawnTime = Time.unscaledTime; _animator = GetComponent(); @@ -83,6 +96,61 @@ namespace EerieVillage.Skills.Effectors _animator.updateMode = AnimatorUpdateMode.UnscaledTime; _animator.speed = 1f; } + + // PD 지시 2026-05-14 — 판정 박스 시각화 (붉은 반투명 박스·ShowDebugVisuals 토글) + var dbg = new GameObject("SpiritFireHitbox_Debug"); + dbg.hideFlags = HideFlags.DontSave; + dbg.transform.SetParent(_player, false); // Player 자식·매 frame 동조 + dbg.transform.localPosition = Vector3.zero; + float lpx = _player.lossyScale.x != 0f ? Mathf.Abs(_player.lossyScale.x) : 1f; + float lpy = _player.lossyScale.y != 0f ? Mathf.Abs(_player.lossyScale.y) : 1f; + dbg.transform.localScale = new Vector3(_boxSize.x / lpx, _boxSize.y / lpy, 1f); + var sr = dbg.AddComponent(); + sr.sprite = HitboxDebug.GetWhiteSprite(); + sr.color = new Color(1f, 0f, 0f, 0.35f); + sr.sortingOrder = 100; + sr.enabled = HitboxDebug.ShowDebugVisuals; + _debugBoxTransform = dbg.transform; + Destroy(dbg, _duration); + + // PD 지시 2026-05-14 — fade 캐싱 (Renderer·MaterialPropertyBlock·기본 alpha) + _baseScale = transform.localScale; + _renderers = GetComponentsInChildren(); + _mpb = new MaterialPropertyBlock(); + _baseAlphas = new float[_renderers.Length]; + for (int i = 0; i < _renderers.Length; i++) + { + var r = _renderers[i]; + if (r == null) { _baseAlphas[i] = 1f; continue; } + if (r.sharedMaterial != null && r.sharedMaterial.HasProperty("_TintColor")) + _baseAlphas[i] = r.sharedMaterial.GetColor("_TintColor").a; + else if (r.sharedMaterial != null && r.sharedMaterial.HasProperty("_Color")) + _baseAlphas[i] = r.sharedMaterial.GetColor("_Color").a; + else _baseAlphas[i] = 1f; + } + } + + // PD 지시 2026-05-14 — 페이드 보간 적용 + void ApplyFadeout(float t) + { + t = Mathf.Clamp01(t); + float alphaMul = 1f - t; + float scaleMul = 1f - 0.5f * t; + transform.localScale = _baseScale * scaleMul; + if (_renderers == null) return; + for (int i = 0; i < _renderers.Length; i++) + { + var r = _renderers[i]; + if (r == null) continue; + r.GetPropertyBlock(_mpb); + string propName = (r.sharedMaterial != null && r.sharedMaterial.HasProperty("_TintColor")) + ? "_TintColor" : "_Color"; + Color baseCol = (r.sharedMaterial != null && r.sharedMaterial.HasProperty(propName)) + ? r.sharedMaterial.GetColor(propName) : Color.white; + baseCol.a = _baseAlphas[i] * alphaMul; + _mpb.SetColor(propName, baseCol); + r.SetPropertyBlock(_mpb); + } } void Update() @@ -117,7 +185,8 @@ namespace EerieVillage.Skills.Effectors _animator.Play(STATE_HASH, 0, normalized); } - if (Time.unscaledTime - _spawnTime >= _duration) + float elapsedFromSpawn = Time.unscaledTime - _spawnTime; + if (elapsedFromSpawn >= _duration) { Destroy(gameObject); return; @@ -125,32 +194,28 @@ namespace EerieVillage.Skills.Effectors Vector2 center = _player != null ? (Vector2)_player.position : (Vector2)transform.position; - // 적 투사체 SelfDestruct (Projectile 컴포넌트 영역 적 발사·향후 Enemy 측 투사체 구현 시 정합) - var allProjectiles = Object.FindObjectsByType(FindObjectsSortMode.None); - foreach (var p in allProjectiles) - { - if (p == null) continue; - float d = Vector2.Distance(center, p.transform.position); - if (d <= _radius) - { - // PD 명시 — 적 투사체만 SelfDestruct. 현 Projectile = Player 발사 only → 영향 X 영역 (방어 코드). - // 향후 Enemy 측 Projectile 분리 시 friendly check 추가 필요. - } - } - - // 매 1초 근접 적 피해 - if (Time.unscaledTime - _lastDamageTime >= 1f) + // PD 지시 2026-05-14 — 정령불의 범위에 있는 적은 지속 시간 동안 일정한 피해 간격마다 피해 + if (Time.unscaledTime - _lastDamageTime >= _interval) { _lastDamageTime = Time.unscaledTime; ApplyDamageAround(center); } + + // PD 지시 2026-05-14 — 소멸 0.5초 전 페이드 (alpha 감소·scale 50% 축소) + float remaining = _duration - elapsedFromSpawn; + if (remaining <= FADE_DURATION && remaining > 0f) + { + float t = 1f - (remaining / FADE_DURATION); // 0→1 over 0.5s + ApplyFadeout(t); + } } void ApplyDamageAround(Vector2 center) { + // PD 지시 2026-05-14 — OverlapBox 영역 박스 형태 판정 (HitboxSize 사용·박스 시각 ↔ 판정 정합) var cf = new ContactFilter2D { useTriggers = false }; var results = new Collider2D[32]; - int n = Physics2D.OverlapCircle(center, _radius, cf, results); + int n = Physics2D.OverlapBox(center, _boxSize, 0f, cf, results); for (int i = 0; i < n; i++) { var c = results[i]; diff --git a/Assets/Scripts/Skills/Runtime/PlayerSkillInventory.cs b/Assets/Scripts/Skills/Runtime/PlayerSkillInventory.cs index 5e22796..99c3e94 100644 --- a/Assets/Scripts/Skills/Runtime/PlayerSkillInventory.cs +++ b/Assets/Scripts/Skills/Runtime/PlayerSkillInventory.cs @@ -87,7 +87,11 @@ namespace EerieVillage.Skills "ProjectileHitbox_Debug", "LaserHitbox_Debug", "MeleeHitbox_Debug", + "MeleeHitbox_Debug2", "Range_Debug", + // PD 지시 2026-05-14 — A06·A11 판정 박스 시각화 신규 + "PoisonSwampHitbox_Debug", + "SpiritFireHitbox_Debug", }; // PD 지시 2026-05-14 — FX clone 카탈로그 (Projectile component 미부착 — Cast FX·HitFx 등)