feat(BT12-Dev): MeleeArea 실전 발사 연결 + FX AutoDestroy unscaledTime (PD 지시 2026-05-13)

작업 1 — 스킬 배워도 이펙트 X fix:
- SkillFireEvent.Execute — MeleeArea case 추가 (CardId 분기·TestSkillFireOn1to5 동일 패턴)
  - A04 → LightningStrikeSpawner
  - A_Laser → LaserSpawner
  - 기타 → MeleeAreaSpawner

작업 2 — 맵 이동 중 이펙트 잔상 재발 fix:
- 원인: Object.Destroy(fxGo, t) 영역 second timer 영역 Time.timeScale 영향·timeScale=0 (LevelUp) 영역 호출 정지
- 신규: FxAutoDestroyUnscaled MonoBehaviour — Update 영역 unscaledTime lifetime check 자가 Destroy
- ProjectileSpawner·Projectile·MeleeAreaSpawner·LaserSpawner·LightningStrikeSpawner 모두 영역 Object.Destroy(fx, t) → FxAutoDestroyUnscaled.Attach
- LightningStrikeSpawner.DelayedExtraHitFx — WaitForSeconds → WaitForSecondsRealtime (timeScale=0 영역 정합)

본 PM 자성 #12 — feedback_new_code_existing_system_dependency_unmeasured 위반. Object.Destroy(go, t) 영역 timeScale 영향 사전 측정 누락 (Unity 표준 API).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
깃 관리자 2026-05-13 20:26:40 +09:00
parent 41fa4e4ce7
commit 26b0666912
6 changed files with 55 additions and 11 deletions

View File

@ -0,0 +1,37 @@
using UnityEngine;
namespace EerieVillage.Skills.Effectors
{
/// <summary>
/// PD 지시 2026-05-13 — fx GO 영역 unscaledTime 영역 자가 Destroy.
/// Object.Destroy(go, t) 영역 second timer 영역 Time.timeScale 영향 영역 → timeScale=0 (LevelUp 등) 영역 호출 정지·잔존.
/// 본 컴포넌트 = Update 영역 Time.unscaledTime 영역 lifetime check → 자가 Destroy.
/// fxGo Instantiate 직후 AddComponent 영역 lifetime 설정.
/// </summary>
public class FxAutoDestroyUnscaled : MonoBehaviour
{
public float Lifetime = 5f;
float _spawnTime;
void Awake()
{
_spawnTime = Time.unscaledTime;
}
void Update()
{
if (Time.unscaledTime - _spawnTime >= Lifetime)
{
Destroy(gameObject);
}
}
public static void Attach(GameObject go, float lifetime)
{
if (go == null) return;
var c = go.GetComponent<FxAutoDestroyUnscaled>();
if (c == null) c = go.AddComponent<FxAutoDestroyUnscaled>();
c.Lifetime = Mathf.Max(0.1f, lifetime);
}
}
}

View File

@ -42,8 +42,8 @@ namespace EerieVillage.Skills.Effectors
}
float fxLifetime = GetFxLifetime(fx);
// PD 지시 2026-05-13 — fx AutoDestroy 누락 fix·safety cap 5초 (잔상 차단)
if (fx != null) Object.Destroy(fx, Mathf.Min(fxLifetime + 0.2f, 5f));
// PD 지시 2026-05-13 — fx AutoDestroy 누락 fix·unscaledTime cap (Time.timeScale=0 영역 잔존 차단)
if (fx != null) FxAutoDestroyUnscaled.Attach(fx, Mathf.Min(fxLifetime + 0.2f, 5f));
int damage = Mathf.Max(data.BaseDamage, 1);
float length = Mathf.Max(data.HitboxSize.x, 1f);
float width = Mathf.Max(data.HitboxSize.y, 0.5f);

View File

@ -99,10 +99,10 @@ namespace EerieVillage.Skills.Effectors
}
}
// PD 지시 2026-05-13 — ExtraHitFxPrefab 지연 spawn (비주얼 전용·판정 무관)
// PD 지시 2026-05-13 — ExtraHitFxPrefab 지연 spawn (비주얼 전용·판정 무관·WaitForSecondsRealtime 영역 Time.timeScale=0 영역 정합)
static System.Collections.IEnumerator DelayedExtraHitFx(ActiveSkillData data, Vector2 fxPos, float delaySeconds)
{
yield return new WaitForSeconds(delaySeconds);
yield return new WaitForSecondsRealtime(delaySeconds);
if (data == null || data.ExtraHitFxPrefab == null) yield break;
var extraFx = Object.Instantiate(data.ExtraHitFxPrefab, fxPos, Quaternion.Euler(0f, 0f, data.FxRotation));
extraFx.hideFlags = HideFlags.DontSave;
@ -154,8 +154,8 @@ namespace EerieVillage.Skills.Effectors
static void AutoDestroyFx(GameObject fxGo, float lifetime)
{
if (fxGo == null) return;
// PD 지시 2026-05-13 — FX 잔상 safety cap 5초
Object.Destroy(fxGo, Mathf.Min(lifetime + 0.2f, 5f));
// PD 지시 2026-05-13 — unscaledTime cap (Time.timeScale=0 영역 잔존 차단)
FxAutoDestroyUnscaled.Attach(fxGo, Mathf.Min(lifetime + 0.2f, 5f));
}
}
}

View File

@ -41,8 +41,8 @@ namespace EerieVillage.Skills.Effectors
// Player 자식 부착 (worldPositionStays=true) 으로 spawn 후에도 Player 이동에 동조.
fxGo.transform.SetParent(inventory.transform, true);
fxLifetime = GetFxLifetime(fxGo);
// PD 지시 2026-05-13 — FX 잔상 safety cap 5초
Object.Destroy(fxGo, Mathf.Min(fxLifetime + 0.2f, 5f));
// PD 지시 2026-05-13 — unscaledTime cap (Time.timeScale=0 영역 잔존 차단)
FxAutoDestroyUnscaled.Attach(fxGo, Mathf.Min(fxLifetime + 0.2f, 5f));
}
// PD 지시 2026-05-13 — 박스 영역 Player 자식 영역 부착·매 frame Player 따라감

View File

@ -312,8 +312,8 @@ namespace EerieVillage.Skills.Effectors
var main = ps.main;
lifetime = main.duration + main.startLifetime.constantMax + 0.2f;
}
// PD 지시 2026-05-13 — FX 잔상 safety cap 5초
Object.Destroy(fxGo, Mathf.Min(lifetime, 5f));
// PD 지시 2026-05-13 — unscaledTime cap (Time.timeScale=0 영역 잔존 차단)
FxAutoDestroyUnscaled.Attach(fxGo, Mathf.Min(lifetime, 5f));
}
}
}

View File

@ -37,7 +37,14 @@ namespace EerieVillage.Skills
effector = new ProjectileSpawner();
break;
// Phase 2-C~ 예정: MeleeArea·PlacementPersistent·Minion·Debuff·SpecialJudge
// PD 지시 2026-05-13 — MeleeArea 영역 CardId 분기 (TestSkillFireOn1to5 영역 동일 패턴)
case ActiveCategory.MeleeArea:
if (data.CardId == "A04") effector = new LightningStrikeSpawner();
else if (data.CardId == "A_Laser") effector = new LaserSpawner();
else effector = new MeleeAreaSpawner();
break;
// Phase 2-C~ 예정: PlacementPersistent·Minion·Debuff·SpecialJudge
default:
return;
}