diff --git a/Assets/Scripts/Mechanics/GameOptimizer.cs b/Assets/Scripts/Mechanics/GameOptimizer.cs index 836f088..b24e528 100644 --- a/Assets/Scripts/Mechanics/GameOptimizer.cs +++ b/Assets/Scripts/Mechanics/GameOptimizer.cs @@ -29,6 +29,8 @@ namespace Platformer.Mechanics // Layer Matrix: Player(13) ↔ Enemy(14) 충돌 OFF. Physics2D.IgnoreLayerCollision(13, 14, true); + // BT99 — Player(13) ↔ EnemyWall(18) 충돌 OFF (투명벽은 Enemy만 차단). + Physics2D.IgnoreLayerCollision(13, 18, true); } [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)] @@ -150,10 +152,78 @@ namespace Platformer.Mechanics var lvlTc = levelGo.GetComponent(); 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}"); + + // BT99 — 절벽 영역 자동 검출·투명벽 (EnemyWall Layer 18) GameObject 자동 생성 + SetupCliffWalls(levelTilemap, fgTilemap, pdForeground); } } } + /// + /// BT99 — 절벽 영역 자동 검출 + 투명벽 GameObject 생성 (Enemy 차단·Player 통과). + /// 모든 Tilemap (Level·AutoForeground·PD Foreground) 영역에서 Tile 좌·우 인접 영역이 모든 Tilemap에 Tile X 시 = 절벽 가장자리. + /// + static void SetupCliffWalls(UnityEngine.Tilemaps.Tilemap levelTm, UnityEngine.Tilemaps.Tilemap autoFgTm, GameObject pdFg) + { + UnityEngine.Tilemaps.Tilemap pdFgTm = pdFg != null ? pdFg.GetComponent() : null; + + GameObject wallParent = GameObject.Find("CliffWalls"); + if (wallParent == null) wallParent = new GameObject("CliffWalls"); + + int wallCount = 0; + var allTilemaps = new System.Collections.Generic.List(); + 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 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(); + box.size = new Vector2(0.1f, 3f); // 좁고 높은 영역 + box.offset = new Vector2(0f, 1f); // Tile 위 영역 차단 (지면 위 1.5m) + } + /// /// 작은 공중 발판 판별: 위·아래 인접 Tile이 모두 빈 공간 + 가로 연속 길이 maxWidth 이하. /// 일반 지면(10+ tile 가로) 잘못 분류 방지. diff --git a/ProjectSettings/TagManager.asset b/ProjectSettings/TagManager.asset index ac346d4..7b98209 100644 --- a/ProjectSettings/TagManager.asset +++ b/ProjectSettings/TagManager.asset @@ -24,7 +24,7 @@ TagManager: - - - - - + - EnemyWall - - -