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:
parent
41fa4e4ce7
commit
26b0666912
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -42,8 +42,8 @@ namespace EerieVillage.Skills.Effectors
|
||||||
}
|
}
|
||||||
|
|
||||||
float fxLifetime = GetFxLifetime(fx);
|
float fxLifetime = GetFxLifetime(fx);
|
||||||
// PD 지시 2026-05-13 — fx AutoDestroy 누락 fix·safety cap 5초 (잔상 차단)
|
// PD 지시 2026-05-13 — fx AutoDestroy 누락 fix·unscaledTime cap (Time.timeScale=0 영역 잔존 차단)
|
||||||
if (fx != null) Object.Destroy(fx, Mathf.Min(fxLifetime + 0.2f, 5f));
|
if (fx != null) FxAutoDestroyUnscaled.Attach(fx, Mathf.Min(fxLifetime + 0.2f, 5f));
|
||||||
int damage = Mathf.Max(data.BaseDamage, 1);
|
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);
|
float width = Mathf.Max(data.HitboxSize.y, 0.5f);
|
||||||
|
|
|
||||||
|
|
@ -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)
|
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;
|
if (data == null || data.ExtraHitFxPrefab == null) yield break;
|
||||||
var extraFx = Object.Instantiate(data.ExtraHitFxPrefab, fxPos, Quaternion.Euler(0f, 0f, data.FxRotation));
|
var extraFx = Object.Instantiate(data.ExtraHitFxPrefab, fxPos, Quaternion.Euler(0f, 0f, data.FxRotation));
|
||||||
extraFx.hideFlags = HideFlags.DontSave;
|
extraFx.hideFlags = HideFlags.DontSave;
|
||||||
|
|
@ -154,8 +154,8 @@ namespace EerieVillage.Skills.Effectors
|
||||||
static void AutoDestroyFx(GameObject fxGo, float lifetime)
|
static void AutoDestroyFx(GameObject fxGo, float lifetime)
|
||||||
{
|
{
|
||||||
if (fxGo == null) return;
|
if (fxGo == null) return;
|
||||||
// PD 지시 2026-05-13 — FX 잔상 safety cap 5초
|
// PD 지시 2026-05-13 — unscaledTime cap (Time.timeScale=0 영역 잔존 차단)
|
||||||
Object.Destroy(fxGo, Mathf.Min(lifetime + 0.2f, 5f));
|
FxAutoDestroyUnscaled.Attach(fxGo, Mathf.Min(lifetime + 0.2f, 5f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,8 @@ namespace EerieVillage.Skills.Effectors
|
||||||
// Player 자식 부착 (worldPositionStays=true) 으로 spawn 후에도 Player 이동에 동조.
|
// Player 자식 부착 (worldPositionStays=true) 으로 spawn 후에도 Player 이동에 동조.
|
||||||
fxGo.transform.SetParent(inventory.transform, true);
|
fxGo.transform.SetParent(inventory.transform, true);
|
||||||
fxLifetime = GetFxLifetime(fxGo);
|
fxLifetime = GetFxLifetime(fxGo);
|
||||||
// PD 지시 2026-05-13 — FX 잔상 safety cap 5초
|
// PD 지시 2026-05-13 — unscaledTime cap (Time.timeScale=0 영역 잔존 차단)
|
||||||
Object.Destroy(fxGo, Mathf.Min(fxLifetime + 0.2f, 5f));
|
FxAutoDestroyUnscaled.Attach(fxGo, Mathf.Min(fxLifetime + 0.2f, 5f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// PD 지시 2026-05-13 — 박스 영역 Player 자식 영역 부착·매 frame Player 따라감
|
// PD 지시 2026-05-13 — 박스 영역 Player 자식 영역 부착·매 frame Player 따라감
|
||||||
|
|
|
||||||
|
|
@ -312,8 +312,8 @@ namespace EerieVillage.Skills.Effectors
|
||||||
var main = ps.main;
|
var main = ps.main;
|
||||||
lifetime = main.duration + main.startLifetime.constantMax + 0.2f;
|
lifetime = main.duration + main.startLifetime.constantMax + 0.2f;
|
||||||
}
|
}
|
||||||
// PD 지시 2026-05-13 — FX 잔상 safety cap 5초
|
// PD 지시 2026-05-13 — unscaledTime cap (Time.timeScale=0 영역 잔존 차단)
|
||||||
Object.Destroy(fxGo, Mathf.Min(lifetime, 5f));
|
FxAutoDestroyUnscaled.Attach(fxGo, Mathf.Min(lifetime, 5f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,14 @@ namespace EerieVillage.Skills
|
||||||
effector = new ProjectileSpawner();
|
effector = new ProjectileSpawner();
|
||||||
break;
|
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:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue