feat(BT12-Dev): 게임 재실행 시 잔존 spawn 강제 cleanup (PD 지시 2026-05-14)

PD 보고: "게임 플레이 중 종료했다가 다시 시작할 경우 이전 게임
플레이 중 생성 된 투사체가 여전히 남아있어. 게임을 재실행할 때
기존에 생성 된 풀링 오브젝트가 소멸될 수 있도록 수정해줘."

PlayerSkillInventory.Awake 시점 CleanupStalePooledSpawns 호출:
- Projectile 및 파생 (HomingProjectile·PiercingProjectile) component
  부착 GameObject 전수 destroy
- 박스 시각화 name 5종 (Hitbox_Debug·ProjectileHitbox_Debug·
  LaserHitbox_Debug·MeleeHitbox_Debug·Range_Debug) destroy
- Resources.FindObjectsOfTypeAll + scene.IsValid filter
  (asset prefab 제외)
- removed 카운트 Debug.Log

기존 HideFlags.DontSave (60e28e3) 정합 외 추가 보험:
- DontDestroyOnLoad 경로 (코드베이스 검색 0건 — 방어 코드)
- Scene 영구 저장 누락 케이스
- 메모리 잔존 (Editor crash 후 재시작 등)

검증 (Play 모드):
- A02·A05 발사 후 spawn 카운트 6
- CleanupStalePooledSpawns 직접 호출 + 1 frame 후 카운트 0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
깃 관리자 2026-05-14 15:43:52 +09:00
parent e0e26ec311
commit 01865b88fb
1 changed files with 44 additions and 0 deletions

View File

@ -45,11 +45,55 @@ namespace EerieVillage.Skills
void Awake() void Awake()
{ {
// PD 지시 2026-05-14 — 게임 재실행 시 이전 Play 잔존 spawn (투사체·박스·Range) 강제 cleanup.
// HideFlags.DontSave 정합 외 DontDestroyOnLoad·Scene 영구 저장·메모리 잔존 경로 방어.
CleanupStalePooledSpawns();
Stats = new PlayerStats(); Stats = new PlayerStats();
PlayerStats.Current = Stats; PlayerStats.Current = Stats;
_health = GetComponent<Health>(); _health = GetComponent<Health>();
} }
// PD 지시 2026-05-14 — 잔존 풀링 GameObject 강제 cleanup
// 대상: Projectile 및 파생 (HomingProjectile·PiercingProjectile) + 박스 시각화 GameObject
static readonly System.Collections.Generic.HashSet<string> StaleSpawnNames =
new System.Collections.Generic.HashSet<string>
{
"Hitbox_Debug",
"ProjectileHitbox_Debug",
"LaserHitbox_Debug",
"MeleeHitbox_Debug",
"Range_Debug",
};
void CleanupStalePooledSpawns()
{
int removed = 0;
// (1) Projectile 및 파생 component GameObject — root 단위 destroy
var projs = Resources.FindObjectsOfTypeAll<EerieVillage.Skills.Effectors.Projectile>();
foreach (var p in projs)
{
if (p == null || p.gameObject == null) continue;
if (!p.gameObject.scene.IsValid()) continue; // prefab asset 제외
Destroy(p.gameObject);
removed++;
}
// (2) 박스 시각화 — name 기반 (자체 부착 컴포넌트 부재 케이스)
var allGOs = Resources.FindObjectsOfTypeAll<GameObject>();
foreach (var go in allGOs)
{
if (go == null) continue;
if (!go.scene.IsValid()) continue;
if (StaleSpawnNames.Contains(go.name))
{
Destroy(go);
removed++;
}
}
if (removed > 0)
Debug.Log("[PlayerSkillInventory] CleanupStalePooledSpawns removed=" + removed);
}
// PD 지시 2026-05-13 — Start 시점에 기본 습득 스킬 자동 장착 (Resources 로드 완료 후·Awake 영역 아님) // PD 지시 2026-05-13 — Start 시점에 기본 습득 스킬 자동 장착 (Resources 로드 완료 후·Awake 영역 아님)
void Start() void Start()
{ {