작업 1 — 피격 이펙트 상위 sortingOrder:
- Projectile.OnTriggerEnter2D OnHitFx — Renderer.sortingOrder += 100
- LightningStrikeSpawner OnHitFx + ExtraHitFx — 동일
- MeleeAreaSpawner fxGo — 동일
- LaserSpawner fx — 동일
- Enemy SpriteRenderer 영역 위·뒤쪽 가림 회피
작업 2 — 적 추적 각도 하단 보정:
- ProjectileSpawner.Trigger TargetEnemyOnFire 영역 toEnemy.y -= 0.5
- 적 transform.position 영역 상단 영역·hitbox 영역 영역 영역 적중 정합
- A08 영역 영역 영역 영역 영역 영역 적 hitbox 영역 영역 영역 적중
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
작업 1 — 캐스팅 이펙트 제거:
- A08.asset OffsetDistance.x 1.5 → 0 (Player 위치 spawn)
- A08.asset CastFxPrefab null
작업 2 — 가장 가까운 적 방향 발사:
- ActiveSkillData.TargetEnemyOnFire (bool) 신규 필드
- ProjectileSpawner.Trigger — TargetEnemyOnFire=true 시 FindObjectsByType<EnemyController> 영역 nearest 검출·facing = (enemyPos - playerPos).normalized
- 적 0명 시 PlayerController.Facing fallback (기존 정합)
- A08.asset TargetEnemyOnFire=1
벽·발판 관통 X — Projectile.Update 영역 Layer 0·16 OverlapPoint 영역 영역 영역 정합 (변경 X).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
원인: SelfDestruct 영역 즉시 Destroy(gameObject) → ParticleSystem 영역 진행 영역 trail·glow particle 즉시 사라짐 → 발사 영역 영역 영역 매번 시각 cut → "뚝뚝 끊기는" 인식.
fix:
- _fadeOutStarted flag — 중복 호출 차단
- Collider2D·_debugBoxTransform disable — 판정 종료
- _speed = 0 — 이동 정지
- ParticleSystem.Stop(true, StopEmitting) — emission 정지·기존 particle 자연 fade
- Destroy(gameObject, 0.5f) — 0.5s 후 Destroy (기존 particle lifetime 영역 자연 fade 완료)
- FADE_START_RATIO 0.8 → 0.85 (sprite fadeout 영역 영역 영역·자연 영역 영역)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
원인: fx.transform.localScale *= HitFxScale 영역 적용·그러나 ParticleSystem.MainModule.scalingMode 영역 = Local·Shape 영역 영역 영역 root scale 영역 영역 X·ParticleSystem 영역 자체 size 영역 영역 영역 영역.
fix: 모든 fx spawn 영역 ParticleSystem foreach 영역 영역 ScalingMode = Hierarchy 설정 + Play(true) 동시. Hierarchy 영역 = parent Transform scale 영역 정합 적용.
전수 적용 (7 파일):
- Projectile.OnTriggerEnter2D — OnHitFx
- ProjectileSpawner.Trigger — CastFx + ProjectilePrefab
- MeleeAreaSpawner.Trigger — fxGo
- LightningStrikeSpawner — OnHitFx + ExtraHitFx
- LaserSpawner.Trigger — fx
- PoisonSwampSpawner — swampGo + Marker.Tick fx
- SpiritFireSpawner — shieldGo
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
작업 1 — 캐스팅 이펙트 끝 지점 영역 투사체 발사:
- A08.asset OffsetDistance.x: 0 → 1.5
- ProjectileSpawner.Trigger 영역 spawnPos = playerPos + facing × 1.5 영역 캐스팅 끝 지점
- (FX_PinkArrow_Shoot 캐스팅 길이 영역 1.5 unit 추정·PD 측정 후 미세 조정 가능)
작업 2 — Hit FX 발사 시 Player 위치 발생 회피:
- 원인 추정: spawn 위치 = Player 위치 + OffsetDistance·작업 1 이전 OffsetDistance=0 영역 Player 위치 spawn → Player 근접 Enemy 즉시 hit → OnHit FX = Enemy 위치 ≈ Player 위치 → "Player에게 발생" 인식
- 작업 1 영역 spawn 위치 영역 Player 영역 1.5 우측 이동 → 자동 정정
- Projectile.OnTriggerEnter2D 영역 spawn 직후 0.1초 grace period 추가 (Time.unscaledTime - _spawnTime < 0.1f 영역 return) — 즉시 hit 차단·OnHitFx Player 위치 표시 회피
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
원인: CastFx Instantiate 영역 = Quaternion.Euler(0, 0, data.FxRotation) (=0) 영역. FX_PinkArrow_Shoot sprite left 기본 → 시전 영역 sprite left 표시·Player right 발사 방향과 반대.
fix:
- ProjectileSpawner.Trigger CastFx — facing angle + ProjectileAngleOffset + FxRotation 적용 (Projectile 본체 동일 패턴)
- 진단 Debug.Log 2종 회수 ([ProjectileSpawner] card·CastFx spawned·[Projectile] OnHit) — fileID 정정 완료·root 원인 확정 후 revert
A08 영역 ProjectileAngleOffset=180 영역 정합 (sprite left → right) → CastFx·Projectile 동일 방향.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
원인: 직전 aa6cef1 영역 Debug.Log interpolated string 영역 `\"NULL\"` escape 사용·C# interpolated string escape 미지원 → 컴파일 에러.
fix: ternary 결과 영역 변수 분리 (castName·projName·hitName).
본 PM 자성 #15 — Edit 후 컴파일 사전 검증 누락. Unity Editor 영역 컴파일 영역 영역 영역 본 PM 영역 X 영역 영역 = PD 영역 보고 후 영역. C# string escape 영역 사전 측정 의무.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A08.asset 영역 ProjectilePrefab·OnHitFxPrefab·CastFxPrefab GUID 정합 측정 정합·코드 정합. 그러나 PD 영역 시전·피격 X 보고 → 실측 진단 필요.
진단 Log 2종 (회수 의무·PD Console 측정 후 본 PM revert):
- ProjectileSpawner.Trigger — [ProjectileSpawner] card·CastFx·ProjPrefab·OnHitFx 매핑 측정·CastFx spawn 확인
- Projectile.OnHit — [Projectile] OnHit card·OnHitFx spawn name·pos 확인
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
원인: FX_PinkMagicArrow prefab sprite 기본 방향 left·Projectile.Initialize 영역 atan2(facing)·우향 발사 시 sprite left 보임.
fix:
- ActiveSkillData.ProjectileAngleOffset (float, Range -360~360) 신규 필드 — prefab sprite 기본 방향 보정용
- Projectile.Initialize — angle = atan2 + ProjectileAngleOffset
- A08.asset — ProjectileAngleOffset 180 설정 (FX_PinkMagicArrow left → right 보정)
박스(판정) 영역 = 동시 회전·HitboxSize 대칭 가정 영역 영향 X.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
직전 b1b476a 영역 PoisonSwamp·SpiritFire 영역만 명시 Play 적용·나머지 4 Spawner + Projectile 영역 누락.
전수 적용:
- MeleeAreaSpawner.Trigger — OnHitFx (A05·A12 등) 영역 Play
- LightningStrikeSpawner.Trigger — OnHitFx·DelayedExtraHitFx Play
- LaserSpawner.Trigger — fx (A_Laser OnHit) Play
- ProjectileSpawner.Trigger — ProjectilePrefab (A02·A08 FX_PinkMagicArrow 등)·CastFxPrefab (A08 FX_PinkArrow_Shoot) Play
- Projectile.OnTriggerEnter2D — OnHitFx (A02·A08 등) Play
원인: 신규 import prefab 영역 playOnAwake 영역 정합 X 가능성 또는 Instantiate 시점 영역 Awake 호출 X·명시 Play 안전망 누락.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
원인 추정:
- PoisonSwampInstance 영역 BoxCollider2D·Rigidbody2D 영역 FX root 직접 부착 → ParticleSystem 영역 영향 가능
- Instantiate playOnAwake 정합·그러나 명시 Play() 호출 안전망 영역 누락
fix:
- PoisonSwampSpawner.Trigger — FX root 영역 GetComponentsInChildren<ParticleSystem>(true) 영역 명시 ps.Play(true)
- PoisonSwampInstance — BoxCollider2D·Rigidbody2D 영역 자식 GO 분리 (PoisonSwamp_Collider)·FX root 영역 visualRoot 보관·duration 종료 시 함께 Destroy
- PoisonedEnemyMarker.Tick — FX_Venom_Spray 영역 동일 ParticleSystem.Play(true) 명시 호출
- SpiritFireSpawner.Trigger — 동일 명시 Play(true) 호출
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
신규 Effector 2종:
- PoisonSwampSpawner — Category C (PlacementPersistent)
· 가장 가까운 적 위치 spawn·6초 유지·BoxCollider2D isTrigger·Kinematic Rigidbody2D
· PoisonSwampInstance — OnTriggerStay 영역 적 마킹·PoisonedEnemyMarker 부착·duration 5초 갱신
· PoisonedEnemyMarker — 매 초 10 피해·FX_Venom_Spray 자식 spawn (DotFxPrefab)·duration 만료 시 자가 소멸
- SpiritFireSpawner — Category D (Minion)
· Player 자식 spawn·8초 유지·OverlapCircle radius 2.5
· SpiritFireInstance — 매 초 근접 적 5 피해·Time.unscaledTime 영역 lifecycle
SkillFireEvent.Execute switch 확장:
- PlacementPersistent case → PoisonSwampSpawner
- Minion case → SpiritFireSpawner
A06 독 늪 .asset 신규 — Category 2·BaseCooldown 10·BaseDamage 10·OnHitFxPrefab=FX_Venom_Swamp·OnDotFxPrefab=FX_Venom_Spray
A11 정령불 .asset 신규 — Category 3·BaseCooldown 15·BaseDamage 5·MinionLifetime 8·OnHitFxPrefab=FX_Rotating shield
SkillRuntimeFactory.AvailableCardIds — A06·A11 추가 (7→9종)
TestSkillFireOn1to5 — PoisonSwamp·SpiritFire 인스턴스 신규·Category 분기 추가 (CardId 기반 MeleeArea 분기 정합)
PD Inspector 영역 — Player.prefab TestSkillFireOn1to5 Skill1=A06·Skill2=A11 .asset drag&drop 필요.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
원인: LightningStrikeSpawner.Trigger 영역 candidates.Count == 0 시 즉시 return → 적 0명 영역 발동 X.
fix: candidates 0 시 Player 위치 영역 fallback (primaryPos = inventory.transform.position) → 일정 쿨타임 자동 발동.
A05 MeleeAreaSpawner·A_Laser LaserSpawner = Player 위치 기준 발동·적 무관 영역 이미 정합.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
작업 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>
근본 원인:
- Time.timeScale=0 (LevelUp 카드 선택 모드) 영역 Time.time 정지 → Invoke(SelfDestruct, lifetime) 영역 호출 X → 영원 잔존
- _spawnTime = Time.time 영역 = lifetime backup check 영역 영역 X
fix:
- _spawnTime = Time.unscaledTime (timeScale 무관)
- Update 영역 lifetime check — Time.unscaledTime - _spawnTime > _lifetime 영역 강제 SelfDestruct
- Wall grace period — Time.unscaledTime 영역 정합
- Invoke 폐기·CancelInvoke 추가 안전 (Initialize 영역 잔존 Invoke 차단)
본 PM 자성 #11 — Time.time vs Time.unscaledTime 영역 사전 측정 누락. Projectile 영역 lifecycle 영역 timeScale 영역 영향 영역 사전 측정 의무 누락.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
작업 1 — 죽는 모션 종료 시점 팝업 UI:
- LevelUpManager — Player 사망 상태 영역 HandleLevelUp 호출 시 _pendingLevels 영역 저장
- Update 영역 매 frame Player IsAlive·!_isLevelUpActive check → pending 영역 ShowLevelUpUI 표시
- 죽는 모션 동안 LevelUp 즉시 표시 X·부활 후 표시
작업 2 — Player 사망 모션 y -0.3 추가 (누적 -0.6):
- PlayerDeath.Execute — new Vector3(0f, -0.6f, 0f)
작업 3 — 투사체 잔상 강화 fix + 진단:
- Projectile.Update — lifetime + 0.5 backup 강제 SelfDestruct (Invoke 누락 안전망)
- Projectile.Initialize — [Projectile][Initialize] 진단 Log (회수 의무)
- ProjectileSpawner.Trigger — [ProjectileSpawner] 진단 Log (회수 의무)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
원인: ProjectileSpawner.Trigger 영역 BoxCollider2D.isTrigger=true 활성 (단계 2) 직후·Initialize (단계 3) 이전 OnTriggerEnter2D 발화 가능 → _runtime=null → NullReferenceException line 187 → SelfDestruct 미호출 → 영구 잔존.
fix:
1. OnTriggerEnter2D 영역 `_runtime == null || _data == null` defensive return
2. Update 영역 `_data == null` 시 즉시 SelfDestruct (잔존 차단)
본 PM 자성 #10 — race condition 사전 측정 누락. ProjectileSpawner.Trigger 영역 collider 부착 시점·Initialize 호출 시점 영역 사이 OnTriggerEnter2D 발화 가능성 사전 측정 X.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
작업 1 — Player 죽는 모션 X fix:
- PlayerDeath.Execute — SetTrigger("hurt") → SetTrigger("hit") (Player.controller parameter 정합: velocityX·velocityY·grounded·attack·dead·hit·combatidle·resurrect·hurt 없음)
- animator.updateMode = AnimatorUpdateMode.UnscaledTime 추가 (EnemyDeath 영역 동일·timeScale=0 영향 차단)
작업 2 — 부활 모션 중 움직임 fix:
- PlayerSpawn.Execute — Rigidbody2D.simulated=true 복원 폐기 (즉시 X)
- EnablePlayerInput.Execute — Rigidbody2D.simulated=true 복원 추가 (2초 후·부활 모션 종료 시점)
- using UnityEngine 추가 (CS0246 회피)
작업 3 — 투사체 잔상 진단 (회수 의무):
- Projectile.SelfDestruct — [Projectile][SelfDestruct] Debug.Log
- Projectile.OnDestroy — [Projectile][OnDestroy] Debug.Log (Destroy 외 경로 검출용)
- PD Console 측정 결과 영역 본 PM 근본 fix 후 revert
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
이전 commit 3a672f0 영역 Rigidbody2D 참조 추가 시 using UnityEngine 영역 누락.
fix: 첫 줄에 using UnityEngine 추가.
본 PM 자성 #8 — 신규 type 영역 (Rigidbody2D) 사용 영역 namespace using 영역 사전 검증 누락.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
작업 1 — Player 사망 사라지는 현상 fix:
- PlayerDeath.Execute — Rigidbody2D.simulated=false (gravity 정지·제자리 사망·낙사 차단)
작업 2·3 — 제자리 부활·부활 모션·2초 무적 깜박:
- PlayerSpawn.Execute — Teleport 폐기 (spawn point 영역 → 제자리)
- player.health.Resurrect() 호출 (currentHP=maxHP·invulnerableUntil=2초·Animator dead=false·resurrect Trigger)
- Rigidbody2D.simulated=true 복원
- PlayerInvulnerabilityFlash 영역 IsInvulnerable 자동 깜박 (2초)
- 2초 후 EnablePlayerInput (조작 가능)
작업 4 — FX 잔상 safety cap 5초:
- LaserSpawner.Trigger — fx Object.Destroy 누락 fix (LaserSpawner 영역 본 영역 영역 영역 직접 원인 가능)
- LightningStrikeSpawner.AutoDestroyFx — cap
- MeleeAreaSpawner.Trigger — cap
- Projectile.AutoDestroyOnParticleEnd — cap
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Projectile.OnTriggerEnter2D 영역 동족 Projectile skip (Wall·Enemy 판정 이전).
원인: fallback Projectile GO 영역 default Layer 0 영역 → 다른 Projectile 영역 isWall=true 판정 → 양쪽 SelfDestruct.
fix: other.GetComponent<Projectile>() != null 시 즉시 return.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
작업 1 — 사망 모션 y -0.5 → -0.3 (EnemyDeath·PlayerDeath)
작업 2 — 게임 시작 시 파이어볼 투사체 정지·잔존 fix:
- ProjectileSpawner.Trigger — facing.sqrMagnitude < 0.01f 시 Vector2.right fallback
- 원인: Player.Facing 영역 (0,0) 영역 → _direction = (0,0) → _speed × deltaTime × (0,0) = 0 → 정지
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
SkillCardSlot.Bind 영역 card.Icon == null fallback:
- _icon — 동적 원 sprite (32×32 알파) + 속성별 색상 (Fire 주황·Frost 하늘·Dark 보라·Lightning 노랑·Physical 흰)
- _glowEffect — 동일 sprite + alpha 0.3 (동심원 빛 효과 정합)
- GetFallbackIconSprite·GetColorByAttribute static helper (정적 캐싱)
- card.Icon 설정 시 정상 sprite 사용 (PD 후속 정식 아이콘 자산 추가 시 자동 정합)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EnemyDeath·PlayerDeath Execute 영역 death Animator Trigger 직전 transform.position.y -= 0.5 적용.
sprite 위로 떠 보이는 현상 정정·collider·gameplay 영향 X (Enemy 1초 후 Destroy·Player PlayerSpawn 시 위치 reset).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
작업 1 — Enemy HP 30~40 자동 fallback:
- Health.Awake — RandomMaxHPRange 미설정 + EnemyController 존재 검출 → maxHP = Random.Range(30, 41) 자동
- PD Inspector 설정 의존 폐기 (PD가 매번 직접 영역 안전 X)
작업 2 — Player 피격 distance 기반 강화 + 진단 Debug.Log (회수 의무):
- EnemyController.Update — VisualBounds.Intersects OR distance < 1.5f 단일 조건 fix
- [EnemyHit] 단일 prefix Debug.Log — dist·boundsHit·distHit·invuln·Enemy/Player pos·t
- PD Console 측정 결과 영역 근본 fix 후 본 PM revert
- 본 PM 자성 #7 — 직전 IsGrounded 폐기 fix 효과 X 자인·다른 가설 (Bounds 미 교차) 강력화
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- PlayerSkillInventory.StartingCardIds (string[]) Inspector 필드 신규 — 기본 { "A02" }
- Start() 메서드 신규 — Resources 로드 완료 후 시점에 AddSkillByCardId 일괄 호출
- 다중 스킬 지원·잘못된 CardId 자동 skip (AddSkillByCardId LogWarning 정합)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
작업 1 — A05·A_Laser 박스 SpriteRenderer.enabled 누락 정정:
- MeleeAreaSpawner·LaserSpawner 영역 직접 GO 생성·SpriteRenderer 부착 (HitboxDebug 미경유 영역).
- sr.enabled = HitboxDebug.ShowDebugVisuals 1줄 추가 (재활용 toggle 정합).
작업 2 — Player 피격 X 진단 Debug.Log 추가 (회수 의무):
- EnemyController.Update L387-396 — VisualBounds.Intersects(Player.Bounds)·IsGrounded·IsInvulnerable 측정.
- [EnemyHit][Intersect] (조건 측정)·[EnemyHit][Decrement] (실제 호출) 2종 prefix.
- PD Console 측정 후 본 PM 가설 검증·근본 fix 후 Debug.Log 회수.
- 본 PM 가설: (1) Enemy patrol 거리 영역 Player 근접 X (2) Enemy maxHearts=1 자동 공격 즉시 처치 (3) IsGrounded false 영역 통과.
feedback_pm_root_diagnosis_priority 정합 — 가설 추정 사전 진단 우선.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
작업 1 — 디버그 박스·사거리 박스 시각화 off (재활용 toggle):
- HitboxDebug.ShowDebugVisuals 정적 플래그 신규 (false 기본·true 설정 시 즉시 노출)
- Spawn·AttachSprite·SpawnRange·SpawnHitboxDebugChild 4 위치 SpriteRenderer.enabled 정합
- GameObject 자체는 정상 spawn → LiveHitboxSync 등 부착 코드 무영향
작업 2 — 레벨업 카드 풀 5종 한정:
- SkillRuntimeFactory.AvailableCardIds HashSet (A02·A13·A04·A05·A_Laser)
- RandomDraw3 영역 화이트리스트 필터 추가
- 미완성 placeholder (A01·A03·A08·A14·A15) 카드 풀 제외
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
원인: MeleeAreaSpawner 이펙트 spawn 후 SetParent 미적용.
spawn 시점 world 좌표에서 freeze 되어 Player 전진 시
이펙트가 뒤로 밀려 보이는 현상.
박스(판정) 는 이미 Player 자식 부착이라 동조 정상.
정정:
- fxGo.transform.SetParent(inventory.transform, true)
- worldPositionStays=true 로 spawn 직후의 world 위치·rotation·scale 유지
+ Player 이동에 자동 동조.
검증 (Play 모드):
- Player x: -7 → -5 (Δ+2.0) 이동
- FX worldPos: -6.80 → -4.80 (Δ+2.0) ✓
- BOX worldPos: -7.00 → -5.00 (Δ+2.0) ✓
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
원인: Scene Assets/Scenes/Ingame.unity 에 이전 Edit Mode 측정 잔존 spawn 6건 영구 저장
- FX_Lightningball(Clone) × 3 (각각 ProjectileHitbox_Debug × 1 자식)
- FX_SLASH(Clone) × 2
- FX_Dragonfire(Clone) × 1
정정 1: Scene 잔존 spawn 6건 일괄 삭제 + Scene 재저장 (Ingame.unity).
정정 2: 모든 runtime spawn GameObject 에 HideFlags.DontSave 부여
(HitboxDebug · Projectile · LaserSpawner · MeleeAreaSpawner ·
LightningStrikeSpawner · ProjectileSpawner · EnemyStateComponents)
→ Scene 저장 시 무시 + Play→Stop 자동 cleanup.
검증: Play 모드 1회 발사 시 박스 1개만 spawn (LaserHitbox_Debug 1·
A13 ProjectileHitbox_Debug 1) · Stop 후 Scene 잔존 0건 확인.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PD 직접 지시 2026-05-12: "정상 동작 시점으로 되돌린 다음 다시 판단"
- 정상 동작 시점: 6c981ed → 16aa6f9 push 정합 (Variant 6개 SpriteRenderer 종별 idle01 override)
- 회귀 commit 22개 (16aa6f9..5f360ca) 일괄 환원
근본 원인 (Play 측정 확정):
- Player.Health.IsAlive=False·ResurrectPromptUI.showPrompt=True·Time.timeScale=0
- 시작 직후 Player가 Enemy와 충돌해 사망 → 부활 prompt가 timeScale=0 → 모든 frame 정지
- Enemy 코드 자체는 정상 (Rigidbody2D Kinematic·body 연결·CF useTriggers=False·IsGrounded=True)
- 본 PM이 5f360ca까지 누적한 Enemy 측 변경은 헛짚음
16aa6f9 시점 기반 위에 PD 요구 사항 (Visual 자식 분리·Variant 종별 patrol 동작·발판 가장자리 회피 등)을
한 단계씩 점진 재적용·각 단계 Play 실측으로 회귀 차단 예정.
PD: "6c981ed 정상 이동·뭐가 달라진건지 확인"
근본 (6c981ed vs HEAD diff 분석):
- fc35179 (2026-05-12)에서 UpdatePatrol 영역에 IsGrounded 가드 추가
if (control == null || !control.IsGrounded) { move.x=0; return; }
- 의도: 공중 낙하 시 patrol skip·자연 낙하 우선
- 실제: KinematicObject.FixedUpdate가 매 frame 호출되어 IsGrounded 갱신해야 동작
- Enemy spawn 직후 IsGrounded=False (default) → patrol skip → move=0
- FixedUpdate가 호출되어도 velocity 영역 패턴 영역
- 매 frame IsGrounded=False 가능성 영역 → 영구 정지 루프
6c981ed (정상 동작 시점):
- UpdatePatrol에 IsGrounded 가드 없음
- patrol 영역 항상 진행 → move=Clamp(dx, -1, 1) → ComputeVelocity →
targetVelocity → FixedUpdate → velocity·position 정상
fix:
- IsGrounded 가드 제거·control NULL 가드만 유지
- patrol 영역 항상 동작·KinematicObject 자연 낙하·gravity 영역 무관
- 공중 spawn Enemy도 patrol 영역 시도 (FixedUpdate gravity·Cast로 자연 정착)
회귀 영역 X:
- KinematicObject Awake 초기화·Update/FixedUpdate override·sr/anim/body 영역 정합
- cliffCheck·waitTimer·stuckTimer·TriggerReverse 영역 영역 X
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PD: "여전히 움직이지 않아·실측해보고 근본 원인 체크"
근본 (MCP Play 실측·자성 #12·#13):
- KinematicObject.OnEnable·Start·Update·FixedUpdate 모두 `protected virtual`
- AnimationController는 KinematicObject 상속하지만 override X
- Unity는 Component 정의된 magic method만 호출·base class virtual은 derived가 override 안 하면 호출 안 됨
- 결과: KinematicObject.OnEnable 호출 X → body=NULL·KinematicObject.FixedUpdate 호출 X → velocity 갱신 X·gravity 적용 X
- Enemy 자연 낙하 X·patrol 동작 X·영구 정지
검증:
- MCP Play 후 body field reflection 읽기 → NULL
- Rigidbody2D 컴포넌트 자체는 GetComponent OK·OnEnable이 body 설정 안 함
fix (AnimationController):
1. Awake 영역에 base 초기화 위임:
- body = GetComponent<Rigidbody2D>()·body.bodyType = Kinematic
- contactFilter.useTriggers/SetLayerMask/useLayerMask
2. Update·FixedUpdate override 추가:
- protected override void Update() { base.Update(); }
- protected override void FixedUpdate() { base.FixedUpdate(); }
- Unity가 AnimationController 인스턴스의 Update/FixedUpdate 호출 → base 실행
검증 후 (MCP Play):
- body=OK·IsGrounded=True·자연 낙하 정합 (pos.y=-2.5 등)
- Enemy 일부 발판 위 정착·일부 InfiniteHorizontalGround 영역 밖 무한 낙하 (별건)
회귀 영역 X:
- spriteRenderer/animator GetComponentInChildren·field initializer 가드 영역 영역 X
- KinematicObject 자체 영역 영역 X (다른 KinematicObject 상속 클래스는 별도 검증)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PD: "여전히 움직이지 않아·실측·근본 원인 체크"
근본 (MCP Play 실측·자성 #12·#13):
- AnimationController field initializer: PlatformerModel model = Simulation.GetModel<PlatformerModel>()
- Editor·Play mode 전환 시 Simulation.GetModel 호출이 인스턴스 컨텍스트 외부에서 실행
- field initializer 영역 NRE/Exception → Component 생성 자체 실패
- Awake/OnEnable 모두 호출 X
- 결과: spriteRenderer/animator/body 모두 NULL
- AnimationController.ComputeVelocity NRE → KinematicObject.Update/FixedUpdate 영역 실행되나
spriteRenderer.flipX/animator.SetFloat 호출 NRE → ComputeVelocity 영역 중단·targetVelocity 미설정
- velocity=0·move=0·Enemy 영구 정지
fix:
1. field initializer 폐기·Awake 영역 try-catch로 안전 초기화
- try { model = Simulation.GetModel<PlatformerModel>(); } catch { model = null; }
2. ComputeVelocity에서 spriteRenderer/animator NULL 가드
3. model NULL 시 jumpModifier=1·jumpDeceleration=0.5 default
검증 (MCP Play):
- 직전: sr=NULL·anim=NULL·body=NULL
- 정정 후: sr=OK·anim=OK·body=OK·IsGrounded=True
회귀 영역 X:
- spriteRenderer/animator GetComponentInChildren fallback 정합
- KinematicObject·EnemyController·patrol·cliffCheck 영역 영역 X
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PD: "몬스터들이 움직이지 않아"
근본 (MCP Play 실측):
- 4c5e33a에서 양측 cliff 분기에 _waitTimer = Random(1, 3) 추가
- 매 frame 양측 cliff 검사 → wait 재설정 → wait 가드 (line 283) return
- waitTimer가 0 도달하지 못함·patrol/cliffCheck 모두 차단·영구 정지
fix:
- 양측 cliff 영역 _waitTimer 재설정 폐기
- move.x=0·stuckTimer=0·return만 유지
- waitTimer는 patrol arrive 영역만 설정 (정상 사이클 유지)
회귀 영역 X:
- cliffCheck Trigger 제외·Enemy 영역 상대·IsGrounded 가드 영역 영역 X
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PD: "발판 가장자리 걸쳐 방향 전환 X·영구 대기"
근본:
- cliffCheckDistance=1.0 절대값 사용
- Type1 발판 폭 1.54·반=0.77 < cliffCheckDistance 1.0
- Enemy bounds.center가 발판 안에 있어도 ±1.0 unit footAhead는 양측 발판 밖
- → 양측 cliff 검출 → 영구 대기
fix:
- footAhead = bounds.center + moveDir * (bounds.extents.x + 0.15)
- Enemy 영역 가장자리 + 0.15 unit 마진 (Enemy 실제 발이 닿는 위치)
- Enemy 발판 안 → 전방만 cliff → TriggerReverse·정상 방향 전환
- Enemy 발판 가장자리 (extents 밖) → 양측 cliff → 제자리 대기 (좁은 발판)
회귀 영역 X:
- IsGrounded 가드·매 frame cliffCheck·2D AABB Player 피격 영역 영역 X
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PD: "발판과 같이 떨어질 수 있는 위치 가장자리에서 방향 바꿔서 정상 patrol·순찰 범위 너무 짧으면 제자리 대기"
근본:
- 전방 cliffCheck만 검사 → 발판 폭이 Enemy 영역 2배 미만일 때
- TriggerReverse → 반대편도 cliff → 다시 TriggerReverse → 좌우 영구 반복
fix:
- 전방 cliff 감지 시 반대편(-moveDir)도 추가 검사
- 전방만 cliff → TriggerReverse (방향 전환·정상 patrol)
- 양측 cliff → 발판 폭 좁음 → 제자리 대기 (move.x=0·waitTimer 재설정)
회귀 영역 X:
- IsGrounded 가드·매 frame cliffCheck·KinematicObject·2D AABB 영역 영역 X
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PD: "지시 수정 정합 X·변화 X"
근본 (MCP Play 직접 실측·자성 #13):
- Enemy 강제 Player 위치 이동 후에도 Intersects=False
- Bounds 분석:
- Enemy z=0 (Variant prefab default)
- Player z=1 (Scene 영역)
- Bounds.Intersects는 3D 비교 → Z 1 unit 차이로 항상 false
fix:
- Bounds.Intersects 폐기·2D AABB 직접 검사
- Mathf.Abs(deltaX) < (eExtents.x + pExtents.x) && deltaY 동일
- Z 좌표 무시·2D 게임 정합
회귀 영역 X:
- IsGrounded 조건·cliffCheck·KinematicObject·VisualBounds 영역 영역 X
- 영역 1 (cliffCheck 매 frame) 정합 유지
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PD 영역 1: 발판 위 Enemy 가장자리에서 방향 전환 X·한방만 바라보다 떨어짐
PD 영역 2: Player 피격 X
근본:
1. cliffCheck phaseCooldown 가드
- TriggerReverse 시 phaseCooldown=1.0s 설정·이 동안 cliffCheck 비활성
- 발판 끝 회피 후 1초간 cliff 미감지 → KinematicObject 진행 → 발판 밖 → 낙하
2. VisualBounds = Collider.bounds (직전 daad311)
- CapsuleCollider 작음 (0.33×0.33)·Player BoxCollider (0.77×1.02)
- Intersects 영역 너무 좁아 hit X
fix:
1. cliffCheck phaseCooldown 가드 폐기·매 frame 검사
- stuckTimer만 phaseCooldown 가드 유지 (좌우 반복 방지)
2. VisualBounds = Visual.SpriteRenderer.bounds 우선
- sprite 실제 시각 영역·Player 접촉 판정 정합
회귀 영역 X:
- IsGrounded 가드·TriggerReverse·KinematicObject 영역 영역 X
- Player IsGrounded 조건 유지 (밟기 X·점프 통과 정합)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>