From 63cecf04ec1a621f31d8bf37e2cf68f55594b0e9 Mon Sep 17 00:00:00 2001 From: swrring Date: Fri, 8 May 2026 14:55:16 +0900 Subject: [PATCH] =?UTF-8?q?BT5-Dev=20#99:=20EnemyWall=20Layer=2018=C2=B7?= =?UTF-8?q?=ED=88=AC=EB=AA=85=EB=B2=BD=20=EC=9E=90=EB=8F=99=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20(PD=20=EB=AA=85=EC=8B=9C=20=EC=B1=84=ED=83=9D)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 도달 가설) --- Assets/Scripts/Mechanics/GameOptimizer.cs | 70 +++++++++++++++++++++++ ProjectSettings/TagManager.asset | 2 +- 2 files changed, 71 insertions(+), 1 deletion(-) 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 - - -