diff --git a/Assets/Scripts/Mechanics/EnemyController.cs b/Assets/Scripts/Mechanics/EnemyController.cs index c0109e2..4d80df2 100644 --- a/Assets/Scripts/Mechanics/EnemyController.cs +++ b/Assets/Scripts/Mechanics/EnemyController.cs @@ -50,6 +50,7 @@ namespace Platformer.Mechanics internal Collider2D _collider; internal AudioSource _audio; SpriteRenderer spriteRenderer; + Rigidbody2D _body; // BT96: KinematicObject body 영역 직접 set 위해 캐싱 public Bounds Bounds => _collider.bounds; @@ -68,6 +69,7 @@ namespace Platformer.Mechanics _collider = GetComponent(); _audio = GetComponent(); spriteRenderer = GetComponent(); + _body = GetComponent(); // BT5-Dev #21 — Awake 시점 fallback 추가 (Player tag 영역 미설정 영역 대비) var playerObj = GameObject.FindGameObjectWithTag("Player"); @@ -100,7 +102,29 @@ namespace Platformer.Mechanics SetNextPatrolTarget(); } - // BT94 — 시작 위치에서 좌·우 walk 영역 절벽 검출까지 거리 측정 (안전 margin 1.5m 차감) + // BT96 — 절벽·벽 검출 시 즉시 반대 방향 이동 (transform + body 동시 push·KinematicObject 정합) + void TriggerReverse(float moveDir, float pushDistance) + { + _patrolPhase = (_patrolPhase + 2) % 4; + SetNextPatrolTarget(); + + // transform + body 동시 push (KinematicObject body.position 영역 동기화) + Vector3 newPos = transform.position + new Vector3(-moveDir * pushDistance, 0f, 0f); + transform.position = newPos; + if (_body != null) _body.position = newPos; + + // velocity.x 즉시 반대 방향 + move.x 반대 (다음 frame 안정 이동) + if (control != null) + { + control.velocity = new Vector2(-moveDir * control.maxSpeed, control.velocity.y); + control.move.x = -moveDir; + } + + _stuckTimer = 0f; + _phaseCooldown = PHASE_COOLDOWN; + _lastX = transform.position.x; + } + float MeasureSafeWalkDistance(float dir) { float groundY = transform.position.y - 0.34f; // 발 영역 위 0.05m (Capsule offset 영역 기반 추정) @@ -171,7 +195,7 @@ namespace Platformer.Mechanics // BT94 — 절벽·벽 검출은 phase cooldown 영역 끝난 후 활성 (좌우 반복 차단) if (_phaseCooldown <= 0f) { - // BT95 — 절벽 검출: velocity.x 즉시 반대 방향 큰 속도 (가장자리에서 빠르게 멀어짐) + // BT96 — 절벽·벽 검출: transform + body 동시 push (가장자리에서 안전 영역으로 즉시 이동) if (_collider != null) { Vector2 footAhead = new Vector2( @@ -181,36 +205,17 @@ namespace Platformer.Mechanics RaycastHit2D groundHit = Physics2D.Raycast(footAhead, Vector2.down, cliffCheckDepth, groundLayerMask); if (groundHit.collider == null) { - _patrolPhase = (_patrolPhase + 2) % 4; - SetNextPatrolTarget(); - if (control != null) - { - control.velocity = new Vector2(-moveDir * control.maxSpeed, control.velocity.y); - control.move.x = -moveDir; - } - _stuckTimer = 0f; - _phaseCooldown = PHASE_COOLDOWN; - _lastX = transform.position.x; + TriggerReverse(moveDir, 0.3f); return; } } - // BT95 — 벽 정지 (stuckTimer): velocity.x 즉시 반대 방향 큰 속도 if (Mathf.Abs(transform.position.x - _lastX) < stuckMoveThreshold) { _stuckTimer += Time.deltaTime; if (_stuckTimer > stuckThresholdTime) { - _patrolPhase = (_patrolPhase + 2) % 4; - SetNextPatrolTarget(); - if (control != null) - { - control.velocity = new Vector2(-moveDir * control.maxSpeed, control.velocity.y); - control.move.x = -moveDir; - } - _stuckTimer = 0f; - _phaseCooldown = PHASE_COOLDOWN; - _lastX = transform.position.x; + TriggerReverse(moveDir, 0.2f); return; } }