BT5-Dev #93: transform push 폐기·velocity.x 0 강제 (KinematicObject 정합)

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
- 이상 떨어짐 영역 차단
This commit is contained in:
깃 관리자 2026-05-08 13:28:32 +09:00
parent 7b484757e9
commit 585eca1022
1 changed files with 12 additions and 5 deletions

View File

@ -29,9 +29,8 @@ namespace Platformer.Mechanics
public float cliffCheckDistance = 1.0f; // BT92: 0.8→1.0 — 더 일찍 검출
public float cliffCheckDepth = 2.0f;
public LayerMask groundLayerMask = (1 << 0) | (1 << 16); // Layer 0 (지면) + Layer 16 (발판)
public float stuckThresholdTime = 0.3f; // BT92: 0.05→0.3 — phase 전환 직후 미세 정지 영역 무시 (좌우 반복 차단)
public float stuckThresholdTime = 0.15f; // BT93: 0.3→0.15 (150ms·밀림 누적 차단)
public float stuckMoveThreshold = 0.02f; // 정지 판정 거리 임계값
public float cliffSafePushDistance = 0.15f; // BT92: 절벽 검출 시 안전 영역 push 거리
public float waitMinTime = 1f; // patrol arrive·벽·절벽 후 대기 random 영역
public float waitMaxTime = 3f;
@ -135,7 +134,8 @@ namespace Platformer.Mechanics
// BT90 — 수평 Raycast 영역 폐기 (BT89 거짓 양성 — 같은 Tile cell 영역 검출)
// 벽 영역 = stuckTimer 영역 (50ms 정지 시 즉시 phase+2)으로 처리
// BT92 — 절벽 검출: 즉시 반대 방향 + transform 안전 push (1 frame 지연 영역에서 발 영역 절벽 진입 차단)
// BT93 — 절벽 검출: velocity.x = 0 강제 (관성 차단·발 절벽 진입 X) + phase+2 + 반대 방향 이동
// transform.position 직접 set 폐기 (BT92 영역·KinematicObject body.position 충돌)
if (_collider != null)
{
Vector2 footAhead = new Vector2(
@ -145,7 +145,10 @@ namespace Platformer.Mechanics
RaycastHit2D groundHit = Physics2D.Raycast(footAhead, Vector2.down, cliffCheckDepth, groundLayerMask);
if (groundHit.collider == null)
{
transform.position += new Vector3(-moveDir * cliffSafePushDistance, 0f, 0f);
if (control != null)
{
control.velocity = new Vector2(0f, control.velocity.y);
}
_patrolPhase = (_patrolPhase + 2) % 4;
SetNextPatrolTarget();
_stuckTimer = 0f;
@ -156,12 +159,16 @@ namespace Platformer.Mechanics
}
}
// BT91 — 벽 정지 (stuckTimer): 즉시 반대 방향 이동 (waitTimer X — 부들부들 차단)
// BT93 — 벽 정지 (stuckTimer 150ms): velocity.x = 0 + phase+2 + 반대 방향
if (Mathf.Abs(transform.position.x - _lastX) < stuckMoveThreshold)
{
_stuckTimer += Time.deltaTime;
if (_stuckTimer > stuckThresholdTime)
{
if (control != null)
{
control.velocity = new Vector2(0f, control.velocity.y);
}
_patrolPhase = (_patrolPhase + 2) % 4;
SetNextPatrolTarget();
_stuckTimer = 0f;