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: "몬스터 방향 전환 시 이미지 잘못 출력"
근본:
- AnimationController에 [RequireComponent(SpriteRenderer, Animator)] 잔존
- Enemy.prefab root SR·Animator 제거 시도가 RequireComponent에 의해 차단
- Variant 6 모두 root SpriteRenderer 잔존·AnimationController.spriteRenderer = root
- ComputeVelocity의 flipX = root에 적용·실제 보이는 Visual 자식 SpriteRenderer 영향 X
- 방향 전환 시 sprite flip 안 됨
fix:
1. AnimationController.cs — [RequireComponent] 제거
2. Enemy.prefab base — root SpriteRenderer·Animator 폐기
3. Variant 6 prefab 재생성 (이전 Variant 폐기·신규)
- Visual 자식 SpriteRenderer.sprite·Animator.runtimeAnimatorController override
4. Scene 16 Enemy instance root SR·Animator 잔존 폐기
5. 결과: AnimationController.spriteRenderer = GetComponentInChildren<SpriteRenderer>() = Visual.SpriteRenderer
flipX·sprite·Animator 모두 Visual 자식 단일화
회귀 영역 X:
- Visual 자식 SpriteRenderer·Animator·OverrideController 정합
- KinematicObject·Collider·EnemyController patrol 영역 영역 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: "이동·죽음·히트 애니메이션 재생 X → 잘 나오도록 수정"
PD: "맵 전체 patrol → 자신 주위 적절 범위 patrol"
근본 (MCP 자율 실측):
1. 애니메이션 — MonsterRandomizer.Awake line 28 `anim.enabled = false`
- Animator 비활성 → AnimationController.SetFloat("velocityX", ...) 영향 X
- Idle/Run/Hurt/Death state 영역 영역 X·sprite 수동 idle만
- fix: anim.enabled=false 제거·sprite 수동 영역 폐기·Animator Clip 정합
- Enemy.controller transition·parameter 정합 (직전 entry 7 fix 영역)
2. patrol 범위 — Enemy.prefab patrolMin=50·Max=75 (맵 전체)
- Camera ortho 5.0·camWidth 17.78·주위 영역 영역 5~10 unit 정합
- fix: patrolMin=5·Max=10 (Enemy.prefab 영역·Scene 16 instance 자동 반영)
회귀 영역 (Minor 사전 고지):
- 6종 random idle 영역 영역 영역 X — 모든 Enemy 동일 외형
- 6종 random visual 다양성 영역 후속 안건 (Sprite 동적 randomization·6 controller·SubStateMachine)·본 fix 영역 외
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
근본 원인 (MCP 직접 진단):
- Wall = TilemapCollider2D (Layer 0 Level·Layer 16 AutoForeground)·isTrigger=false·Rigidbody2D 부재 (Static)
- Projectile = CircleCollider2D·isTrigger=true·Rigidbody2D 부재 (Static)
- Static (Trigger) ↔ Static (Solid) → OnTriggerEnter2D 발화 X (Unity 2D Physics 표준)
→ 직전 fix `Layer 0/16 isWall` 분기 영역 호출 X
해결:
- Projectile.Update 영역 매 frame Physics2D.OverlapPoint(transform.position, WallLayerMask) 영역 검출
- WallLayerMask = (1 << 0) | (1 << 16) — Layer 0 Default·Ground + Layer 16 Foreground·발판
- hit != null → SelfDestruct (영역 영역 영역 영역 영역 영역 정합)
- OnTriggerEnter2D 영역 isWall 분기 영역 영역 영역 (영역 영역 영역 영역 영역)
진단 Debug.Log 회수 (이전 추가분).
PD 보고 (2026-05-10): "벽에 닿은 투사체가 여전히 소멸하지 않아"
PD #1 (적이 죽지 않음) — 본 PM MCP 직접 검증 결과:
- Enemy maxHP 20·damage 5·4hit kill 영역 영역
- Schedule<EnemyDeath> 영역 호출 영역 영역 — Execute 영역 호출 영역 정합 (직접 검증)
- → Editor 영역 영역 영역 영역 영역 영역 영역 X (runInBackground·Game window) — PD 영역 직접 Play 영역 검증 영역 영역
PD 지시 (2026-05-10):
1. 투사체 종류 영역 일정 거리 영역 소멸 (Camera width × 1.5)
2. 레이저 외 투사체 영역 벽 충돌 시 소멸
3. 스킬 특성 영역 컨셉 동작
4. 스킬 선택 UI 영역 아이콘 노출
본 PM MCP 자율 진행:
==== PD #1: 거리 제한 ====
Projectile.Initialize:
- _spawnPosition 저장
- _maxRange = Camera.orthographicSize × 2 × aspect × 1.5 (가로 × 1.5)
Projectile.Update:
- Distance(transform.position, _spawnPosition) >= _maxRange → SelfDestruct
==== PD #2: 벽 충돌 ====
Projectile.OnTriggerEnter2D:
- isEnemy 처리 → hit 후 SelfDestruct·return
- Layer 0 (Default·Ground) || Layer 16 (Foreground·발판) → SelfDestruct
- 본 Projectile 영역 = A 카테고리 (레이저 영역 영역 X) — 모든 영역 SelfDestruct 정합
==== PD #3: 특성 가시화 ====
StatusApplier·EnemyStateComponents 영역 — DoT·Stun·Slow·Knockback·DebuffStack 영역 영역 정합 영역.
근본 영역 — Enemy hp 4·damage 5·1hit 즉사 → 효과 시각 X.
정정 — Enemy.prefab maxHearts 1→5 (maxHP 4→20) — A02 DoT·A03 Stun·A14 Slow 영역 4 hit 영역 영역 영역.
==== PD #4: Icon UI ====
SkillCardSlot _icon 매핑 X 영역 — BannerFrame04_Divided 자식 영역 SkillIcon GameObject 신규 추가 + Image 컴포넌트
- anchorMin·max (0.5, 0.7)·sizeDelta (120, 120)·preserveAspect true
- 3 슬롯 영역 _icon 필드 매핑 정합
Scene SkillSelectionCanvas·Enemy 인스턴스 RevertPrefabInstance — prefab 변경 동기화
MCP Play 검증:
- enemyMaxHP 20 ✅·컴파일 에러 0 ✅·Icon 매핑 3/3 ✅
PD 지적 (2026-05-10):
- "단순히 키운거라서 비효율적 — 리소스를 재활용할 수 있는 기능 구현"
본 PM 자성 — 직전 Tiled DrawMode size (500, 7) 영역 단순 영역 영역 메모리·렌더 영역 비효율. 영역 영역 — Camera 영역 영역 영역 sprite 영역 reposition 패턴 (재활용·효율).
신규 컴포넌트 InfiniteHorizontalBackground.cs:
- Start — sprite 가로 폭 측정 + 자식 사본 2개 (Left·Right) 영역 영역 영역 영역
→ 화면 영역 영역 영역 3 sprite (root + Left + Right) 영역 충분 (sprite > Camera width 정합)
- LateUpdate — Camera 영역 영역 영역 영역 sprite 폭 영역 영역 영역 → root 영역 정수 배수 reposition
→ 자식 사본 영역 영역 영역 영역 따라가 영역 영역 영역 영역 영역 영역
- 효율 — sprite 1개 (Resources 1회·Texture 메모리 재사용)·GameObject 3개
Background_BgImage1 정정:
- DrawMode Tiled → Simple (sprite default size·재활용 패턴 정합)
- Scale (1.77, 1.77, 1) — Camera height fit
- Position (0, 0.5, 10) — World root
- InfiniteHorizontalBackground 컴포넌트 부착
MCP Play 검증:
- SendMessage("LateUpdate") → bgPos 0 → 188.04 reposition 정합
- Camera 150 → bgChild0 (94.02)·bgChild1 (282.07) — Camera 영역 영역 sprite 3 영역 정합
근본 원인 (본 PM MCP 직접 진단):
- Enemy.controller 영역 Idle/Run/Hurt → Death/Hurt transition 부재 → death Trigger 호출 영역 transition X
- Animator updateMode = Normal·Time.timeScale = 0 (LevelUp 카드 선택) → Animator.Update 정지 → transition 영역 X
해결 (본 PM 자율 결정 + MCP 직접 적용):
- Enemy.controller transition 5 추가 (Idle→Death, Idle→Hurt, Run→Death, Run→Hurt, Hurt→Death)
→ manage_animation controller_add_transition 영역 직접 호출
- EnemyDeath.cs animator.updateMode = AnimatorUpdateMode.UnscaledTime 추가
→ Time.timeScale = 0 영역 영역 Animator 영역 정상 진행 → death animation 재생 + transition 발동
- 진단 Debug.Log 회수: Projectile (8 분기)·AttackHitbox (1줄)·EnemyDeath (1줄)
→ 사망 원인 확정 영역 회수 의무 정합
본 PM MCP 직접 진단 절차:
1. read_console — Console 직접 읽기 (Health@Enemy·Projectile 출력 검증)
2. controller_get_info — Enemy.controller parameters·states·transitions 직접 검증
3. execute_code — Player·Enemy 위치·Schedule<EnemyDeath> 직접 호출·Animator state 검증
4. manage_animation controller_add_transition — Animator transition 5 직접 추가
5. anim.SetTrigger("death") + anim.Update(0.5f) → Baddie-Death 진입 정합 검증
PD 결정 (2026-05-10): "MCP 활용해서 네가 직접 체크해" — 본 PM 자율 진단·fix·검증.
PD 자성 #13: PD에게 작업 떠넘기기 금지·MCP 능동 활용 의무.
목적:
- 본 PM 가설 4회 누적 부정확 + 회귀 1회 → feedback_pm_root_diagnosis_priority 의무 적용
- 가설 즉시 중단·실측 우선 진단 도구 추가
- PD Play 영역 Console [Projectile] prefix 필터 → 호출 여부·other 정보·각 분기 reach·return 시점 정확 진단
진단 Debug.Log 영역 (prefix [Projectile][...] 통일·grep 영역):
- [Enter] OnTriggerEnter2D 진입 영역 (other.name·layer·t)
- [Return] _hitTargets duplicate
- [Return] PlayerController detected
- [LayerCheck] enemyLayer·otherLayer·hasEnemyController·isEnemy
- [Return] not Enemy
- [Return] Health component missing
- [Return] Health not alive (hp 정보)
- [Hit] damage 적용
회수 의무:
- PD Console 결과 수령 + 근본 fix 적용 후 본 진단 Debug.Log 일괄 제거 (대화로그 영역 명시)
PD 결정 (2026-05-09): "A 안으로 해" — 진단 Debug.Log 즉시 추가.
pm-auditor 통과 (조건부) + 권고 4종 수용.
회귀 사실 (C3 자진 고지):
- 직전 fix `fe65592` Projectile Rigidbody2D Kinematic 추가
- Enemy = KinematicObject 상속 → Rigidbody2D Kinematic
- → Kinematic vs Kinematic + useFullKinematicContacts=false (기본값)
- → OnTriggerEnter2D 발화 X → 적 피격 X 회귀
근본 원인:
- C39 위반 — Enemy Rigidbody2D type 사전 실측 X
- KinematicObject.cs:76 영역 Read X·라이프사이클 검증 X
해결 (옵션 C — 단순 회귀):
- ProjectileSpawner.CreateFallbackProjectile 영역 Rigidbody2D 추가 영역 5 라인 제거
- Static Collider + Enemy Kinematic Rigidbody2D = OnTriggerEnter2D 발화 정합 복원
- `33eaa55` 시점 동작 정합 영역 복원 (DebuffStackLimit 정정 영역 그대로 유지)
자성 추가:
- 헌법급 feedback `feedback_new_code_existing_system_dependency_unmeasured` 신설
- 신규 코드 영역 기존 시스템 의존성 미실측 금지 (재발 차단 3 단계)
PD 보고 (2026-05-09 3차): "여전히 적이 플레이어의 투사체에 피격되지 않아" 회귀 정정.
근본 원인:
- Resources/Skills/Projectiles/Default.prefab 부재
- LoadProjectilePrefab fallback이 new GameObject로 Scene 영역 GameObject 생성·반환
- ProjectileSpawner.Trigger가 이를 prefab으로 Object.Instantiate
→ 사본은 정상 SelfDestruct
→ 원본 Scene GameObject는 Initialize 미호출 → _lifetime Invoke 미설정 → 영구 잔존
해결 (옵션 J):
- LoadProjectilePrefab은 Resources prefab만 반환 (부재 시 null)
- ProjectileSpawner.Trigger가 prefab null 시 CreateFallbackProjectile 직접 호출
- fallback 영역 매번 새 GameObject 직접 생성 (Instantiate X·자기 자신 발사체)
- 원본 Scene GameObject 잔존 패턴 근본 차단
검증:
- Glob 0건: Assets/Resources/Skills/Projectiles/ 부재 확인
- pm-auditor Pass + Minor 1 + Improvement 1 (회귀 위험 0건)
PD 보고 (2026-05-09): "맵에 투사체 하나가 영구적으로 남아있어" 근본 해결.
- Effectors/IEffector.cs: 효과 발동기 공통 인터페이스
- Effectors/Projectile.cs: Line 직선 투사체 (단일 적 타격 후 소멸)
- Effectors/HomingProjectile.cs: Homing 유도 투사체 A15 (FindNearestEnemy)
- Effectors/ProjectileSpawner.cs: IEffector 구현 — 다중 발사·궤적 분기
- Effectors/StatusApplier.cs: DoT·Stun·Slow·Knockback·DebuffStack 통합 적용기
- Effectors/DebuffStack.cs: A08 저주 스택 N회 폭발 레지스트리
- Effectors/EnemyStateComponents.cs: DoT·Stun·Slow MonoBehaviour 통합
- Events/SkillFireEvent.cs: Execute stub → ActiveCategory.Projectile 분기 정식 연결
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PD 직접 지시 2026-05-08 — Phase 2-A 검증 우선 + Phase 2-B 진행. 본 응답 = 코드 영역.
신규 영역 (2 파일):
- Assets/Scripts/MyUI/SkillCardSlot.cs — 단일 카드 슬롯 (PD 예시 정합)
· 1. 상단 색상 배너 (등급별: 청록 Common · 노랑 Rare · 빨강 Max)
· 2. 카드 이름 (한글)
· 3. 원형 아이콘 + 동심원 빛 효과
· 4. 레벨 N / 최대 (빨강 강조)
· 5. 효과 설명 3~4 라인
· 클릭 영역 + 선택 highlight
- Assets/Scripts/MyUI/SkillSelectionUI.cs — 스킬 선택 화면 (PD 예시 정합)
· 헤더: '기술 선택' 타이틀 + X 닫기 버튼
· 본체: 카드 3장 가로 배치 (SkillCardSlot ×3)
· 푸터: '남은 포인트: N' + '확인' 버튼
· 인터랙션: 카드 클릭 → 선택·highlight / 확인 → onConfirm 콜백 / X → 첫 카드 자동 fallback
기존 수정 (1 파일):
- Assets/Scripts/Progression/LevelUpManager.cs
· _ui 필드 (SkillSelectionUI) 추가
· HandleLevelUp → _ui.Show(cards, level, HandleCardConfirmed) 정식 호출
· UI 부재 fallback 영역 (placeholder asset 미등록 시)
· HandleCardConfirmed → _ui.Hide() + 게임 재개
TMPro 영역: Unity 6 com.unity.ugui 2.0.0 통합 — 별도 패키지 X.
Phase 2-B 다음 세그먼트 (별도): placeholder asset 5장 + Canvas Prefab + Scene [LevelUpManager] 통합.
PD 직접 지시 2026-05-08 — (b) 채택 + JSON 테이블 영역 관리.
신규 영역 (8 파일):
- Assets/Resources/Progression/level_xp_table.json — Lv 1~30 EXP 테이블 (balance-designer SOT)
- Assets/Scripts/Progression/LevelXPTableLoader.cs — Resources.Load + JsonUtility 캐시
- Assets/Scripts/Progression/PlayerProgression.cs — Level·EXP 진행도 (BT12-Dev v1 PlayerStats와 직무 분리)
- Assets/Scripts/Progression/ExperienceSystem.cs — EXP 발급 정적 게이트웨이
- Assets/Scripts/Progression/SkillCardPlaceholder.cs — placeholder ScriptableObject
- Assets/Scripts/Progression/SkillCardPlaceholderPool.cs — 카드 풀·Draw3Random
- Assets/Scripts/Progression/LevelUpManager.cs — 레벨업 발화·일시정지·UI placeholder (Phase 2-B 통합)
기존 파일 수정 (2 파일):
- EnemyDeath.cs Execute 마지막 영역 ExperienceSystem.OnEnemyKilled 호출
- PlayerController.cs Awake PlayerProgression 자동 부착
회귀 위험:
- BT5-Dev 발판/몬스터 영역 영향 X (EnemyDeath 호출 마지막·PlayerController 자동 부착)
- BT7-Dev VS 순수형 영향 X (Schedule 영역 변경 X)
- BT12-Dev v1 영역 충돌 X (PlayerStats 분리·신규 namespace EerieVillage.Progression)
Phase 2-A 영역 검증:
- 적 처치 → EXP 누적 → Lv 임계점 → Console [LevelUpManager] 영역 출력 확증
- Phase 2-B 영역 = SkillSelectionUI prefab + 5 placeholder asset + Scene 통합
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):
1. 숨겨진 통로 Player 통과 X (이전엔 문제 X)
2. 투명벽 위치 이상
진단:
- 1: BT82 영역 PD Foreground TilemapCollider 부착 = 통로 영역 충돌
- 2: BT100 인접 검사 = PD Foreground 포함 → PD FG 영역 옆 = cliff X 인식 → 실제 절벽 영역 투명벽 X 생성
정정 (BT101):
1. PD Foreground TilemapCollider Object.Destroy (BT66 R2 영역 회복·BT82 부착 영역 폐기)
- Enemy 절벽 차단 = BT99 투명벽 영역 (Layer 18)으로 분리됨 → PD Foreground = 시각만 영역 회복 가능
- 숨겨진 통로 영역 Player 자유 통과
2. 인접 검사 = Level + AutoForeground 만 (PD Foreground 영역 X)
- PD FG = TilemapCollider X = Enemy 발판 X = 검사 영역 X
- 실제 절벽 영역 정확 검출 → 투명벽 정확 위치
효과:
- 숨겨진 통로 = Player 자유 통과 (BT66 R2 영역 회복)
- 투명벽 = Level/AutoForeground 영역 가장자리만 검출·정확 위치
- Enemy 절벽 차단 = 투명벽 (Layer 18)
PD 보고 (2026-05-08):
1. 투명벽 위치 너무 짧게 멈춤 (절벽 위치보다 안쪽)
2. 대기 시간 짧음 (1~3초 대기 X)
3. 숨겨진 통로 막힘
진단:
- 1: BoxCollider size (0.1, 3) → halfWidth 0.05m → Enemy Capsule bounds 정합 시 절벽 영역 0.282m 앞 멈춤
- 3: PD Foreground 자체 가장자리 영역 = 시각 가림막 영역 끝 = 통로 영역. 본 PM 가장자리 검사 영역에 PD Foreground 포함 → 통로 영역에 투명벽 생성 → Player 통과 X (Layer 13 ↔ 18 OFF임에도 BoxCollider 영역 정합 X 가능성)
정정 (BT100):
1. BoxCollider size: (0.1, 3) → (0.02, 3) (매우 좁음)
2. BoxCollider offset.y: 1 → 0 (Tile 표면 영역·절벽 위치 정확)
3. 자체 가장자리 검사 = Level + AutoForeground 만 (PD Foreground 자체 검사 X)
4. 인접 검사 = Level + AutoForeground + PD Foreground 모두 (안전 영역 모두 포함)
효과:
- 투명벽 = 매우 좁은 영역 + Tile 표면 영역 → Enemy 영역 절벽 영역 가까이 도달
- PD Foreground 자체 가장자리 영역 = 검사 X → 숨겨진 통로 영역 투명벽 X → Player·Enemy 통과 가능
- waitTimer 영역 그대로 (1~3초 random·arrive 시점 트리거)
PD 명시 (2026-05-08): "낭떠러지 앞에 몬스터만 지나갈 수 없는 투명한 벽을 세우면 안돼?"
본 PM 17회 가설 누적 부정확 자인 후 PD 직접 단순 해결 채택.
변경:
1. ProjectSettings/TagManager.asset:
- Layer 18 = 'EnemyWall' 신규 추가
2. GameOptimizer.cs Init():
- Physics2D.IgnoreLayerCollision(13, 18, true) — Player ↔ EnemyWall 충돌 OFF (Player 통과)
3. GameOptimizer.cs SetupCliffWalls() 신규:
- 모든 Tilemap (Level·AutoForeground·PD Foreground) Tile 영역 순회
- Tile 좌·우 인접 영역이 모든 Tilemap에 Tile X 시 = 절벽 가장자리
- 가장자리 위치에 BoxCollider2D GameObject (CliffWall) 자동 생성
- Layer 18 (EnemyWall) + size (0.1×3) + offset (0, 1)
- parent = CliffWalls GameObject (그룹 영역)
효과:
- Player ↔ EnemyWall 충돌 OFF → Player 자유 통과
- Enemy ↔ EnemyWall 충돌 ON → Enemy 절벽 가장자리 도달 시 차단
- 알고리즘 부정합 무관 (물리 영역 차단)
- BT98 R1 방어 영역 = 보조 (투명벽 차단으로 X 도달 가설)
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): "여전히 몬스터가 낭떠러지로 사라졌어"
근본 원인:
- BT66 R2 영역에서 PD Foreground TilemapCollider2D Object.Destroy
- = PD 직접 그린 발판 영역 위에 Enemy 배치 시 발 아래 충돌 X = 떨어짐
- BT81 절벽 검출 영역 = footAhead Raycast Layer 0+16. PD Foreground = TilemapCollider X = Raycast 검출 X = 절벽 영역 인식 X = 떨어짐
정정 (BT82):
- BT66 R2 영역의 PD Foreground TilemapCollider2D Destroy 영역 폐기
- TilemapCollider2D 부착 회복 + Layer 16 강제 (AutoForeground와 동일)
효과:
- Player ↔ PD Foreground = Drop-Through 패턴 영역 정상 (통과·착지 분기)
- Enemy ↔ PD Foreground = 충돌 ON (Layer 14 ↔ Layer 16) = 떨어짐 X
- Enemy 절벽 검출 = PD Foreground·AutoForeground 모두 Layer 16 + TilemapCollider = 정합
후속 의무:
- PD Refresh+Play 시각 검증 (Enemy 떨어짐 X·Player 통과 영역 그대로)
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 시각 검증
PD 명시 (2026-05-08):
1. 몬스터 바닥 살짝 뚫고 들어감 → y +0.5 (Enemy.prefab + Scene 인스턴스)
2. PatrolPath 폐기 → 생성 위치 기준 좌/우 random 100~150 왕복 자동 patrol
3. 절벽 검출 → 낭떠러지 떨어지지 않도록
변경:
1. Enemy.prefab transform.y: 1.032 → 1.532
2. Scene Ingame.unity Enemy 인스턴스 16개 m_LocalPosition.y override 영역 +0.5 일괄 (19건)
3. EnemyController.cs:
- patrol 4-phase 영역 (0: 우측 random / 1: 시작 복귀 / 2: 좌측 random / 3: 시작 복귀)
- SetNextPatrolTarget — Random.Range(100, 150) 영역 + phase별 _targetX 계산
- Update 영역 자동 patrol 로직 (PatrolPath path 영역 폐기·legacy 호환만)
- 절벽 검출 — 발 앞 0.6 + 발 아래 0.8 Raycast 영역 지면 X 시 시작 위치 즉시 복귀
- Inspector 노출: patrolMinRange·patrolMaxRange·patrolArriveThreshold·cliffCheckDistance·cliffCheckDepth·groundLayerMask
- BT17 marker Debug.Log 영역 폐기 (시행착오 정리)
효과:
- 모든 Enemy 인스턴스 (path 미설정 영역 포함) 자동 patrol 작동
- 시작 위치 기준 ±100~150 random 왕복 패턴
- 절벽 영역 검출 시 시작 위치 즉시 복귀 (낭떠러지 X)
- y +0.5 = 발 영역 지면 위 정합
PD 명시 (2026-05-08): "몬스터도 캐릭터와 같이 리소스를 반대로 재생시켜야 해"
근본 원인:
- AnimationController.cs (Enemy 영역) flipX 영역:
- 우측 이동 시 flipX = false
- 좌측 이동 시 flipX = true
- PlayerController.cs (Hero1 영역) flipX 영역:
- 우측 이동 시 flipX = true
- 좌측 이동 시 flipX = false
- = 반대 영역. M001 sprite (좌측 향함) 기준 Enemy 영역 우측 이동 시 sprite 그대로 = 후방 이동 영역.
정정 (true·false 반전):
- 우측 이동 시 spriteRenderer.flipX = true
- 좌측 이동 시 spriteRenderer.flipX = false
- = PlayerController·Hero1 영역과 동일 영역 정합
PD 추가 보고 진단 (첫 번째 등장 몬스터 정지):
- Scene Enemy prefab 인스턴스 16개 중 5개 path 미설정 (#3·#9·#11·#13·#14)
- path null = mover null = move.x = 0 = 정지
- pos.x 카탈로그: #13(7.79·path=0) #3(24.49·NO_PATH) #14(42.91·NO_PATH) #11(82.28·NO_PATH) #9(139.27·NO_PATH)
- = PD 시각 첫 번째 등장 = pos.x 가장 작은 영역 가설 (#13 또는 #3)
- 정정 영역 = PD가 Editor에서 path 영역 직접 부여 의무 (PatrolPath GameObject Inspector 영역 drag·drop)
PD 명시 (2026-05-08): "플레이어 조작 시스템 완성. 시행착오로 불필요하게 생성된 코드·작업물 제거 + 최신 상태로만 깔끔하게"
정리 영역:
1. GameOptimizer.cs (Write 전체 재작성):
- 헤더 주석 — BT5-Dev 발판 시스템 영구 영역 명시 + 동작 요약 5단계
- BT34·BT46·BT66·BT67·BT48·BT63·BT68 시행착오 주석 영역 통합 정리
- Debug.Log 영역 통합 1행 ([GameOptimizer] 출력)
- IsSmallAirPlatform 헬퍼 영역 보존 (BT48 휴리스틱 사용 중)
2. PlayerController.cs (Edit 부분 정리):
- dropThroughTimer·jumpAscentTimer 변수 영역 주석 정리
- OnCollisionEnter2D BT30-Collide 진단 Debug.Log 영역 폐기 (시행착오)
- BT69·BT70·BT71·BT72·BT73·BT74 시행착오 주석 영역 통합 정리
- UpdateContactFilterForDropThrough 영역 메서드 docstring 추가
3. KinematicObject.cs (Edit 부분 정리):
- BT68 X·Y 분리 영역 주석 정리
영구 채택 영역:
- R2 (BT66): AutoForeground GameObject 분리 + PD Foreground = 가림막 시각만
- BT67: AutoForeground transform 동기화 (PD Foreground·Level 영역과 동일)
- BT68: KinematicObject X·Y 분리 + GameOptimizer TileGround* 자동 분류 제외
- BT69~BT74: Drop-Through (Down + Jump) Input 패턴 + 가장자리 jitter 차단
플레이어 조작 시스템 완성:
- 발판 위 착지·점프 통과·자유 이동
- Down + Jump = Drop-Through (발판 위만)
- 전진 점프 시 앞 벽 hit + 위로 점프 보존
- 대각선 벽 통과 X (TileGround* Level 잔존)
- 발판 가장자리 jitter 차단 (3점 Raycast + 밀림 강제 Drop-Through)
PD 권고 (2026-05-08): "한번이라도 밀리면 아래로 강제로 떨구어야하지 않을까?"
진단:
- BT73 후 footHit 3점 안정화에도 특수 영역 잔존
- 점프 정점(velocity.y ≈ 0) + 수평 이동 시도 + 발판 가장자리 = 발판 일시 검출
- = standingOnPlatform=true → mask ON → body.Cast 충돌 → 수평·수직 정지
- = '밀린 상태 고정'
정정 (BT74 — UpdateContactFilterForDropThrough 영역 추가):
밀림 상태 검출 4조건 AND 결합:
1. standingOnPlatform=true (footHit 3점 검출)
2. inAir = jumpState == Jumping || jumpState == InFlight (점프·낙하 중)
3. nearApex = velocity.y > -1.5f (정점·낙하 초기)
4. horizontalIntent = Mathf.Abs(move.x) > 0.1f (수평 이동 시도)
검출 시 강제 Drop-Through:
- dropThroughTimer = DROP_THROUGH_DURATION (0.3초 mask 강제 OFF)
- standingOnPlatform = false (즉시 해제)
- = Player 발판 통과 + 자연 낙하 시작
효과:
- 발판 가장자리 정점 + 수평 이동 시 = 강제 통과 (밀림 X)
- 정상 착지 (velocity.y < -1.5 빠른 descending) = 영역 외 → 그대로 착지
- 발판 위 정지 (Grounded·수평 입력 X) = 영역 외 → 그대로
- ascending·Drop-Through·일반 점프 = 그대로
후속 의무:
- PD Refresh+Play 시각 검증 (특수 재현 경로 + 다양한 점프 영역)
PD 보고 (2026-05-08): "발판 끝에서 내려오기 직전 아래 방향 유지 + 발판방향 이동 시 밀려남"
진단:
- BT72 후도 descending 시 standingOnPlatform 검사 활성
- footHit Raycast 단일 (중앙) 영역 = 발판 가장자리 진입 시 검출 X·검출 O frame 교차
- = jitter (mask ON·OFF 진동) → 미세 밀려남
정정 (BT73):
- footHit Raycast 좌·중·우 3점 추가
- footY = collider2d.bounds.min.y + 0.02f
- boundsLeft = collider2d.bounds.min.x + 0.02f
- boundsCenter = collider2d.bounds.center.x
- boundsRight = collider2d.bounds.max.x - 0.02f
- standingOnPlatform = 3점 OR 결합 (어느 하나라도 검출 시 true)
- = 발판 가장자리 영역 안정 검출
효과:
- 발판 가장자리 영역 진입 시 standingOnPlatform 안정 (jitter 차단)
- 발판 위 착지 정합 (3점 중 1점 검출 영역 충분)
- ascending·Drop-Through·일반 점프 영역 그대로
후속 의무:
- PD Refresh+Play 시각 검증 (특수 재현 경로 — 발판 끝 + Down + 발판 방향 이동)
PD 질문 (2026-05-08): "발판 방향 통과 시 밀려나는 현상. 깔끔하게 통과 또는 통과 X (착지) 둘 중 하나로"
진단:
- ascending 판정: velocity.y > 0.01f (mask OFF Layer 16 통과)
- 정점 영역 (velocity.y ≈ 0): 1~2 frame 동안 조건 X → standingOnPlatform 검사 활성
- = 발판 영역 진입 + footHit 검출 → mask ON 짧은 충돌 → 밀려남 (jitter)
정정 (BT72):
- jumpAscentTimer 신규 (JUMP_ASCENT_DURATION = 0.4초)
- PrepareToJump → Jumping 시 Timer 활성 (Drop-Through 점프 X — dropThroughTimer 영역으로 처리)
- Update에 매 frame Timer 감소
- isJumpingThrough 조건에 jumpAscentTimer > 0f 추가
- = 점프 시작 후 0.4초 mask 강제 OFF → ascending·정점 일관 통과
- 0.4초 후 또는 descending velocity.y < -0.01 → standingOnPlatform 검사 활성 → 발판 위 착지
효과:
- 발판 방향 점프 = 깔끔 통과 (정점 영역 밀려남 X)
- 발판 위 떨어지면 착지 (descending standingOnPlatform 검사)
- 일반 점프·Drop-Through·전진 점프 영역 그대로
후속 의무:
- PD Refresh+Play 시각 검증 (발판 통과 일관성)
- 정합 시 BT72 영역 영구 채택
PD 보고 (2026-05-08): "아래로 점프 시도 한 다음부터 점프키가 동작하지 않는 현상"
근본 원인:
- BT69 ComputeVelocity dropThroughJump 분기: velocity.y = 0
- velocity.y = 0 + 발판 위 IsGrounded=true 잔존 시:
→ KinematicObject FixedUpdate에서 IsGrounded 갱신 시 발판 통과 전 잔존 가능
→ jumpState = Jumping 영역에 IsGrounded=true → InFlight 전환 조건 X
→ jumpState = Jumping 영구 잔존
- Update §145: jumpState == Grounded 조건만 점프 입력 수용
→ 점프 입력 영구 무시
정정 (1행):
- velocity.y = 0f → -0.5f
- 즉시 낙하 시작 → IsGrounded=false 확보
- Jumping → InFlight → 착지 → Landed → Grounded 정상 사이클
- 점프 입력 정상 수용
효과:
- Drop-Through (Down + Jump 발판 위) 후 → 발판 통과 + 자연 낙하 + 다른 영역 착지
- 착지 후 점프 입력 정상 수용 (Grounded 영역 도달)
- 점프 모션 그대로 (jumpState = PrepareToJump → Jumping → InFlight → Landed → Grounded)
후속 의무:
- PD Refresh+Play 시각 검증 (Drop-Through 후 점프키 정상 작동)
- 정합 시 BT69+BT70+BT71 Drop-Through Input 영구 채택
PD 보고 (2026-05-08): "아래가 뚫려있지 않은 지형에서 아래로 점프 시도 시 점프가 되지 않는 버그"
근본 원인:
- BT69 코드: Down + Jump 입력 시 무조건 dropThroughTimer + dropThroughJump 활성
- ComputeVelocity: dropThroughJump=true 시 velocity.y=0 강제 (위 점프 X)
- = 지면(Layer 0) 위 Down + Jump → velocity.y=0 → 점프 자체 차단
정정 (Update 영역에 발판 위 검증 추가):
- Down + Jump 입력 시 footHit Raycast (Layer 16 mask 0.1m 아래)
- onJumpThroughPlatform = (footHit.collider != null)
- Drop-Through 발동 조건: downHeld AND onJumpThroughPlatform
- = 발판(Layer 16) 위만 Drop-Through 발동
- = 지면(Layer 0) 위 = 일반 점프 (velocity.y = jumpTakeOffSpeed)
효과:
- 발판 위 + Down + Jump → 발판 통과 + 점프 모션 + 자연 낙하 (BT69 영역 그대로)
- 지면 위 + Down + Jump → 일반 점프 (위로) ✅ (정정)
- Down 미입력 + Jump → 일반 점프 (그대로)
후속 의무:
- PD Refresh+Play 시각 검증
- 정합 시 BT69 + BT70 결합 = Drop-Through Input 패턴 영구 채택
PD 명시 (2026-05-08): "발판과 같이 아래가 뚫려있고 이동 가능한 영역이 있는 경우, 아래 방향키 상태로 점프하면 점프 모션과 함께 내려올 수 있도록"
표준 platformer 패턴 (Drop-Through Input):
- Player가 발판(Layer 16) 위 + Down 방향키 + Jump 키 동시 입력
- = Layer 16 mask 강제 OFF (DROP_THROUGH_DURATION=0.3초) → 발판 통과
- = velocity.y = 0 (위 점프 X·gravity로 자연 낙하)
- = jumpState = PrepareToJump (점프 애니메이션 발동·시각상 점프 모션)
변경 (PlayerController.cs 3영역):
1. 클래스 변수 추가:
- float dropThroughTimer (Layer 16 mask 강제 OFF 지속 시간)
- const float DROP_THROUGH_DURATION = 0.3f
- bool dropThroughJump (본 frame Drop-Through 점프 발동 분기)
2. Update 영역:
- Move Input 영역 y < -0.5 (Down) + Jump WasPressed → dropThroughTimer 활성 + dropThroughJump=true
- 매 frame dropThroughTimer 감소 (Time.deltaTime)
3. UpdateContactFilterForDropThrough 영역:
- isJumpingThrough 조건에 dropThroughTimer > 0 추가
- Drop-Through 활성 시 Layer 16 mask 강제 OFF
4. ComputeVelocity 영역:
- jump && IsGrounded 시 dropThroughJump 분기:
- dropThroughJump → velocity.y = 0 (위 점프 X)
- else → velocity.y = jumpTakeOffSpeed (기존 정상 점프)
효과 (PD 의도 정합):
- 일반 점프 (Jump only) = 위로 점프 (그대로)
- Drop-Through (Down + Jump) = 발판 통과 + 점프 모션 + 자연 낙하
- 0.3초 후 mask 자동 복원 (다른 발판 위 정상 착지 가능)
후속 의무:
- PD Refresh+Play 시각 검증 (발판 위 + Down + Jump → 통과·낙하 + 점프 애니메이션)
- 정합 시 BT49~BT65 영구 폐기 + R2 + BT68 + BT69 영역 영구 채택
PD 명시 (2026-05-08):
1. "대각선으로 점프로 벽 부분을 통과하려는 상황 → Player 점프 상태에서 밀려나는 현상" (애초에 통과 X 의무)
2. "전진하며 점프할 경우 앞이 막혀있으면 위로만 점프되어야 하는데 점프 자체가 막힘" (앞 막혀도 정상 점프 의무)
본 PM 직접 read 진단:
버그 1 (벽 통과) 원인:
- 자동 분류 영역(BT47/BT48)이 TileGround·TileGroundDark·TileGroundTop도 AutoForeground로 이동
- AutoForeground = Layer 16 + Drop-Through 패턴 (ascending mask OFF)
- = 대각선 점프 시 벽 Tile 통과 가능
버그 2 (점프 막힘) 원인:
- KinematicObject.PerformMovement line 164~165:
velocity.x *= 0; velocity.y = Mathf.Min(velocity.y, 0);
- = X 이동 시점 hit (앞 벽)에서도 velocity.y 영점 강제
- = 점프 시작 시 앞 벽 hit → 점프 속도 0 → 점프 자체 차단
정정:
1. KinematicObject.cs (버그 2):
- 공중 hit 처리 X·Y 분리:
- X 이동 시점 hit (앞 벽) → velocity.x = 0, velocity.y 보존 (점프 속도 유지)
- Y 이동 시점 hit (천장) → velocity.x·y 모두 cap (기존)
2. GameOptimizer.cs (버그 1):
- TileGround* (3종 — 지면·벽 의도) 자동 분류 제외 추가
- tileAsset.name.StartsWith("TileGround") → continue
- TileGround·TileGroundDark·TileGroundTop = Level 잔존·Layer 0·영구 충돌·통과 X
효과:
- 버그 1: 벽 통과 X (TileGround* = Layer 0 영구 충돌)
- 버그 2: 앞 막혀도 위로 점프 정합 (Y 속도 보존)
- 발판 동작 그대로 (TileFloating·MidgroundFiller·Building·cloud·hillside·midground·mountains 자동 분류)
- 나무·plant·fence·house 자체 통과 그대로
후속 의무:
- PD Refresh+Play 시각 검증 (대각선 점프 벽 통과 X + 앞 막힌 점프 작동)
- 본 PM Editor.log [BT48-MoveTiles] direct read
PD 보고 (2026-05-08): "발판의 위치가 1만큼 y로 올라갔는데 왜 그런거지?"
근본 원인:
- BT66 R2 — AutoForeground GameObject 신규 생성 (Grid 자식)
- 신규 생성 시 transform.localPosition = default (0, 0, 0)
- PD가 Level·Foreground GameObject를 y=-1로 직접 변경 (PD 시각 정정 작업)
- = AutoForeground (y=0) ↔ Level/Foreground (y=-1) → 1m 차이로 시각상 위로
정정 (1행 추가):
- 매 Play 시점 AutoForeground.transform.localPosition = PD Foreground localPosition (또는 Level)
- PD Foreground 우선 (가림막 영역과 동일 공간 보장) · 미존재 시 Level fallback
효과:
- AutoForeground 발판 시각 위치 = PD Foreground·Level 영역과 동일
- Drop-Through 패턴 작동 영역 동일 (Layer 16 + ContactFilter mask)
- 발판 위 착지 좌표 정합 (Player 영역과 정합)
후속 의무:
- PD Refresh+Play 시각 검증
- BT67 commit으로 R2 영역 완결
PD 명시 (2026-05-08): "R2로 진행해줘"
근본 원인 (BT65 진단):
- 본 PM 자동 분류 코드(BT47/BT48)가 PD 시각 분리 의도 침범
- PD Foreground = 직접 그린 가림막 시각만 + 본 PM 자동 분류 발판이 같은 GameObject 영역 혼재
R2 변경 (BT63 영역 + 분리):
1. PD Foreground GameObject = 가림막 시각만 (TilemapCollider2D Object.Destroy)
- PD 직접 그린 Tile 그대로·시각 표시 보존
- Player와 충돌 X (PD 시각 의도 정합)
2. AutoForeground GameObject 신규 생성 (Grid 자식)
- Tilemap + TilemapRenderer + TilemapCollider2D 자동 부착
- Layer 16 (Drop-Through)
- 자동 분류(BT47/BT48 임계값+작은 발판) SetTile 대상
3. PlayerController.UpdateContactFilterForDropThrough 영역 그대로 (Layer 16 mask 동적·BT63 영역 보존)
효과:
- PD 가림막 = 시각 표시·Player 통과 가능 (PD 의도 정합)
- 자동 분류 발판 = AutoForeground 영역·Drop-Through 패턴 (위 착지 + ascending 통과)
- BT49 None 차단 그대로 (tree·plant·fence·house 자체 통과)
매 Play 시점 동작:
- PD Foreground TilemapCollider Destroy
- AutoForeground 검색·없으면 신규 생성·Grid 자식·필수 컴포넌트 자동 부착
- 자동 분류 영역(BT48 임계값+작은 발판) Level → AutoForeground SetTile
후속 의무:
- PD Refresh+Play 시각 검증
- 본 PM Editor.log [BT48-MoveTiles] direct read
- 정합 시 BT49~BT65 영구 폐기 + feedback 메모리 등재
PD 명시 (2026-05-08): "직전 상태로 되돌려" + "에디터 상태에서는 박스 쳐진 가림막 부분만 Foreground인데 어째서 발판까지 영향을 받는거지?"
변경: fgTc.enabled = false 라인 제거 = BT63 정확 회귀.
본 PM 진단 (PD 의문 답변):
근본 원인 — 본 PM의 자동 분류 코드가 PD의 시각 분리 의도 침범:
- PD 의도: Foreground GameObject = PD 직접 그린 가림막 영역만 (시각 배경)
- 본 PM 코드 (BT47/BT48): Level Tile들을 GameObject.Find('Foreground') 영역으로 자동 이동 (SetTile)
- 결과: PD 가림막 + 본 PM 자동 분류 발판이 같은 Foreground GameObject 영역 혼재
- BT64 fgTc.enabled=false: 모든 Foreground Tile 충돌 X = 발판도 충돌 X = PD 보고 영역
= 자동 분류 영역이 PD 시각 분리 의도 침범 = 본 PM 핵심 오해.
PM 권고 (PD 결정 영역):
- 옵션 1: 자동 분류 영역 폐기 + PD가 발판 영역 직접 Tile Palette로 그리기 (표준 Unity 워크플로우)
- 옵션 2: 자동 분류 결과를 별도 GameObject (예: AutoForeground)에 SetTile = PD Foreground 분리
- 옵션 3: BT63 + 가림막 Tile asset (예: MidgroundFiller) 자동 식별 + 분리
후속 의무:
- PD 결정 영역 명시 후 본 PM 즉시 집행
- BT49~BT64 누적 16회 변경 영역 영구 폐기 의무
PD 명시 (2026-05-08): "BT63이 내가 원했던 기본 상태야. 이제 Grid 오브젝트의 자식 오브젝트인 Foreground가 플레이어와 충돌하지 않도록만 해봐"
변경 (BT63 영역 + 1행 추가):
- Foreground TilemapCollider2D 자동 부착 그대로 유지 (BT47 영역)
- 자동 분류 SetTile + SetColliderType 그대로 유지 (BT48·BT63 영역)
- 부착 직후 fgTc.enabled = false → 물리 충돌만 차단
효과:
- Foreground GameObject = Player와 충돌 X (PD 명시 정합)
- TilemapRenderer 시각 표시 그대로 (Layer 16·SortingOrder=5)
- Tile data·SetColliderType 영역 그대로 (BT63 영역 보존·롤백 가능)
- Level Tilemap = 영구 충돌 (지면·발판 역할)
미적용 (의도적):
- Object.Destroy 폐기 (data 보존·롤백 경로)
- Layer Matrix 변경 폐기 (Project Settings 영역 영향 X)
후속 의무:
- PD Refresh+Play 시각 검증
- 본 PM Editor.log [BT48-MoveTiles] direct read
- 정합 시 BT49~BT61 영구 폐기·feedback 메모리 등재
PD 명시 (2026-05-07): "이제 이 상태에서 나무가 충돌되는 것만 수정해봐"
변경 (BT62 = BT48 시점 + 1행 추가):
- Level → Foreground 자동 분류 영역에 None Tile 차단 추가:
if (tileAsset != null && tileAsset.colliderType == None) continue;
효과:
- BT48 영역 발판 동작 그대로 보존 (PD 정합 시점)
- tree·plant·fence·house (4종 None Tile) = 자동 분류 제외
- Level Tilemap 잔존 + Tile asset 자체 None Collider = 자연 통과 (충돌 X)
미적용 영역 (BT49 영역과 차이):
- 사후 복원 영역(Foreground 그려진 None Tile SetColliderType(None) 복원) 미추가
- 이유: PD 명시 = 나무 충돌만 정정 + BT48 영역 변경 최소화
Player.prefab·PlayerController.cs = BT62 영역 그대로 (BT48 시점).
BT49~BT61 누적 14회 변경은 BT62에서 이미 모두 폐기됨.
후속 의무:
- PD Refresh+Play 시각 검증
- 본 PM Editor.log [BT48-MoveTiles] direct read
- 나무·plant·fence·house 통과 + 발판 영역 정합 확증
PD 강한 어조 (2026-05-07): "또다시 발판을 통과할 수 없게 되었잖아!"
본 PM 자기검증 — 12회 가설 누적 부정확 자인:
- BT49 (None 차단·정합) → BT50/BT51 (Grid→Sprite 영역 효과 X)
- BT52/BT53 (카탈로그·decor=1 부정확)
- BT54 (Foreground 충돌 제거·발판 위 X)
- BT55 (BT47 회귀 시도·BT58 BoxCollider 영향)
- BT58 (BoxCollider BT47 회귀·점프 X 보고)
- BT59 (BT49 회귀 + Foreground 충돌 제거·발판 위 X)
- BT60 (자동 분류 폐기·발판 통과 X)
PD 명시 흐름 ('Foreground = Grid → Foreground 배경 의도') 정합 시도 모두 실패.
PD가 발판 통과·점프·위 착지 모두 정합 인식한 마지막 시점 = BT47 (commit 1024e08).
BT61 정정:
- git checkout 1024e08 -- Assets/Scripts/Mechanics/GameOptimizer.cs (BT47 시점 정확 회귀)
- BT47 영역 = Foreground TilemapCollider 자동 부착 + Layer 16 + Level→Foreground 임계값 자동 분류 + Sprite 강제
- Player.prefab BT58 그대로 (BT47 정합 영역)
- PlayerController.cs BT57 Debug.Log 그대로 (영향 X)
- diff: +38 / -46 (BT49~BT60 누적 영역 모두 폐기)
PD 의도 정합 (BT47 시점):
- 발판 위 착지 ✅ (Foreground TilemapCollider + Layer 16 + ContactFilter 동적 mask)
- 점프 ascending 통과 ✅ (PlayerController.UpdateContactFilterForDropThrough)
- 임계값 위 (worldY>=playerY+1.5) Tile 자동 분류
BT49 None 차단 영역(나무 통과) = BT47 시점에 미적용 = 나무도 발판처럼 충돌 영역 재발 가능 (PD 첫 보고 영역).
BT47 정합 우선 + 나무 충돌 영역 후속 PD 결정 영역.
본 PM 능력 한계 자인 — PD 추가 명시 영역 결정 영역 의무.
PD 보고 (2026-05-07): "지금은 발판 위에 올라갈 수 없게 되었어."
근본 원인 (본 PM 자기검증):
- BT49 자동 분류 (Level → Foreground 이동) = SetTile(null) 영역에서 Level 발판 Tile 제거
- Foreground TilemapCollider X (BT59) = Foreground 충돌 X
- = Level 발판 Tile 사라짐 + Foreground 영역 충돌 X
- = 발판 위 착지 X (PD 보고 영역)
BT60 정정:
- BT48 자동 분류 영역 폐기 (임계값+작은 발판 휴리스틱)
- BT49 사후 복원 영역 폐기 (None 처리)
- Foreground 자동 부착 영역 (TilemapCollider 제거 — BT59 영역) 그대로 유지
- 결과:
- Level Tilemap = Scene yaml 영역 그대로 (영구 충돌·발판·지면 역할)
- Foreground Tilemap = 시각만 (TilemapRenderer + Layer 16·TilemapCollider X)
PD 의도 정합 효과:
- Player가 Level 지면 위 착지 (영구 충돌)
- Foreground 영역 자유 통과 (충돌 X·시각만)
- BT47부터 누적된 Foreground Tile (Scene yaml) = 시각상 잔존·통과 가능
부수 영역:
- IsSmallAirPlatform 헬퍼 = dead code (사용 X·후속 정리 권고)
- 변경 전 자동 분류 영역 코드 = git history 9adfc64(BT49)·92f102e(BT59) 보존
PD 명시 (2026-05-07): "BT49 정정 (commit 9adfc64) 시점에서 Foreground에 충돌체크만 없애면 될거 같은데?"
변경:
1. GameOptimizer.cs = git checkout 9adfc64 영역 회귀 (BT49 자동 분류 + None 차단 + colliderType 존중 + 사후 복원)
2. Foreground 자동 부착 영역 정정:
- TilemapCollider2D 자동 부착 폐기
- 기존 TilemapCollider2D Object.Destroy
- fgTc null 유지 → 사후 복원 영역 자동 skip
결과 (PD 의도):
- Foreground Tilemap = 시각만 (TilemapRenderer + Layer 16·TilemapCollider X)
- BT48 자동 분류 (임계값+작은 발판) = SetTile 작동·ProcessTilemapChanges X (fgTc null)
- Level Tilemap = 영구 충돌 (발판·지면 역할)
- Player가 Level 지면 위 착지 + Foreground 영역 자유 통과
Player.prefab BoxCollider2D BT58 영역 그대로 (BT47 정확 회귀: 0.45×1.15 + offset 0,0.1)
PlayerController.cs BT57 Debug.Log 그대로 (Drop-Through 영역 폐기로 영향 X)
후속 의무:
- PD Refresh+Play 시각 검증
- Editor.log [BT48-MoveTiles] 직접 read (이름 BT48이지만 실제 BT49 회귀 코드)
- 정합 시 BT55+BT58 영역 폐기 채택 영구화
PD 보고 (2026-05-07): "발판을 다시 통과해서 이동하거나 점프할 수 없게 되었어"
본 PM 알고리즘 영역 진단 결과 (모두 정합):
- BT55 자동 분류 [BT55-MoveTiles] moved=1389 (BT47 정합)
- Player Layer 13 / Foreground Layer 16
- Layer Matrix 13 ↔ 16 충돌 ON
- PlayerController.UpdateContactFilterForDropThrough 표준 패턴
= 알고리즘 영역 정합 + PD 보고 점프 X = 본 PM 미식별 영역.
BT57 진단 Debug.Log 추가:
- 출력 시점: 점프 시점 (jump || PrepareToJump || Jumping || InFlight velY>0.5)
- 출력 영역: jumpState·velocity.y·standingOnPlatform·mask16(Layer 16 mask)·transform.y·bounds.min.y
- log spam 방지 (점프 시점만)
PD Refresh+Play 후 본 PM Editor.log [BT57-DropThrough] direct read 후 진단:
- jumpState 영역 정상 전환 검증 (Grounded → PrepareToJump → Jumping)
- mask16 = false (ascending 시 mask OFF) 확증
- standingOnPlatform 영역 정상 검출 검증
알고리즘 정합 + 진단 결과로 후속 정정 영역 결정.
PD 명시 (2026-05-07):
1. "발판은 위에 설 수 있어야 해"
2. "내가 말한건 Grid → Foreground를 말한거야" (이미지 첨부)
3. "이전 버전처럼 발판을 통과해서 이동하거나 점프할 수 있도록 되돌려"
변경:
1. BT54 폐기 — Foreground TilemapCollider2D 자동 부착 회복 (Drop-Through 패턴 복원)
2. 자동 분류 영역 BT47 정확 회귀:
- 임계값(worldY >= playerY+1.5) 분류
- Sprite 강제 (BT47 호환·sprite 빈 픽셀 영역 점프 통과 보존)
- BT49 None 차단 유지 (tree·plant·fence·house 자체 통과)
3. 폐기:
- BT48 작은 발판 휴리스틱 (가로≤8+위·아래 빈)
- BT50 Grid→Sprite 이동 시 강제
- BT52 TileFloating* 단일 매칭
- BT53 카탈로그 8종 (TileFloating* + 배경·건물 7종)
4. 사후 복원 영역 (BT51 None 처리) 유지
효과 (PD 명시 정합):
- 발판 위 착지 (Foreground TilemapCollider + Layer 16 + ContactFilter 동적 mask)
- 점프 ascending 통과 (PlayerController.cs UpdateContactFilterForDropThrough — BT40 개발팀장 진단)
- 모든 비-None Tile 자동 분류 (BT47 시점 moved=1389 정합 회귀)
- tree·plant·fence·house 자체 통과 (BT49 None 차단)
본 PM 6회 가설 누적 부정확 자인:
- BT49 None 차단 (정합·유지)
- BT50 Grid→Sprite 이동·사후 강제 (효과 X)
- BT51 사후 Grid→Sprite 폐기 (효과 X)
- BT52 TileFloating* 단일 (decor=0 부정확)
- BT53 카탈로그 8종 (decor=1 부정확·1266개 미식별)
- BT54 Foreground TilemapCollider 제거 (발판 위 착지 X — PD 의도 부정합)
→ BT47 정합 영역 회귀 = PD 명시 "이전 버전처럼" 정합
후속 의무:
- PD Refresh+Play 시각 검증 + 본 PM Editor.log [BT55-MoveTiles] direct read
- BT49 후 "두 레이어 겹친 숨겨진 길 통과 X" 보고 영역 재발 시 PD 결정 영역
Debug.Log: [BT55-MoveTiles] moved=N (BT47 임계값 회귀·Sprite 강제·BT49 None 차단·thresholdY=...)
PD 결정 (2026-05-07): "그냥 단순히 Foreground에 충돌체크만 없애면 되지 않을까?"
변경:
- BT47 Foreground TilemapCollider2D 자동 부착 영역 폐기
- 기존 TilemapCollider2D Object.Destroy
- fgTilemap·fgTc null 유지 → 자동 분류(§83~) + 사후 복원(§129~) 자동 skip
- Foreground GameObject Layer 16 유지 (시각 정합)
영향 (PD 사전 명시 + 인지):
- 모든 Foreground Tile 충돌 X = 발판 위 착지 X (Drop-Through 패턴 폐기)
- BT47부터 자동 분류로 Foreground에 누적된 Tile들 = 시각만·자유 통과
- Level Tilemap (TileGround·TileGroundTop 1266개)만 영구 충돌 유지
본 PM 5회 가설 누적 부정확 후 PD 직접 단순 해결 채택:
- BT49 None 차단 (효과 X·restored=0)
- BT50 Grid→Sprite 강제 (효과 X·forced=0)
- BT51 사후 Grid→Sprite 폐기 (효과 X·restored=0)
- BT52 TileFloating* 단일 (decor=0 부정확)
- BT53 카탈로그 8종 확장 (decor=1 부정확·1266개 미식별)
→ PD 단순 제안 = 5회 가설 모두 우회
롤백 경로 (pm-auditor 권고):
- BT47 자동 분류 영역 + 사후 복원 영역 코드 보존 (fgTilemap null check skip만 추가)
- 회귀 시 fgTc 자동 부착 영역 회복 → 자동 분류 재가동 가능
후속 의무:
- PD Refresh+Play 시각 검증 + 본 PM Editor.log direct read
- 발판 위 착지 보존 의도 시 BT54 회귀 또는 카탈로그 v1.2 전환
Debug.Log: 자동 분류·사후 복원 출력 모두 fgTilemap null로 skip → BT54 시점 출력 X
PD 결정 (2026-05-07): "PM 권고안대로 해"
근본 원인 (Editor.log 직접 read):
- BT47 정상 시점 [BT47-MoveTiles] moved=1389 = PD 통과 가능 인식 영역
- BT52 보수적 후 [BT52-Classify] floating=122 = TileFloating* 3종만 = 배경·건물 7종 Level 잔존 = 영구 충돌
- PD 보고: "기존과 다르게 레벨 오브젝트가 생성됨·정상적인 플레이가 안 되고 있어"
- = 배경·건물 7종이 BT47 정상 시점 자동 분류된 결과로 추정 (가설)
옵션 A1 카탈로그 8종 SOT (GameOptimizer.cs SetupJumpThroughPlatforms 영역):
1. TileFloating* (3종) — 공중 발판 (Drop-Through):
- TileFloatingLeftEdge·TileFloatingRightEdge·TileFloatingTileMiddle
2. 배경·건물 (7종 — 자동 Foreground 이동·Drop-Through):
- ShortBuilding·TallBuilding·MidgroundFiller (건물·배경 채움)
- cloud·hillside·midground·mountains (배경 Parallax)
Level 잔존 (영구 충돌 또는 자연 통과):
- TileGround·TileGroundDark·TileGroundTop (3종 지면 — 영구 충돌)
- tree·plant·fence·house (4종 None — 자체 통과)
마이그레이션 X (PD 옵션 A 결정 유지 — Foreground 변경 X·위험 최소화).
사후 복원 영역 (BT51 None 처리) 유지.
가설 한계:
- 배경·건물 7종이 PD 의도 발판/통과 영역인지 확증 X (PD 시각 검증 후 정정 가능)
- 가설 실패 시 카탈로그 v1.1 재조정 또는 옵션 A2 (PD 직접 17종 명시) 전환 의무
Debug.Log: [BT53-Classify] moved=N (floating=F decor=D)
본 PM 직접 Editor.log read 의무 (PD 시각 검증 결과 보고 직후).
PD 결정 (2026-05-07): "A안대로 진행해"
근본 원인 (Editor.log 직접 read):
- [BT48-MoveTiles] moved=3524 비정상 (정상 1389 대비 2.5배)
- BT47/BT48 휴리스틱(임계값 playerY+1.5·작은 발판 가로≤8+위·아래 빈) = 정상 길·배경 벽지까지 자동 Foreground 이동
- → "숨겨진 레이어가 정상적인 길을 막고 있어" 근본 원인
- BT49/BT50/BT51 사후 복원 가설 모두 효과 X (restored=0/forced=0) — 4회 누적 부정확 자인
옵션 A 변경 (PD 승인 범위):
1. 휴리스틱 폐기: 임계값·작은 발판·BT49 None 차단 영역 모두 폐기
2. 새 알고리즘: Tile asset 이름 prefix "TileFloating" 3종만 자동 분류
(TileFloatingLeftEdge·TileFloatingRightEdge·TileFloatingTileMiddle — 카탈로그 17종 중 명시적 Floating 의도 3종)
3. 그 외 모든 Tile = Level 잔존 (PD Inspector 직접 분류 — 표준 Unity Tilemap 워크플로우)
4. 마이그레이션 X (PD 옵션 A 결정 — Foreground 변경 X·위험 최소화)
5. IsSmallAirPlatform 헬퍼 폐기 (dead code)
6. 사후 복원 영역 (BT51 None 처리) 유지
후속 의무:
- PD Refresh+Play 시각 검증 + 잘못 분류된 영역 발견 시 PD 직접 Inspector 정정 또는 카탈로그 확장 안건
- 본 PM 직접 Editor.log [BT52-Classify] floating moved=N read 의무
Debug.Log: [BT52-Classify] floating moved=N (Level→Foreground TileFloating* 3종만)
PD 보고 (BT50 후): "숨겨진 길이 최상단에 나와버려서 길을 다 막고 있어"
원인 가설:
- BT50 사후 복원 영역 = Foreground에 PD가 직접 그린 Grid Tile을 무차별 Sprite 강제
- PD Editor 직접 그린 Tile = default colliderType (Tile asset의 Grid) 의도
- 무차별 Sprite 강제 = PD 의도 형상 변형 → 통과 영역 차단
정정:
- 사후 복원: None Tile만 SetColliderType(None) 복원 (BT49 영역 정합 회귀)
- Grid→Sprite 강제 코드 영역 폐기
- 이동 시 Grid→Sprite 강제(상단)는 유지 — Level→Foreground 이동 신규 Tile만 Sprite 적용
효과:
1. Level→Foreground 이동 신규 Tile = Sprite Collider (BT49 후 통과 X 정정 유지)
2. PD 직접 그린 Grid Tile = default Grid Collider (PD 의도 형상 보존)
3. None Tile = 배경 통과 (BT49 영역 정합)
가설 한계 (pm-auditor Major #1 자인):
- BT50 사후 복원이 진짜 원인 확증 X. PD 시각 검증 후 효과 X 시 즉시 추가 가설 (Layer Matrix·UpdateContactFilter·Tilemap sortingOrder·Tile 위치 좌표) 전환 의무.
Debug.Log: [BT51-FgRefine] None restored=N (forced Sprite 카운터 폐기)
PD Refresh+Play 시 숨겨진 길 통과 + 이전 발판 정상 동작 시각 검증.
본 PM 직접 Editor.log read 의무 (PD 시각 검증 결과 보고 직후).
근본 원인 가설:
- Tile asset 카탈로그 17종: 13종 colliderType=1 (Grid·사각형) / 4종 0 (None — tree·plant·fence·house)
- 이전 BT47 = SetColliderType(Sprite) 무차별 강제 → 픽셀 정확 Collider (sprite 빈 영역 점프 통과 가능)
- BT49 = colliderType 존중 → Grid Tile은 SetColliderType(Grid) → 사각형 Collider (빈 영역 X) → 통과 차단
표준 패턴 정정 (BT49 metadata 존중 유지 + 이전 BT47 호환):
1. 이동 시: None=None (배경) / Grid→Sprite (강제) / Sprite=Sprite (그대로)
2. 사후 복원: Foreground 이미 그려진 Grid Tile = SetColliderType(Sprite) 강제 + ProcessTilemapChanges
- Debug.Log: [BT50-FgRefine] None restored=N / Grid→Sprite forced=M
가설 검증 의무 (pm-auditor Minor 권고):
PD 시각 검증 실패 시 Layer Matrix·UpdateContactFilter 가설 즉시 전환.
PD Refresh+Play 시 Console [BT50-FgRefine] forced=M + 숨겨진 길 통과 시각 검증.
본 PM 직접 Editor.log read 의무 (PD 시각 검증 결과 보고 직후).