From 53e6a5935f32e6e0575643706786f870da961c43 Mon Sep 17 00:00:00 2001 From: swrring Date: Fri, 8 May 2026 13:55:08 +0900 Subject: [PATCH] =?UTF-8?q?BT5-Dev=20#96:=20transform+body=20=EB=8F=99?= =?UTF-8?q?=EC=8B=9C=20push=20(=EA=B0=80=EC=9E=A5=EC=9E=90=EB=A6=AC=20?= =?UTF-8?q?=EB=B0=80=EB=A6=BC=20=EC=B0=A8=EB=8B=A8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 = 충분 영역 멀어진 후 재검출 --- Assets/Scripts/Mechanics/EnemyController.cs | 51 +++++++++++---------- 1 file changed, 28 insertions(+), 23 deletions(-) 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; } }