작업 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>
작업 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>
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 실측):
- 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>
PD: "(나)안 — 어느 위치에 있든 절벽 회피·단 순찰 패턴 아닐 때 (공중 낙하 등) 상관 없음"
근본 정리:
- cliffCheck Raycast는 기존부터 정합 (Layer 0 발판·바닥 모두 hit)
- 공중 낙하 시 cliffCheck 적용되면 즉시 TriggerReverse → 자연 낙하 방해
fix:
- UpdatePatrol 시작 영역에 IsGrounded 가드
- control.IsGrounded=False (공중·피격 밀림·spawn 직후 낙하 등) → patrol·cliffCheck skip
move.x=0·stuckTimer=0·return
- KinematicObject 자연 낙하·바닥/발판 정착 → IsGrounded=True → patrol 재개·cliffCheck 정합
회귀 영역 X:
- 영역 1 (애니메이션 Clip path)·영역 2 (Collider bounds) 정합 유지
- TriggerReverse·MeasureSafeWalkDistance·KinematicObject 영역 영역 X
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PD 영역 1: 이동 애니메이션 재생 X
PD 영역 2: Player·Enemy 충돌 시 피해 X
근본:
1. 애니메이션 — Animator가 Visual 자식에 부착됨 + Clip path "Visual"
- Animator path는 Animator 기준 자식 경로 → "Visual/Visual" 자식 찾음·존재 X
- SpriteRenderer sprite curve 미적용 → 이동 시 Run sprite 교체 X
2. 피해 — VisualBounds = Visual.SpriteRenderer.bounds
- Visual 자식 분리 후 sprite bounds는 시각만·실제 Collider 영역과 별
- Player BoxCollider와 Visual.bounds.Intersects 정합 X
fix:
1. 35 Clip path "Visual" → "" (Animator·SpriteRenderer 동일 GameObject = Visual)
2. EnemyController.VisualBounds = _collider.bounds 우선 (CapsuleCollider 영역·실제 충돌)
영역 3 (발판 위 spawn) — PD 결정 대기 (가/나 분기).
회귀 영역 X:
- Variant Visual 자식 sprite override·AnimationController·KinematicObject 영역 영역 X
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PD 영역 1+3:
- "절벽에 닿으면 텔레포트" 회귀 — 이전 정상 방향 전환 동작
- "공중 spawn Enemy가 떨어지지 않고 이전 위치로 되돌아감"
근본 (단일):
- EnemyController.Update의 BT102 (line 360-376) 떨어짐 검출 텔레포트
- _isInitialized && y < _startY - fallThreshold(1.0) → 시작 위치 텔레포트
- 절벽 케이스: TriggerReverse 방향 전환 직후 fallThreshold 진입 → 텔레포트가 방향 전환을 덮어씀
- 공중 spawn 케이스: 떨어지는 즉시 fallThreshold 진입 → spawn 위치 복귀 무한 반복
fix:
- BT102 떨어짐 검출 텔레포트 영역 폐기
- 자연 낙하 + TriggerReverse 절벽 방향 전환만 동작
- 공중 spawn Enemy도 자연 낙하·KinematicObject Cast로 GameObject 위 정착
영역 2 (렉) 별건 — PD 측정 영역 필요·후속 안건.
회귀 영역 X:
- TriggerReverse cliffCheck Raycast 절벽 방향 전환 정합
- KinematicObject 자연 낙하·IsGrounded 정합
- Player·Enemy 충돌·발판 통과·Variant 영역 영역 X
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PD: "Enemy 닿으면 Player 피해 (밟기는 X·통과)"
근본:
- 직전 commit adcb1ac에서 Player↔Enemy 충돌 검출 자체 폐기
- Player 피해 경로 부재 → 복원 필요·단 밟기는 X
fix (EnemyController.Update):
- _cachedPlayer 캐싱 (Tag·fallback)
- Player.IsGrounded && VisualBounds.Intersects(Player.Bounds)
→ !IsInvulnerable 시 Player.health.Decrement (i-frame 적용)
- 공중 (점프) 상태는 통과·밟기 판정 X·EnemyDeath·Bounce X
회귀 영역 X:
- Enemy 사망 경로: Player 공격(Projectile·AttackHitbox)만 정합
- Player ↔ Enemy IgnoreCollision Awake 적용 정합·물리 통과
- Enemy ↔ Enemy IgnoreLayerCollision·발판 통과·scale·patrol 정합
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PD: "밟아서 적을 공격 가능한 기능 제거 (관련 기능 모두 삭제)"
PD: "몬스터는 Player 공격에만 피해를 받음"
변경:
1. PlayerEnemyCollision.cs·meta 삭제
- 점프+위 = EnemyDeath·Bounce 로직 폐기
- 지상 측면·아래 = i-frame 피격 로직 폐기
2. EnemyController.cs
- hitRangeX·hitRangeY·stompMinDy 필드 폐기
- Update 영역 Player ↔ Enemy Bounds.Intersects 검출 폐기
- PlayerEnemyCollision Schedule 폐기
- _cachedPlayer·_diagWasIntersecting·VisualBounds 사용처 폐기
- Player ↔ Enemy IgnoreCollision Awake 시점 적용 유지 (물리 통과 정합)
회귀 영역 X:
- Enemy 사망 경로: Player Projectile·AttackHitbox → Health.Decrement → Schedule<EnemyDeath> 정합 유지
- Player 피해 경로: 밟기 충돌 폐기·Enemy 공격 로직 후속 PD 지시 대기
- Enemy patrol·발판 통과·Enemy ↔ Enemy 통과·scale 1.19 정합
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PD: "몬스터도 발판 자유 통과"
PD: "몬스터 랜덤 변경"
근본 (MCP 자율 실측):
1. Enemy 발판 통과
- Layer 14 (Enemy) ↔ Layer 0 (발판) collide=True → Enemy 발판 영역
- PlatformEffector2D surfaceArc 170°·옆 영역 통과·발판 위 영역 영역
- fix: EnemyController.Awake 영역 PlatformEffector2D 영역 IgnoreCollision 일괄 등록
→ Enemy 16개 × 발판 17개 모두 IgnoreCollision·발판 영역 영역 X·자유 통과
2. 몬스터 랜덤
- 직전 MonsterRandomizer 폐기 (Animator 영역)
- 영역 영역 — 6 Override Controller·24 Clip 신규 영역 영역 영역 영역 영역
- 영역 — SpriteRenderer.color 6 random tint
White·Red·Green·Blue·Yellow·Purple·Awake 1회 random
- Animator (Idle·Run·Hurt·Death) 정합 유지·sprite swap X·tint만 영역
- 영역 영역 영역·영역 영역 영역 영역
회귀 영역 X:
- One-Way Platform·Player 영역 영역 X·Camera·Wall LayerMask·Composite 정합
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PD 보고 2026-05-08: 일부 몬스터 이동 X.
Editor.log [Enemy@N] 직접 read 결과 — 16건 중 8~9건 maxR=0/maxL=0:
- footPos.y = bounds.min.y - 0.5f 영역 발판 cell 영역 미정합
- 인스턴스마다 collider bounds·sprite bounds 영역 변동
- startTm = NULL → maxR/maxL = 0 → patrol 거리 0 → 무한 정지
근본 정정: 다단 fallback 채택
- sprite/collider/transform 3 영역 각 후보
- 다중 offset (-0.1·-0.3·-0.5·-0.7·-1.0)
- 첫 HasTile cell 채택
- Debug.Log 강화 (startY·colliderFoot·spriteFoot·chosenFootY)
PD 보고 (2026-05-08): 1) 몬스터 이동 X / 2) 비밀통로 막힘
본 PM 23회+ 가설 누적 부정확 자인.
진단 (BT108):
- Debug.Log 추가 — Start 시점 _startX·_startY·_maxRightRange·_maxLeftRange 출력
- PD Refresh+Play 시각 검증 후 본 PM Editor.log direct read 의무
비밀통로 막힘 진단:
- BT101 영역 PD Foreground TilemapCollider Object.Destroy 영역 정합 검증 (line 80)
- 가능 원인: AutoForeground 영역에 PD 통로 Tile 영역 누적 (이전 Play 영역 결과 Scene yaml 영구) → Drop-Through 패턴 영역
- 또는: 본 PM 자동 분류 영역에서 통로 Tile 영역이 자동 이동됨
본 PM 능력 한계 자인:
- 측정·검출·재배치 영역 23회 가설 누적
- PD 결정 영역 권고:
- 옵션 1: Debug.Log 결과 보고 후 본 PM 후속 진단
- 옵션 2: 본 PM 자동 patrol 영역 폐기·PD Editor 영역 직접 PatrolPath 부여
- 옵션 3: BT47 시점 git checkout 영역 회귀
PD 근본 진단 (2026-05-08): "절벽 체크 로직이 잘못된 것이 근본원인" + 공중 부유 발생
본 PM 22회+ 가설 누적 부정확 자인. PD 근본 진단 정합 — Raycast 영역 자체 부정확.
정정 (BT107):
1. BT106 y 강제 고정 영역 폐기 (공중 부유 원인)
2. MeasureSafeWalkDistance 영역 = Tilemap cell 기반 재설계:
- GameObject.Find('Level') + 'AutoForeground' → groundTilemaps 영역
- Enemy 발 아래 cell = 시작 cell (Tilemap.WorldToCell)
- 좌·우 연속 Tile 영역 끝 영역 검색 (cell + Vector3Int.left/right)
- HasTileInAnyTilemap 검사 (Level + AutoForeground)
- 마지막 Tile cell center 영역까지 거리 - 0.5m margin
효과:
- Raycast 영역 부정확 영역 폐기 (Tile data 직접 사용)
- Tile cell 단위 정확 영역 측정 → patrol 영역 정확
- 시작 cell 발판 X 시 = 0 반환 (재배치 영역 BT104에서 처리)
- 공중 부유 영역 차단 (BT106 폐기)
PD 명시 (2026-05-08): "여전히 떨어졌다 복귀하는 모습 잔존·수정할 수 없어?"
본 PM 측정·검출 영역 22회 가설 누적 부정확. 근본 해결:
정정 (BT106):
- UpdatePatrol 시작 영역에 y 영역 강제 고정:
- |transform.y - _startY| > 0.1f 시 = 즉시 _startY 복귀
- transform.position + body.position 동시 set
- control.velocity.y = 0 강제 (gravity 영향 차단)
효과:
- Enemy 영역 매 frame _startY 영역에 영구 고정 → 떨어짐 영역 0.1m 이상 발생 X
- BT102 텔레포트 영역 = 보조 fallback (트리거 X 가설)
- patrol 영역 = X 영역만 이동 (Y 고정)
- 시각상 = 자연 patrol (Y 변화 X·발판 외 영역 도달 X)
부수 효과:
- Enemy 영역 = 발판 위 영역 영구 (gravity X)
- 다른 높이 발판 patrol 영역 X (시작 위치 Y 영역만)
PD 보고 (2026-05-08):
1. 밟기 처치 Enemy 맵에서 떨어짐 → 제자리 사망 모션
2. 떨어짐 잔존 → 낭떠러지 닿기 전 방향 전환
정정 (BT105):
1. EnemyDeath.cs:
- body.simulated = false 추가 (Rigidbody2D 물리 미참여 → gravity X)
- = 제자리 사망 (death 애니메이션 + 1초 Destroy)
2. EnemyController.cs MeasureSafeWalkDistance:
- 안전 margin 0.5m → 2.0m
- patrol _maxRightRange/_maxLeftRange = 측정 거리 - 2.0m
- = patrol 영역이 절벽에서 항상 2m 이상 영역 → 절벽 도달 X
효과:
- 밟기 사망 = 제자리 사망 (떨어짐 X·시각 자연 모션)
- patrol 영역 = 절벽에서 2m 안전 영역까지 → 절벽 영역 도달 X
PD 보고 (2026-05-08):
1. 떨어졌다 복귀 반복 (시작 위치 발판 X 영역 가설)
2. 밟아서 처치한 Enemy 죽지 X·잔존
정정 (BT104):
1. EnemyDeath.cs:
- enemy._collider.enabled = false (기존)
- enemy.control.enabled = false (기존)
- **enemy.enabled = false** 추가 (EnemyController patrol 영역 정지)
- **animator.SetTrigger('death')** 추가 (death 애니메이션)
- **Object.Destroy(enemy.gameObject, 1f)** 추가 (1초 후 영역 제거)
2. EnemyController.Start (재배치):
- 시작 위치 발 영역 Raycast → groundUnder X 시 = 발판 X
- 좌·우 0.5m 간격 50m 영역 검색 → 가까운 발판 영역 발견 시 = transform + _startX 재배치
- _startY = 재배치 후 갱신
효과:
- 밟기 처치 = enabled=false + death 애니메이션 + 1초 후 Destroy → 정상 사망
- Enemy 시작 위치 발판 X 시 = 가까운 발판 자동 재배치 → 떨어짐 X
- BT102 텔레포트 영역 = 보조 영역 (재배치 후 트리거 X)
PD 명시 (2026-05-08): "미리 생성하는 시점에 맵 탐색·자신이 탐색 가능한 범위 결정"
진단:
- BT94/BT97 영역 측정 영역 0.5m 간격 + groundY = transform.y - 0.34f 추정
- 0.5m 미만 영역 절벽 검출 X 가능
- groundY 추정 영역 Capsule offset 영역과 정합 X 가능
정정 (BT103):
- groundY = _collider.bounds.min.y + 0.05f (Capsule 발 영역 정확)
- 간격: 0.5m → 0.1m (촘촘 측정)
- 안전 margin: 1.5m → 0.5m (실제 절벽 영역까지 정확)
- Start 시점 1회 측정 (BT97 영역 그대로·AfterSceneLoad 후·AutoForeground Tile 활성)
효과:
- Capsule 발 영역 정확 기준 측정 → 정확한 절벽 거리
- 0.1m 간격 = 0.5m 미만 절벽도 검출
- 0.5m margin = 절벽 영역에서 0.5m 안전 영역까지 patrol → 실제 절벽 영역 도달 X
- BT102 텔레포트 영역 = 측정 영역 정확 시 X 트리거 → 시각상 자연 patrol
- 1회 측정 (Start) = 최적화 (매 frame 측정 X)
PD 명시 (2026-05-08): "몬스터의 투명벽을 삭제하고 몬스터가 낭떠러지로 떨어지지 않도록 할 방법을 찾아봐"
변경:
1. GameOptimizer.cs:
- Init() Physics2D.IgnoreLayerCollision(13, 18) 영역 폐기
- SetupCliffWalls·CreateCliffWall·HasTileInAny 영역 폐기 (BT99/BT100/BT101 영역 제거)
- SetupJumpThroughPlatforms 끝에 기존 CliffWalls GameObject Object.Destroy (정리)
2. EnemyController.cs:
- _startY 영역 신규 (Awake 시점 transform.position.y)
- fallThreshold Inspector 영역 신규 (기본 1.0m)
- BT98 R1 영역 (발 자체 Raycast) 폐기 → BT102 y 검출 영역으로 대체
- 매 frame Update: transform.position.y < _startY - fallThreshold 시:
- 시작 위치 (startX, startY) 텔레포트 (transform + body 동시)
- velocity = Vector2.zero
- patrolPhase 0·SetNextPatrolTarget·cooldown·waitTimer·stuckTimer 영역 초기화
효과:
- 투명벽 영역 (Layer 18·CliffWalls GameObject) 완전 폐기
- Enemy 영역 떨어진 후 = 즉시 시작 위치 복귀 (영구 떨어짐 X)
- 단순·근본 방법 (algorithm 영역 부정합 잔존 시도 안전 보장)
- 시작 위치 = 안전 영역 가설 (PD가 Enemy 영역 발판 위 배치)
PD 강한 어조 (2026-05-08): "여전히 몬스터가 낭떠러지로 떨어져"
본 PM 17회 가설 누적 부정확 자인. R1 방어 영역 즉시 적용:
매 frame Update 영역 마지막에 발 영역 자체 절벽 검사:
- footHere = (_collider.bounds.center.x, _collider.bounds.min.y + 0.05f)
- Raycast Layer 0+16 cliffCheckDepth 영역
- groundUnder.collider == null 시 = 발 영역 자체 절벽
- 시작 위치 텔레포트 즉시 복귀:
- transform.position + body.position 동시 set
- control.velocity = Vector2.zero (낙하 차단)
- patrolPhase = 0, SetNextPatrolTarget, cooldown 활성, waitTimer 1~3초
효과:
- 본 PM 알고리즘 영역 부정합 잔존 시도 = 떨어짐 검출 즉시 시작 위치 복귀
- 영구 떨어짐 X 보장 (방어 영역)
- 시작 위치 = 안전 영역 가설 (PD가 Enemy 영역 발판 위 배치)
후속 의무:
- PD Refresh+Play 시각 검증 (떨어짐 차단 정합)
PD 보고 (2026-05-08): 벽 영역 자연스러움 ✅·낭떠러지 떨어짐 잔존
진단:
- BT94 MeasureSafeWalkDistance = Awake 시점 호출
- AutoForeground Tile data = RuntimeInitializeOnLoadMethod(AfterSceneLoad) 시점 활성
- Unity execution order: Awake → AfterSceneLoad → Start
- = Awake 시점 = AutoForeground Tile 영역 미처리 → MeasureSafeWalkDistance 영역 = AutoForeground 발판 검출 X
- = 안전 거리 영역 부정확 (실제 절벽 영역과 다름) → patrol 영역 절벽 도달 → 떨어짐
정정 (BT97):
1. _isInitialized 영역 신규 (Awake = false / Start = true)
2. Awake 시점 = _startX·_lastX·patrolPhase 영역만 초기화 (측정·target X)
3. Start 시점 (AfterSceneLoad 이후) MeasureSafeWalkDistance 호출 + SetNextPatrolTarget + _isInitialized=true
4. UpdatePatrol 영역 시작에서 !_isInitialized 시 control.move.x = 0 + return (patrol 비활성)
효과:
- AutoForeground Tile 영역 활성 후 안전 거리 측정 → 정확한 절벽 거리
- patrol 영역 = 안전 거리 cap 정확 → 절벽 영역 도달 X
- 측정 전 1 frame patrol 비활성 = 안전
PD 보고 (2026-05-08): "몬스터가 벽 가장자리에 닿으면 밀려나는 현상·방향 튼 상태로 뒤로 밀려남"
진단:
- BT95 velocity.x = -moveDir * maxSpeed = 1 frame만 적용 (KinematicObject FixedUpdate 영역에서 velocity.x = targetVelocity.x로 덮어씀)
- transform.position 영역 ↔ body.position 영역 비동기 = KinematicObject 영역 부정합 → 미세 영역 잔존
정정 (BT96):
1. _body Rigidbody2D 영역 캐싱 (Awake)
2. TriggerReverse(moveDir, pushDistance) 함수 신규:
- phase+2 + SetNextPatrolTarget
- transform.position + body.position 동시 push (반대 방향 0.2~0.3m)
- velocity.x = -moveDir * maxSpeed + move.x = -moveDir
- cooldown 1.0초 활성
3. 절벽 검출 시 TriggerReverse(moveDir, 0.3f)
4. 벽 정지 (stuckTimer) 시 TriggerReverse(moveDir, 0.2f)
효과:
- transform + body 동시 set = KinematicObject body 영역 정합 = 비동기 영역 부정합 차단
- 즉시 반대 방향 0.2~0.3m push = 가장자리 영역에서 즉시 멀어짐
- velocity.x 큰 속도 = 다음 frame 안정 이동
- 1초 cooldown = 충분 영역 멀어진 후 재검출
PD 명시 (2026-05-08):
1. 가장자리 좌우 반복 잔존
2. 모든 Enemy의 PatrolPath 제거 + 자동 알고리즘만
정정 (BT95):
1. Scene Ingame.unity Enemy 인스턴스 path 영역 m_Modifications 12건 제거
- Python 자동 영역 (PrefabInstance 영역에서 propertyPath: path 영역 삭제)
- PatrolPath GameObject 영역은 Scene 잔존 (영향 X·EnemyController 영역 미참조)
2. EnemyController.cs:
- PHASE_COOLDOWN 0.5 → 1.0 (긴 영역·좌우 반복 영구 차단)
- 절벽·벽 검출 시 velocity.x = 0 → velocity.x = -moveDir * maxSpeed (즉시 반대 방향 큰 속도)
- control.move.x = -moveDir 직접 (1 frame 지연 차단)
효과:
- velocity 영역 즉시 반대 방향 큰 속도 → 가장자리에서 빠르게 멀어짐
- 1초 cooldown = 충분 영역 멀어진 후 검출 활성 → 좌우 반복 X
- PatrolPath path 영역 m_Modifications 제거 = 자동 patrol 영역만 사용 (PD 명시)
PD 보고 (2026-05-08): 1) 벽 가장자리 좌우 반복 / 2) 좁은 영역 생성 Enemy 떨어짐
진단:
- 좌우 반복: phase 전환 직후 1~2 frame 미세 정지 → stuckTimer 트리거 → 또 phase+2 → 매 frame 반복
- 좁은 영역: patrol 거리 50~75m > 시작 위치 ↔ 절벽 거리 → 시작 즉시 절벽 영역 도달 → 떨어짐
정정 (BT94):
1. _phaseCooldown 영역 신규 (0.5초)
- phase 전환 직후 절벽·벽 검출 비활성
- cooldown 동안 Enemy 영역 반대 방향 이동 (충분 영역) → 안정
2. 시작 시 좌·우 walk 영역 안전 거리 측정 (MeasureSafeWalkDistance)
- Awake 시점 0.5m 간격 Raycast 영역 절벽 검출까지 거리 측정
- patrol 거리 = min(설정 거리, 측정 거리 - 1.5m 안전 margin)
- _maxRightRange·_maxLeftRange 영역
3. SetNextPatrolTarget — _maxRightRange/_maxLeftRange cap 적용
효과:
- 좌우 반복 = phase cooldown 0.5초 = phase 전환 직후 검출 X → 안정
- 좁은 영역 = 시작 시 안전 거리 측정 → patrol 영역 절벽 영역 도달 X
- 일반 영역 = 영향 X (안전 거리 측정 ≥ patrolMaxRange)
PD 보고 (2026-05-08): 가장자리 밀림·갑자기 바닥 떨어짐·낭떠러지 돌진
진단:
- BT92 transform.position += 직접 set = KinematicObject body.position 영역과 충돌
- = body.position ↔ transform.position 비동기 → 비정상 위치 → 갑자기 떨어짐
- BT92 stuckThresholdTime 0.3 = 가장자리 밀림 누적 영역 발생
정정 (BT93):
1. transform.position push 폐기 (cliffSafePushDistance Inspector 영역도 폐기)
2. 절벽·벽 검출 시 control.velocity = (0, velocity.y) 강제
- velocity.x 영역 즉시 0 = 관성 차단 = 발 절벽 진입 X
- velocity.y 보존 (gravity·점프 영역)
3. stuckThresholdTime: 0.3 → 0.15 (150ms·밀림 누적 차단)
효과:
- KinematicObject body 영역 정합 (transform 직접 set X)
- 절벽 영역 = velocity.x 즉시 0 + 반대 방향 control.move.x → 다음 frame 반대 이동
- 벽 가장자리 = 150ms 정지 후 phase+2 + velocity.x 0
- 이상 떨어짐 영역 차단
PD 보고 (2026-05-08): 1) 벽 가장자리 좌우 반복 / 2) 낭떠러지 돌진 떨어짐
진단:
- 좌우 반복: stuckTimer 50ms 영역이 phase 전환 직후 1 frame 정지를 정지로 인식 → 매번 트리거 → 부들부들
- 낭떠러지: cliffCheckDistance 0.8m + 1 frame 지연으로 발 영역 절벽 진입 → KinematicObject 영역 발 아래 충돌 X → gravity 떨어짐
정정 (BT92):
1. stuckThresholdTime: 0.05 → 0.3 (300ms — phase 전환 직후 미세 정지 영역 무시)
2. cliffCheckDistance: 0.8 → 1.0 (1m 일찍 검출)
3. cliffSafePushDistance Inspector 영역 신규 (기본 0.15m)
4. 절벽 검출 시: transform.position += (-moveDir * 0.15m) 즉시 안전 영역 push
- 1 frame 지연 영역에서 발 영역 절벽 진입 차단
- 이후 phase+2 + control.move.x = 반대 방향
효과:
- 벽 가장자리 = stuckTimer 300ms 임계값 → phase 전환 후 안정 → 좌우 반복 X
- 절벽 영역 = 1m 앞 검출 + transform 즉시 안전 push → 발 영역 절벽 X → 떨어짐 X
- arrive·일반 patrol 영역 그대로
PD 보고 (2026-05-08): 1) 낭떠러지 떨어짐 잔존 / 2) 부들부들 / 3) 자연스러운 patrol
진단:
- BT86 cliffCheckDistance 0.3 = 발 외부 0.017m → 너무 가까움
- 절벽 영역 도달 직전 검출 → 다음 frame 발 영역 절벽 진입 + waitTimer 1~3초 정지 → gravity로 떨어짐
- 벽 영역 = stuckTimer 50ms → phase+2 + waitTimer 정지 → 부들부들
정정 (BT91):
1. cliffCheckDistance: 0.3 → 0.8 (더 일찍 검출·발 외부 0.5m)
2. cliffCheckDepth: 1.5 → 2.0 (더 깊게)
3. 절벽 검출 시: phase+2 + 즉시 반대 방향 이동 (waitTimer X)
- control.move.x = Mathf.Clamp(dx_new, -1, 1) 즉시 적용
4. 벽 정지 (stuckTimer 50ms) 시: phase+2 + 즉시 반대 방향 이동 (waitTimer X)
5. patrol arrive 시점만 waitTimer 1~3초 대기 (안전 영역만 정지)
효과:
- 절벽 영역 = 더 일찍 검출 + 즉시 반대 이동 (정지 X·떨어짐 X)
- 벽 영역 = 즉시 반대 이동 (부들부들 X)
- arrive 시점만 자연스러운 1~3초 대기
- patrol 사이클: 이동 → arrive → 1~3초 idle → 이동 → arrive → idle (자연스러움)
- 위험 영역 (벽·절벽) = 즉시 반응 (정지 X)
PD 보고 (2026-05-08): "몬스터들이 전혀 이동하지 않고 있어"
진단:
- BT89 수평 Raycast = bounds 외부 0.05+0.1m = 같은 Tile cell (1m) 영역 검출 → 거짓 양성
- 매 frame phase+2 + waitTimer 1~3초 → 영구 대기 사이클 → 정지
정정 (BT90):
- 수평 벽 Raycast 영역 폐기 (BT85 영역 회복)
- wallCheckDistance Inspector 영역 폐기
- stuckThresholdTime 0.1 → 0.05 (50ms·거의 즉시)
- stuckTimer 영역 = 벽 정지 50ms 후 phase+2 + waitTimer 1~3초
- 절벽 검출·waitTimer 영역 그대로
효과:
- 정상 이동 시 stuckTimer 누적 X (frame당 ~0.058m > 0.02m 임계값)
- 벽 정지 시 50ms 후 phase+2 (거의 즉시)
- 절벽 영역 = 즉시 phase+2 + 대기
- arrive·벽·절벽 = 1~3초 대기 후 다음 phase
PD 보고 (2026-05-08):
1. 벽 영역 버벅대다 밀림 → 즉시 반대 방향 의무
2. patrol 1회 후 1~3초 대기 패턴
정정 (BT89):
1. UpdatePatrol() 영역 분리 — patrol·벽·절벽·대기 통합
2. 수평 벽 Raycast 부활:
- bounds 외부 (halfWidth + 0.05m) 시작
- distance 0.1m (총 0.15m·인접 Tile X)
- 검출 시 phase+2 즉시 전환 (stuckTimer 100ms 영역 폐기 — 즉시)
3. 절벽 검출:
- 검출 시 phase+2 즉시 전환
4. _waitTimer 영역 신규:
- patrol arrive 시 Random.Range(1, 3)초 대기
- 벽 검출 시 동일 (대기 후 반대 방향 patrol)
- 절벽 검출 시 동일
- 대기 중 control.move.x = 0
5. stuckTimer 보조 영역 잔존 (수평 Raycast 미감지 fallback)
6. Inspector 노출: wallCheckDistance·waitMinTime·waitMaxTime
효과:
- 벽 영역 = 즉시 반대 방향 (Raycast 검출 frame에 phase+2)
- 절벽 영역 = 즉시 반대 방향
- patrol arrive·벽·절벽 = 1~3초 random 대기 후 다음 phase
- 대기 중 = control.move.x = 0 (Idle)
- 시각상 자연스러운 patrol 패턴
PD 보고 (2026-05-08): "이번에는 몬스터들이 다시 낭떠러지로 떨어져버렸어 (이전 버전은 떨어지지 않음)"
진단:
- BT86 절벽 검출 = phase+1 (= 시작 위치 복귀)
- BT87 patrol 거리 절반 (50~75) → 시작 위치 ↔ 절벽 거리 작아짐
- 시작 위치 복귀 도중 = 절벽 영역 도달 → 떨어짐
정정 (BT88):
- 절벽 검출 시: phase+2 (반대 방향 patrol·시작 위치 복귀 폐기)
- 벽 정지(stuckTimer) 시: phase+2 (동일·즉시 반대 방향)
phase 전환 영역:
- phase 0 (우측 out) → phase 2 (좌측 out)
- phase 1 (시작 복귀·우측에서) → phase 3 (시작 복귀·좌측에서)
- phase 2 (좌측 out) → phase 0 (우측 out)
- phase 3 (시작 복귀·좌측에서) → phase 1 (시작 복귀·우측에서)
효과:
- 절벽 영역 = 즉시 반대 방향 patrol (시작 위치 영역 X)
- 벽 충돌 = 동일 (즉시 반대 방향)
- 시작 위치 절벽 근처 영역 = 안전
PD 보고 (2026-05-08):
1. 벽 충돌 후 움찔거리다 방향 전환 어색
2. 순찰 거리 너무 멀어 절반으로
정정 (BT87):
1. stuckThresholdTime: 0.3 → 0.1 (100ms·움찔 차단·즉시 방향 전환)
2. patrolMinRange: 100 → 50 / patrolMaxRange: 150 → 75 (절반)
효과:
- 벽 충돌 시 100ms 정지 → 즉시 다음 phase (반대 방향 patrol)
- 순찰 거리 = 시작 위치 기준 좌/우 random 50~75 왕복
PD 보고 (2026-05-08):
1. 몬스터 이동속도 너무 빨라 2배 느리게
2. 벽 가장자리 미세 밀림 → 낭떠러지 떨어짐
3. 낭떠러지 근처 생성 Enemy 이동 중 떨어짐
정정 (BT86):
1. AnimationController maxSpeed 7 → 3.5 (Enemy.prefab):
- frame당 이동 거리 ~0.117m → ~0.058m (2배 느림)
2. stuckTimer 영역 임계값 정정:
- 거리: |transform.x - _lastX| < 0.01 → 0.02 (미세 밀림 검출)
- 시간: stuckThresholdTime 0.5 → 0.3 (빠른 phase 전환)
- stuckMoveThreshold Inspector 영역 신규
3. 절벽 검출 영역 정정:
- cliffCheckDistance: 0.6 → 0.3 (더 빠른 검출·낭떠러지 근처 보호)
- 시작 위치 복귀 영역 폐기 → 다음 phase 강제 (시작 위치도 절벽 가능 가설)
효과:
- Enemy 이동속도 2배 느림
- 미세 밀림 (< 0.02m/frame) = stuckTimer 누적 → 0.3초 후 phase 전환
- 절벽 영역 = 즉시 다음 phase (반대 방향 patrol) — 시작 위치 복귀 X
- 낭떠러지 근처 생성 Enemy = 절벽 영역 검출 → 즉시 반대 방향
PD 보고 (2026-05-08):
1. 몬스터 바닥 뚫고 나옴 (이미지 첨부)
2. 몬스터 여전히 이동 X
진단:
- 버그 1: sprite 발 영역(transform.y - 0.63·sprite half) ↔ Capsule bounds.min.y(transform.y - 0.39) = 0.24m 차이. Capsule 영역 위 Tile 표면 → sprite 영역 발이 0.24m 침투 → 시각상 침투
- 버그 2: BT83/BT84 수평 벽 Raycast 영역(bounds 외부 + 0.5m)도 옆 Tile (평지 인접) 검출 → 거짓 양성 → 매 frame phase 강제 → 모든 Enemy 정지
정정 (BT85):
1. transform.y 추가 +0.3 (Enemy.prefab 1.532→1.832 + Scene 인스턴스 19건 +0.3)
2. EnemyController.cs:
- 수평 벽 Raycast (BT83/BT84 영역) 폐기
- wallCheckDistance Inspector 영역 폐기
- stuckThresholdTime: 0.3→0.5 (BT81 영역 회복·정상 이동 미세 영역 거짓 양성 차단)
- 절벽 검출 영역 그대로
- stuckTimer 영역 그대로 (벽 정지 시 0.5초 후 다음 phase 강제)
효과:
- 시각상 발 영역 침투 X (transform.y +0.3 → 총 +0.8 from 원본)
- 정상 patrol 영역 = stuckTimer 영역 0 (frame당 transform.x 변경 큰 영역)
- 벽 영역 정지 시 = stuckTimer 영역 0.5초 누적 → 다음 phase 강제
- 절벽 영역 = footAhead Raycast 영역 (Layer 0+16) 검출 → 시작 위치 복귀
후속 의무:
- PD Refresh+Play 시각 검증
PD 보고 (2026-05-08): "이제는 모든 몬스터가 이동(순찰 패턴)하지 않고 있어"
근본 원인:
- BT83 wallOrigin = bounds.center.x + moveDir * 0.05 = Capsule bounds 내부
- Enemy가 Foreground Tile 위 영역에 서있을 때 = 인접 Tile (같은 Layer 16) Raycast 검출
- = 거짓 양성 → 즉시 다음 phase 강제 → 매 frame 반복 → patrol X
정정 (BT84):
- wallOrigin.x = bounds.center.x + moveDir * (halfWidth + 0.05f)
- = Capsule bounds 외부 영역 시작 → 자기 영역(또는 같은 Tile) 검출 X
- 절벽 검출 영역 그대로 (footAhead 영역은 발 앞 cliffCheckDistance·다른 영역)
효과:
- Enemy 영역 자기 검출 X = 거짓 양성 차단
- 벽 영역 정상 검출 (외부 영역만)
- patrol 정상 작동
후속 의무:
- PD Refresh+Play 시각 검증
PD 보고 (2026-05-08): "몬스터가 벽 가장자리에서 이동하지 못하게 되면 밀려나면서 결국 낭떠러지로 떨어지고 있어"
진단:
- 벽 가장자리 정지 시 미세 밀림(< 0.01 영역) → stuckTimer 누적 X
- 다음 phase 전환 X → 미세 밀림 누적 → 결국 절벽 영역 도달 → 떨어짐
- BT81 stuckTimer 영역만으로 부족 (정지 임계값 0.01 미달 미세 밀림 미감지)
정정 (BT83):
1. wallCheckDistance 영역 신규 (Inspector 노출·기본 0.5)
2. 수평 벽 Raycast 검출 추가:
- 발 영역 horizontal (moveDir 방향) Raycast Layer 0+16
- 벽 검출 시 즉시 다음 phase 강제 (stuckTimer 영역과 분리)
3. stuckThresholdTime: 0.5 → 0.3 (빠른 영역 전환)
효과:
- 벽 영역 즉시 검출 + 다음 phase = 정지·밀림 영역 도달 X
- 절벽 영역 도달 X = 떨어짐 차단
- stuckTimer 영역 = 보조 (벽 검출 + 미감지 fallback)
후속 의무:
- PD Refresh+Play 시각 검증
PD 보고 (2026-05-08):
1. 벽에 닿은 후 멈춰있음 (이동 거리 미달 + 벽 충돌 → dx 영역 큰 값 잔존 → 영구 정지)
2. 낭떠러지 떨어짐 (절벽 검출 거짓 양성 또는 미검출)
진단:
- 버그 1: BT80 코드는 dx<arriveThreshold 시점만 다음 phase. 벽 충돌 시 KinematicObject body.Cast 차단 → transform.x 정지 → dx 영역 잔존 → phase 전환 X
- 버그 2: groundLayerMask=~0 (모든 layer) = Enemy/Player Collider 거짓 양성 → 절벽 영역 미검출
정정 (BT81):
1. stuckTimer 영역 신규:
- _lastX·_stuckTimer 추가
- 매 frame |transform.x - _lastX| < 0.01 시 _stuckTimer 누적
- _stuckTimer > 0.5초 시 = 벽 정지 → 다음 phase 강제
2. groundLayerMask: ~0 → (1 << 0) | (1 << 16) — Layer 0 (지면) + Layer 16 (발판)만
3. cliffCheckDepth: 0.8 → 1.5 — 지면 검출 깊이 증가
4. Inspector 노출: stuckThresholdTime 신규 (기본 0.5초)
효과:
- 벽 정지 시 0.5초 후 자동 phase 전환 (다음 patrol 방향 시도)
- 절벽 검출 = Layer 0/16만 = Enemy/Player 거짓 양성 차단
- 시작 위치 복귀 영역 그대로
후속 의무:
- PD Refresh+Play 시각 검증