fix(BT12-Dev): 잔존 cleanup Scene root 재귀 + Projectile.Awake 자기 destroy (PD 지시 2026-05-14)
PD 추가 진단 (스크린샷 + 발화): "게임 플레이 후 스크롤 되는 맵에
여전히 남아있는 상태야. 아마 스크롤 되며 연장되는 맵 영역이
초기화 되지 않는 것으로 예상 돼"
이전 commit ea239fe (3중 진입점 + FX clone prefix) 의 catch 누락
가능성 차단:
1. PlayerSkillInventory.DoCleanupStalePooledSpawns 영역
Resources.FindObjectsOfTypeAll → Scene.GetRootGameObjects + 재귀
변경. hideFlags hidden GO 누락 우려 제거·정확도 향상.
CollectStaleRecursive 신규 — 자식 트리 재귀 탐색.
IsStaleByName 헬퍼 — 이름 매칭 통합.
2. Projectile.Awake 신규 — _data == null && _runtime == null 상태
(= Initialize 미호출 잔존) 시 1 frame 유예 후 자기 destroy.
PlayerSkillInventory cleanup 누락 케이스 자체 정리 (2중 방어).
InfiniteHorizontalBackground·기타 컴포넌트 자식 부착된 잔존도
본 자가 destroy 로 catch.
측정 (Play 진입 직후):
- AfterSceneLoad static cleanup removed=0
- Awake cleanup removed=0
→ 이전 Play 잔존 = 0건 (Scene load·Awake 시점)
→ Hierarchy 영역 시각상 spawn = 자동 발사 진행 결과
후속: PD Refresh + Play → 화면 잔존 재확인 필요.
잔존 시 Console "[PlayerSkillInventory] ... removed=N" 로그 +
스크린샷 으로 본 PM 추가 진단.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ea239fef54
commit
7c894c60da
|
|
@ -36,6 +36,27 @@ namespace EerieVillage.Skills.Effectors
|
||||||
protected float[] _baseAlphas;
|
protected float[] _baseAlphas;
|
||||||
const float FADE_START_RATIO = 0.85f;
|
const float FADE_START_RATIO = 0.85f;
|
||||||
|
|
||||||
|
// PD 지시 2026-05-14 — Awake 시점 _data == null 잔존 GameObject 자기 destroy.
|
||||||
|
// 게임 재실행·Scene reload 시 이전 Play 잔존 Projectile (Initialize 미호출 상태) 자가 정리.
|
||||||
|
protected virtual void Awake()
|
||||||
|
{
|
||||||
|
if (_data == null && _runtime == null)
|
||||||
|
{
|
||||||
|
// Initialize 호출 전 (= 잔존) → 자기 destroy. 정상 spawn 은 Awake 직후 Initialize 호출이라 _data set 정합.
|
||||||
|
// Awake 직후 Initialize 가 별도 frame 에 호출되는 케이스 대비 1 frame 유예
|
||||||
|
StartCoroutine(_DestroyIfStale());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.Collections.IEnumerator _DestroyIfStale()
|
||||||
|
{
|
||||||
|
yield return null; // 1 frame 유예 (정상 Initialize 시점 보장)
|
||||||
|
if (_data == null && _runtime == null)
|
||||||
|
{
|
||||||
|
Destroy(gameObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ProjectileSpawner.Trigger 에서 Instantiate 직후 호출.
|
/// ProjectileSpawner.Trigger 에서 Instantiate 직후 호출.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -104,43 +104,58 @@ namespace EerieVillage.Skills
|
||||||
static int DoCleanupStalePooledSpawns(bool useImmediate)
|
static int DoCleanupStalePooledSpawns(bool useImmediate)
|
||||||
{
|
{
|
||||||
int removed = 0;
|
int removed = 0;
|
||||||
// (1) Projectile 및 파생 component GameObject — root 단위 destroy
|
// PD 지시 2026-05-14 — Scene root 재귀 탐색 (Resources.FindObjectsOfTypeAll 영역 hideFlags hidden GO 누락 우려·정확도 ↑)
|
||||||
var projs = Resources.FindObjectsOfTypeAll<EerieVillage.Skills.Effectors.Projectile>();
|
var scene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
|
||||||
foreach (var p in projs)
|
if (!scene.IsValid()) return 0;
|
||||||
|
var roots = scene.GetRootGameObjects();
|
||||||
|
// 재귀 cleanup 대상 수집 (직접 destroy 시 enumeration 중 collection 변경 회피)
|
||||||
|
var targets = new System.Collections.Generic.List<GameObject>();
|
||||||
|
foreach (var root in roots)
|
||||||
{
|
{
|
||||||
if (p == null || p.gameObject == null) continue;
|
CollectStaleRecursive(root, targets);
|
||||||
if (!p.gameObject.scene.IsValid()) continue; // prefab asset 제외
|
|
||||||
if (useImmediate) DestroyImmediate(p.gameObject); else Destroy(p.gameObject);
|
|
||||||
removed++;
|
|
||||||
}
|
}
|
||||||
// (2) 박스·Range 시각화 + FX clone — name 기반
|
foreach (var go in targets)
|
||||||
var allGOs = Resources.FindObjectsOfTypeAll<GameObject>();
|
|
||||||
foreach (var go in allGOs)
|
|
||||||
{
|
{
|
||||||
if (go == null) continue;
|
if (go == null) continue;
|
||||||
if (!go.scene.IsValid()) continue;
|
if (useImmediate) DestroyImmediate(go); else Destroy(go);
|
||||||
bool matchName = StaleSpawnNames.Contains(go.name);
|
removed++;
|
||||||
bool matchPrefix = false;
|
|
||||||
if (!matchName)
|
|
||||||
{
|
|
||||||
foreach (var pre in StaleClonePrefixes)
|
|
||||||
{
|
|
||||||
if (go.name.StartsWith(pre) && go.name.EndsWith("(Clone)"))
|
|
||||||
{
|
|
||||||
matchPrefix = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (matchName || matchPrefix)
|
|
||||||
{
|
|
||||||
if (useImmediate) DestroyImmediate(go); else Destroy(go);
|
|
||||||
removed++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return removed;
|
return removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void CollectStaleRecursive(GameObject root, System.Collections.Generic.List<GameObject> targets)
|
||||||
|
{
|
||||||
|
if (root == null) return;
|
||||||
|
// Projectile 및 파생 component 부착 → 이 root 단위 destroy
|
||||||
|
if (root.GetComponent<EerieVillage.Skills.Effectors.Projectile>() != null)
|
||||||
|
{
|
||||||
|
targets.Add(root);
|
||||||
|
return; // 자식 재귀 불필요 (root destroy 시 자식 자동 destroy)
|
||||||
|
}
|
||||||
|
// Name 매칭 (박스·Range·FX clone)
|
||||||
|
if (IsStaleByName(root.name))
|
||||||
|
{
|
||||||
|
targets.Add(root);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 자식 재귀
|
||||||
|
foreach (Transform child in root.transform)
|
||||||
|
{
|
||||||
|
CollectStaleRecursive(child.gameObject, targets);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsStaleByName(string name)
|
||||||
|
{
|
||||||
|
if (StaleSpawnNames.Contains(name)) return true;
|
||||||
|
if (!name.EndsWith("(Clone)")) return name.StartsWith("Projectile_");
|
||||||
|
foreach (var pre in StaleClonePrefixes)
|
||||||
|
{
|
||||||
|
if (name.StartsWith(pre)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// PD 지시 2026-05-13 — Start 시점에 기본 습득 스킬 자동 장착 (Resources 로드 완료 후·Awake 영역 아님)
|
// PD 지시 2026-05-13 — Start 시점에 기본 습득 스킬 자동 장착 (Resources 로드 완료 후·Awake 영역 아님)
|
||||||
void Start()
|
void Start()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue