BT5-Dev #107: Tilemap cell 기반 측정 (PD 근본 진단)

PD 근본 진단 (2026-05-08): "절벽 체크 로직이 잘못된 것이 근본원인" + 공중 부유 발생

본 PM 22회+ 가설 누적 부정확 자인. PD 근본 진단 정합 — Raycast 영역 자체 부정확.

정정 (BT107):
1. BT106 y 강제 고정 영역 폐기 (공중 부유 원인)
2. MeasureSafeWalkDistance 영역 = Tilemap cell 기반 재설계:
   - GameObject.Find('Level') + 'AutoForeground' → groundTilemaps 영역
   - Enemy 발 아래 cell = 시작 cell (Tilemap.WorldToCell)
   - 좌·우 연속 Tile 영역 끝 영역 검색 (cell + Vector3Int.left/right)
   - HasTileInAnyTilemap 검사 (Level + AutoForeground)
   - 마지막 Tile cell center 영역까지 거리 - 0.5m margin

효과:
- Raycast 영역 부정확 영역 폐기 (Tile data 직접 사용)
- Tile cell 단위 정확 영역 측정 → patrol 영역 정확
- 시작 cell 발판 X 시 = 0 반환 (재배치 영역 BT104에서 처리)
- 공중 부유 영역 차단 (BT106 폐기)
This commit is contained in:
깃 관리자 2026-05-08 15:34:53 +09:00
parent 589f6ad258
commit 1137583b4b
1 changed files with 54 additions and 17 deletions

View File

@ -166,18 +166,63 @@ namespace Platformer.Mechanics
_lastX = transform.position.x;
}
// BT105 — 정확 측정·안전 margin 2.0m (PD 보고 떨어짐 잔존: 보수적 영역으로 절벽 도달 X 보장)
// BT107 — Tilemap 영역 cell 기반 측정 (PD 근본 진단: Raycast 영역 자체 부정확)
// Enemy 시작 위치 cell → 좌·우 연속 Tile 영역 끝 영역까지 거리 = 안전 patrol 거리
float MeasureSafeWalkDistance(float dir)
{
if (_collider == null) return patrolMaxRange;
float groundY = _collider.bounds.min.y + 0.05f;
for (float d = 0.1f; d <= patrolMaxRange; d += 0.1f)
if (_collider == null) return 0f;
var groundTilemaps = new System.Collections.Generic.List<UnityEngine.Tilemaps.Tilemap>();
var levelGo = GameObject.Find("Level");
if (levelGo != null)
{
Vector2 origin = new Vector2(_startX + dir * d, groundY);
RaycastHit2D hit = Physics2D.Raycast(origin, Vector2.down, cliffCheckDepth, groundLayerMask);
if (hit.collider == null) return Mathf.Max(0f, d - 2.0f); // BT105: 0.5→2.0m
var t = levelGo.GetComponent<UnityEngine.Tilemaps.Tilemap>();
if (t != null) groundTilemaps.Add(t);
}
return patrolMaxRange;
var autoFgGo = GameObject.Find("AutoForeground");
if (autoFgGo != null)
{
var t = autoFgGo.GetComponent<UnityEngine.Tilemaps.Tilemap>();
if (t != null) groundTilemaps.Add(t);
}
if (groundTilemaps.Count == 0) return 0f;
// 시작 cell = Enemy 발 아래 cell
Vector3 footPos = new Vector3(_startX, _collider.bounds.min.y - 0.1f, 0f);
UnityEngine.Tilemaps.Tilemap startTm = null;
Vector3Int startCell = Vector3Int.zero;
foreach (var tm in groundTilemaps)
{
Vector3Int cell = tm.WorldToCell(footPos);
if (tm.HasTile(cell))
{
startTm = tm;
startCell = cell;
break;
}
}
if (startTm == null) return 0f;
// 좌·우 연속 Tile 영역 끝 영역 검색
int dirCell = (int)Mathf.Sign(dir);
Vector3Int cellIter = startCell;
for (int steps = 0; steps < 500; steps++)
{
Vector3Int nextCell = cellIter + new Vector3Int(dirCell, 0, 0);
if (!HasTileInAnyTilemap(groundTilemaps, nextCell)) break;
cellIter = nextCell;
}
// 마지막 Tile cell 영역 center 영역까지 거리
Vector3 lastTileWorld = startTm.CellToWorld(cellIter) + new Vector3(0.5f, 0f, 0f);
float distance = Mathf.Abs(lastTileWorld.x - _startX);
return Mathf.Max(0f, distance - 0.5f); // 안전 margin 0.5m (Tile cell 영역 안)
}
static bool HasTileInAnyTilemap(System.Collections.Generic.List<UnityEngine.Tilemaps.Tilemap> tms, Vector3Int cell)
{
foreach (var tm in tms) if (tm != null && tm.HasTile(cell)) return true;
return false;
}
void SetNextPatrolTarget()
@ -210,15 +255,7 @@ namespace Platformer.Mechanics
return;
}
// BT106 — y 강제 고정 (PD 명시 2026-05-08): Enemy 영역 매 frame _startY 영역 영구 위치
// 떨어짐 영역 0.1m 이상 발생 시 = 즉시 _startY 복귀 → 떨어짐 영역 영구 차단
if (Mathf.Abs(transform.position.y - _startY) > 0.1f)
{
Vector3 fixedY = new Vector3(transform.position.x, _startY, transform.position.z);
transform.position = fixedY;
if (_body != null) _body.position = fixedY;
if (control != null) control.velocity = new Vector2(control.velocity.x, 0f);
}
// BT107 — BT106 y 강제 고정 영역 폐기 (PD 보고: 공중 부유 영역 원인)
// 대기 영역 — control.move.x = 0 + Timer 감소
if (_waitTimer > 0f)