BT5-Dev #99: EnemyWall Layer 18·투명벽 자동 생성 (PD 명시 채택)
PD 명시 (2026-05-08): "낭떠러지 앞에 몬스터만 지나갈 수 없는 투명한 벽을 세우면 안돼?" 본 PM 17회 가설 누적 부정확 자인 후 PD 직접 단순 해결 채택. 변경: 1. ProjectSettings/TagManager.asset: - Layer 18 = 'EnemyWall' 신규 추가 2. GameOptimizer.cs Init(): - Physics2D.IgnoreLayerCollision(13, 18, true) — Player ↔ EnemyWall 충돌 OFF (Player 통과) 3. GameOptimizer.cs SetupCliffWalls() 신규: - 모든 Tilemap (Level·AutoForeground·PD Foreground) Tile 영역 순회 - Tile 좌·우 인접 영역이 모든 Tilemap에 Tile X 시 = 절벽 가장자리 - 가장자리 위치에 BoxCollider2D GameObject (CliffWall) 자동 생성 - Layer 18 (EnemyWall) + size (0.1×3) + offset (0, 1) - parent = CliffWalls GameObject (그룹 영역) 효과: - Player ↔ EnemyWall 충돌 OFF → Player 자유 통과 - Enemy ↔ EnemyWall 충돌 ON → Enemy 절벽 가장자리 도달 시 차단 - 알고리즘 부정합 무관 (물리 영역 차단) - BT98 R1 방어 영역 = 보조 (투명벽 차단으로 X 도달 가설)
This commit is contained in:
parent
b3cbbdbf40
commit
63cecf04ec
|
|
@ -29,6 +29,8 @@ namespace Platformer.Mechanics
|
||||||
|
|
||||||
// Layer Matrix: Player(13) ↔ Enemy(14) 충돌 OFF.
|
// Layer Matrix: Player(13) ↔ Enemy(14) 충돌 OFF.
|
||||||
Physics2D.IgnoreLayerCollision(13, 14, true);
|
Physics2D.IgnoreLayerCollision(13, 14, true);
|
||||||
|
// BT99 — Player(13) ↔ EnemyWall(18) 충돌 OFF (투명벽은 Enemy만 차단).
|
||||||
|
Physics2D.IgnoreLayerCollision(13, 18, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
|
||||||
|
|
@ -150,10 +152,78 @@ namespace Platformer.Mechanics
|
||||||
var lvlTc = levelGo.GetComponent<UnityEngine.Tilemaps.TilemapCollider2D>();
|
var lvlTc = levelGo.GetComponent<UnityEngine.Tilemaps.TilemapCollider2D>();
|
||||||
if (lvlTc != null) lvlTc.ProcessTilemapChanges();
|
if (lvlTc != null) lvlTc.ProcessTilemapChanges();
|
||||||
Debug.Log($"[GameOptimizer] AutoForeground moved={movedHigh + movedSmall} (high={movedHigh} small={movedSmall} threshold={airThresholdY:F2}) / Layer16 applied={applied} levelKept0={levelKept} excluded={excluded}");
|
Debug.Log($"[GameOptimizer] AutoForeground moved={movedHigh + movedSmall} (high={movedHigh} small={movedSmall} threshold={airThresholdY:F2}) / Layer16 applied={applied} levelKept0={levelKept} excluded={excluded}");
|
||||||
|
|
||||||
|
// BT99 — 절벽 영역 자동 검출·투명벽 (EnemyWall Layer 18) GameObject 자동 생성
|
||||||
|
SetupCliffWalls(levelTilemap, fgTilemap, pdForeground);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// BT99 — 절벽 영역 자동 검출 + 투명벽 GameObject 생성 (Enemy 차단·Player 통과).
|
||||||
|
/// 모든 Tilemap (Level·AutoForeground·PD Foreground) 영역에서 Tile 좌·우 인접 영역이 모든 Tilemap에 Tile X 시 = 절벽 가장자리.
|
||||||
|
/// </summary>
|
||||||
|
static void SetupCliffWalls(UnityEngine.Tilemaps.Tilemap levelTm, UnityEngine.Tilemaps.Tilemap autoFgTm, GameObject pdFg)
|
||||||
|
{
|
||||||
|
UnityEngine.Tilemaps.Tilemap pdFgTm = pdFg != null ? pdFg.GetComponent<UnityEngine.Tilemaps.Tilemap>() : null;
|
||||||
|
|
||||||
|
GameObject wallParent = GameObject.Find("CliffWalls");
|
||||||
|
if (wallParent == null) wallParent = new GameObject("CliffWalls");
|
||||||
|
|
||||||
|
int wallCount = 0;
|
||||||
|
var allTilemaps = new System.Collections.Generic.List<UnityEngine.Tilemaps.Tilemap>();
|
||||||
|
if (levelTm != null) allTilemaps.Add(levelTm);
|
||||||
|
if (autoFgTm != null) allTilemaps.Add(autoFgTm);
|
||||||
|
if (pdFgTm != null) allTilemaps.Add(pdFgTm);
|
||||||
|
|
||||||
|
foreach (var tm in allTilemaps)
|
||||||
|
{
|
||||||
|
var bounds = tm.cellBounds;
|
||||||
|
for (int x = bounds.xMin; x <= bounds.xMax; x++)
|
||||||
|
{
|
||||||
|
for (int y = bounds.yMin; y <= bounds.yMax; y++)
|
||||||
|
{
|
||||||
|
var pos = new Vector3Int(x, y, 0);
|
||||||
|
if (!tm.HasTile(pos)) continue;
|
||||||
|
|
||||||
|
bool leftCliff = !HasTileInAny(allTilemaps, pos + Vector3Int.left);
|
||||||
|
bool rightCliff = !HasTileInAny(allTilemaps, pos + Vector3Int.right);
|
||||||
|
if (!leftCliff && !rightCliff) continue;
|
||||||
|
|
||||||
|
Vector3 worldPos = tm.CellToWorld(pos) + new Vector3(0.5f, 0.5f, 0f); // cell center
|
||||||
|
if (leftCliff)
|
||||||
|
{
|
||||||
|
CreateCliffWall(wallParent, worldPos + new Vector3(-0.5f, 0f, 0f));
|
||||||
|
wallCount++;
|
||||||
|
}
|
||||||
|
if (rightCliff)
|
||||||
|
{
|
||||||
|
CreateCliffWall(wallParent, worldPos + new Vector3(0.5f, 0f, 0f));
|
||||||
|
wallCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Debug.Log($"[GameOptimizer] CliffWalls (EnemyWall Layer 18) 생성: {wallCount}개");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool HasTileInAny(System.Collections.Generic.List<UnityEngine.Tilemaps.Tilemap> tms, Vector3Int pos)
|
||||||
|
{
|
||||||
|
foreach (var tm in tms) if (tm != null && tm.HasTile(pos)) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CreateCliffWall(GameObject parent, Vector3 worldPos)
|
||||||
|
{
|
||||||
|
GameObject wall = new GameObject("CliffWall");
|
||||||
|
wall.transform.SetParent(parent.transform, false);
|
||||||
|
wall.transform.position = worldPos;
|
||||||
|
wall.layer = 18; // EnemyWall
|
||||||
|
var box = wall.AddComponent<BoxCollider2D>();
|
||||||
|
box.size = new Vector2(0.1f, 3f); // 좁고 높은 영역
|
||||||
|
box.offset = new Vector2(0f, 1f); // Tile 위 영역 차단 (지면 위 1.5m)
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 작은 공중 발판 판별: 위·아래 인접 Tile이 모두 빈 공간 + 가로 연속 길이 maxWidth 이하.
|
/// 작은 공중 발판 판별: 위·아래 인접 Tile이 모두 빈 공간 + 가로 연속 길이 maxWidth 이하.
|
||||||
/// 일반 지면(10+ tile 가로) 잘못 분류 방지.
|
/// 일반 지면(10+ tile 가로) 잘못 분류 방지.
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ TagManager:
|
||||||
-
|
-
|
||||||
-
|
-
|
||||||
-
|
-
|
||||||
-
|
- EnemyWall
|
||||||
-
|
-
|
||||||
-
|
-
|
||||||
-
|
-
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue