BT5-Dev #50: 두 레이어 겹친 숨겨진 길 통과 복원 — Grid→Sprite Collider 강제

근본 원인 가설:
- Tile asset 카탈로그 17종: 13종 colliderType=1 (Grid·사각형) / 4종 0 (None — tree·plant·fence·house)
- 이전 BT47 = SetColliderType(Sprite) 무차별 강제 → 픽셀 정확 Collider (sprite 빈 영역 점프 통과 가능)
- BT49 = colliderType 존중 → Grid Tile은 SetColliderType(Grid) → 사각형 Collider (빈 영역 X) → 통과 차단

표준 패턴 정정 (BT49 metadata 존중 유지 + 이전 BT47 호환):
1. 이동 시: None=None (배경) / Grid→Sprite (강제) / Sprite=Sprite (그대로)
2. 사후 복원: Foreground 이미 그려진 Grid Tile = SetColliderType(Sprite) 강제 + ProcessTilemapChanges
- Debug.Log: [BT50-FgRefine] None restored=N / Grid→Sprite forced=M

가설 검증 의무 (pm-auditor Minor 권고):
PD 시각 검증 실패 시 Layer Matrix·UpdateContactFilter 가설 즉시 전환.

PD Refresh+Play 시 Console [BT50-FgRefine] forced=M + 숨겨진 길 통과 시각 검증.
본 PM 직접 Editor.log read 의무 (PD 시각 검증 결과 보고 직후).
This commit is contained in:
깃 관리자 2026-05-07 22:29:13 +09:00
parent 9adfc64625
commit 867f0de253
1 changed files with 14 additions and 4 deletions

View File

@ -113,7 +113,11 @@ namespace Platformer.Mechanics
if (!aboveThreshold && !isSmallAir) continue; if (!aboveThreshold && !isSmallAir) continue;
var tile = levelTilemap.GetTile(pos); var tile = levelTilemap.GetTile(pos);
// BT49 — Foreground 이동 시 Tile asset 원래 colliderType 존중 (None=배경, Sprite=발판) // BT49 — Foreground 이동 시 Tile asset 원래 colliderType 존중 (None=배경, Sprite=발판)
// BT50 — Grid (1) Tile은 Sprite (2)로 강제. 이전 BT47 호환 — Grid 사각형 Collider는
// sprite 빈 픽셀 영역(두 레이어 겹친 숨겨진 길)을 차단 → Sprite 정확 Collider로 빈 영역 통과 보존
var srcColliderType = (tileAsset != null) ? tileAsset.colliderType : UnityEngine.Tilemaps.Tile.ColliderType.Sprite; var srcColliderType = (tileAsset != null) ? tileAsset.colliderType : UnityEngine.Tilemaps.Tile.ColliderType.Sprite;
if (srcColliderType == UnityEngine.Tilemaps.Tile.ColliderType.Grid)
srcColliderType = UnityEngine.Tilemaps.Tile.ColliderType.Sprite;
fgTilemap.SetTile(pos, tile); fgTilemap.SetTile(pos, tile);
fgTilemap.SetColliderType(pos, srcColliderType); fgTilemap.SetColliderType(pos, srcColliderType);
levelTilemap.SetTile(pos, null); levelTilemap.SetTile(pos, null);
@ -132,7 +136,7 @@ namespace Platformer.Mechanics
// BT47이 SetColliderType(Sprite) 무차별 강제 → 배경 Tile도 발판처럼 충돌 → Tile asset metadata 존중으로 정정 // BT47이 SetColliderType(Sprite) 무차별 강제 → 배경 Tile도 발판처럼 충돌 → Tile asset metadata 존중으로 정정
if (fgTilemap != null && fgTc != null) if (fgTilemap != null && fgTc != null)
{ {
int restored = 0; int restoredNone = 0, forcedSprite = 0;
var fgBounds = fgTilemap.cellBounds; var fgBounds = fgTilemap.cellBounds;
for (int x = fgBounds.xMin; x <= fgBounds.xMax; x++) for (int x = fgBounds.xMin; x <= fgBounds.xMax; x++)
{ {
@ -145,12 +149,18 @@ namespace Platformer.Mechanics
if (fgTileAsset.colliderType == UnityEngine.Tilemaps.Tile.ColliderType.None) if (fgTileAsset.colliderType == UnityEngine.Tilemaps.Tile.ColliderType.None)
{ {
fgTilemap.SetColliderType(pos, UnityEngine.Tilemaps.Tile.ColliderType.None); fgTilemap.SetColliderType(pos, UnityEngine.Tilemaps.Tile.ColliderType.None);
restored++; restoredNone++;
}
else if (fgTileAsset.colliderType == UnityEngine.Tilemaps.Tile.ColliderType.Grid)
{
// BT50 — Grid Tile은 Sprite로 강제 (이전 BT47 호환·sprite 빈 픽셀 영역 통과 보존)
fgTilemap.SetColliderType(pos, UnityEngine.Tilemaps.Tile.ColliderType.Sprite);
forcedSprite++;
} }
} }
} }
if (restored > 0) fgTc.ProcessTilemapChanges(); if (restoredNone + forcedSprite > 0) fgTc.ProcessTilemapChanges();
Debug.Log($"[BT49-Background] Foreground tile colliderType=None restored: {restored} (배경 Tile 충돌 차단)"); Debug.Log($"[BT50-FgRefine] colliderType=None restored: {restoredNone} (배경 통과) / Grid→Sprite forced: {forcedSprite} (sprite 빈 영역 통과 보존)");
} }
Debug.Log($"[BT48-DropThrough] Layer16 applied={applied} levelKeptLayer0={levelKept} excluded={excluded} total={allColliders.Length}"); Debug.Log($"[BT48-DropThrough] Layer16 applied={applied} levelKeptLayer0={levelKept} excluded={excluded} total={allColliders.Length}");