fix(BT12-Dev): cliffCheck 매 frame·VisualBounds → SpriteRenderer 정정

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>
This commit is contained in:
깃 관리자 2026-05-12 16:51:44 +09:00
parent fc351795e7
commit e3e4f97a6f
1 changed files with 19 additions and 19 deletions

View File

@ -52,10 +52,10 @@ namespace Platformer.Mechanics
public Bounds Bounds => _collider.bounds;
/// <summary>
/// BT12-Dev 2026-05-12 — Collider Bounds 사용 (PD: Visual 자식 분리 후 sprite bounds 충돌 판정 정합 X).
/// CapsuleCollider2D는 실제 충돌 영역·정확한 Player 접촉 판정.
/// BT12-Dev 2026-05-12 재정정 — SpriteRenderer (Visual) bounds 우선 (PD: Player 피해 X·CapsuleCollider 작음).
/// Visual.SpriteRenderer.bounds = sprite 실제 시각 영역·Player 접촉 판정 정합.
/// </summary>
public Bounds VisualBounds => _collider != null ? _collider.bounds : (spriteRenderer != null ? spriteRenderer.bounds : new Bounds());
public Bounds VisualBounds => spriteRenderer != null ? spriteRenderer.bounds : (_collider != null ? _collider.bounds : new Bounds());
PlayerController _cachedPlayer;
bool _ignoreCollisionApplied;
@ -320,24 +320,24 @@ namespace Platformer.Mechanics
// BT90 — 수평 Raycast 영역 폐기 (BT89 거짓 양성 — 같은 Tile cell 영역 검출)
// 벽 영역 = stuckTimer 영역 (50ms 정지 시 즉시 phase+2)으로 처리
// BT94 — 절벽·벽 검출은 phase cooldown 영역 끝난 후 활성 (좌우 반복 차단)
// BT12-Dev 2026-05-12 — phaseCooldown 가드 폐기 (PD: 한방만 바라보다 떨어짐).
// 매 frame cliffCheck → 발판 끝 즉시 회피·낙하 차단.
if (_collider != null)
{
Vector2 footAhead = new Vector2(
_collider.bounds.center.x + moveDir * cliffCheckDistance,
_collider.bounds.min.y + 0.05f
);
RaycastHit2D groundHit = Physics2D.Raycast(footAhead, Vector2.down, cliffCheckDepth, groundLayerMask);
if (groundHit.collider == null)
{
TriggerReverse(moveDir, 0.3f);
return;
}
}
if (_phaseCooldown <= 0f)
{
// BT96 — 절벽·벽 검출: transform + body 동시 push (가장자리에서 안전 영역으로 즉시 이동)
if (_collider != null)
{
Vector2 footAhead = new Vector2(
_collider.bounds.center.x + moveDir * cliffCheckDistance,
_collider.bounds.min.y + 0.05f
);
RaycastHit2D groundHit = Physics2D.Raycast(footAhead, Vector2.down, cliffCheckDepth, groundLayerMask);
if (groundHit.collider == null)
{
TriggerReverse(moveDir, 0.3f);
return;
}
}
if (Mathf.Abs(transform.position.x - _lastX) < stuckMoveThreshold)
{
_stuckTimer += Time.deltaTime;