diff --git a/Assets/Scripts/Mechanics/EnemyController.cs b/Assets/Scripts/Mechanics/EnemyController.cs index 94ee410..97b32c1 100644 --- a/Assets/Scripts/Mechanics/EnemyController.cs +++ b/Assets/Scripts/Mechanics/EnemyController.cs @@ -140,6 +140,9 @@ namespace Platformer.Mechanics // BT107 — Tilemap 영역 cell 기반 측정 (PD 근본 진단: Raycast 영역 자체 부정확) // Enemy 시작 위치 cell → 좌·우 연속 Tile 영역 끝 영역까지 거리 = 안전 patrol 거리 + // BT110 (2026-05-08) — 다중 footPos offset fallback (PD 보고: 16건 중 8~9건 이동 X) + // 근본: Enemy 인스턴스마다 collider bounds·sprite bounds·transform.y 영역 변동 + // → 다단 fallback (sprite/collider/transform × 다중 offset) 첫 HasTile cell 채택 float MeasureSafeWalkDistance(float dir) { if (_collider == null) return 0f; @@ -159,23 +162,38 @@ namespace Platformer.Mechanics } if (groundTilemaps.Count == 0) return 0f; - // BT109 — footPos 영역 정정 (PD 보고 2026-05-08: 이동 X) - // bounds.min.y - 0.1f = Enemy 발 영역 cell → 발판 cell X - // → bounds.min.y - 0.5f = 발판 cell 영역 정확 검사 - Vector3 footPos = new Vector3(_startX, _collider.bounds.min.y - 0.5f, 0f); + // BT110 — 다중 footPos offset fallback + // sprite·collider·transform 각 영역 발 후보 + 다중 offset (-0.1·-0.3·-0.5·-0.7·-1.0) + // 각 후보 → 모든 groundTilemap HasTile 검사 → 첫 HasTile cell 채택 + float colliderFootY = _collider.bounds.min.y; + float spriteFootY = spriteRenderer != null ? spriteRenderer.bounds.min.y : colliderFootY; + float transformY = transform.position.y; + float[] candidateYs = new float[] { + spriteFootY - 0.1f, spriteFootY - 0.3f, spriteFootY - 0.5f, spriteFootY - 0.7f, spriteFootY - 1.0f, + colliderFootY - 0.1f, colliderFootY - 0.3f, colliderFootY - 0.5f, colliderFootY - 0.7f, colliderFootY - 1.0f, + transformY - 0.1f, transformY - 0.3f, transformY - 0.5f, transformY - 0.7f, transformY - 1.0f + }; + UnityEngine.Tilemaps.Tilemap startTm = null; Vector3Int startCell = Vector3Int.zero; - foreach (var tm in groundTilemaps) + float chosenFootY = 0f; + foreach (float candY in candidateYs) { - Vector3Int cell = tm.WorldToCell(footPos); - if (tm.HasTile(cell)) + Vector3 footPos = new Vector3(_startX, candY, 0f); + foreach (var tm in groundTilemaps) { - startTm = tm; - startCell = cell; - break; + Vector3Int cell = tm.WorldToCell(footPos); + if (tm.HasTile(cell)) + { + startTm = tm; + startCell = cell; + chosenFootY = candY; + break; + } } + if (startTm != null) break; } - Debug.Log($"[Enemy@{name}] dir={dir} footPos.y={footPos.y:F2} startTm={(startTm!=null?startTm.name:"NULL")} startCell={startCell}"); + Debug.Log($"[Enemy@{name}] dir={dir} startY={transformY:F2} colliderFoot={colliderFootY:F2} spriteFoot={spriteFootY:F2} chosenFootY={chosenFootY:F2} startTm={(startTm!=null?startTm.name:"NULL")} startCell={startCell}"); if (startTm == null) return 0f; // 좌·우 연속 Tile 영역 끝 영역 검색