From 725c7105e336bb6db131f5f8585a1f01231e6a39 Mon Sep 17 00:00:00 2001 From: swrring Date: Fri, 8 May 2026 15:16:10 +0900 Subject: [PATCH] =?UTF-8?q?BT5-Dev=20#102:=20=ED=88=AC=EB=AA=85=EB=B2=BD?= =?UTF-8?q?=20=ED=8F=90=EA=B8=B0=C2=B7y=20=EA=B2=80=EC=B6=9C=20=ED=85=94?= =?UTF-8?q?=EB=A0=88=ED=8F=AC=ED=8A=B8=20(PD=20=EB=AA=85=EC=8B=9C=20?= =?UTF-8?q?=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): "몬스터의 투명벽을 삭제하고 몬스터가 낭떠러지로 떨어지지 않도록 할 방법을 찾아봐" 변경: 1. GameOptimizer.cs: - Init() Physics2D.IgnoreLayerCollision(13, 18) 영역 폐기 - SetupCliffWalls·CreateCliffWall·HasTileInAny 영역 폐기 (BT99/BT100/BT101 영역 제거) - SetupJumpThroughPlatforms 끝에 기존 CliffWalls GameObject Object.Destroy (정리) 2. EnemyController.cs: - _startY 영역 신규 (Awake 시점 transform.position.y) - fallThreshold Inspector 영역 신규 (기본 1.0m) - BT98 R1 영역 (발 자체 Raycast) 폐기 → BT102 y 검출 영역으로 대체 - 매 frame Update: transform.position.y < _startY - fallThreshold 시: - 시작 위치 (startX, startY) 텔레포트 (transform + body 동시) - velocity = Vector2.zero - patrolPhase 0·SetNextPatrolTarget·cooldown·waitTimer·stuckTimer 영역 초기화 효과: - 투명벽 영역 (Layer 18·CliffWalls GameObject) 완전 폐기 - Enemy 영역 떨어진 후 = 즉시 시작 위치 복귀 (영구 떨어짐 X) - 단순·근본 방법 (algorithm 영역 부정합 잔존 시도 안전 보장) - 시작 위치 = 안전 영역 가설 (PD가 Enemy 영역 발판 위 배치) --- Assets/Scripts/Mechanics/EnemyController.cs | 37 +++++----- Assets/Scripts/Mechanics/GameOptimizer.cs | 76 +-------------------- 2 files changed, 21 insertions(+), 92 deletions(-) diff --git a/Assets/Scripts/Mechanics/EnemyController.cs b/Assets/Scripts/Mechanics/EnemyController.cs index fe273af..bb6d6a0 100644 --- a/Assets/Scripts/Mechanics/EnemyController.cs +++ b/Assets/Scripts/Mechanics/EnemyController.cs @@ -35,6 +35,8 @@ namespace Platformer.Mechanics public float waitMaxTime = 3f; private float _startX; + private float _startY; // BT102: 시작 시 y 위치 — 떨어짐 검출 기준 + public float fallThreshold = 1.0f; // BT102: _startY - fallThreshold 영역 미만 시 시작 위치 텔레포트 private float _targetX; private int _patrolPhase; // 0: right out / 1: right back / 2: left out / 3: left back private float _lastX; // 벽 정지 검출용 @@ -91,6 +93,7 @@ namespace Platformer.Mechanics // PD 명시 2026-05-08 — 자동 patrol 시작 위치 저장 (측정·target은 Start 시점) _startX = transform.position.x; + _startY = transform.position.y; // BT102: 떨어짐 검출 기준 _lastX = _startX; _stuckTimer = 0f; _phaseCooldown = 0f; @@ -250,26 +253,22 @@ namespace Platformer.Mechanics // BT89 — 자동 patrol + 즉시 벽 검출 + 1~3초 대기 영역 UpdatePatrol(); - // BT98 — 방어 영역 (R1·PD 강한 어조 정합): 발 영역 자체 절벽 검사 → 시작 위치 즉시 텔레포트 복귀 - // 본 PM 17회 가설 누적 부정확. 알고리즘 영역 부정합 잔존 시도 안전 보장. - if (_isInitialized && _collider != null) + // BT102 — 떨어짐 검출 영역: y < _startY - fallThreshold 시 = 시작 위치 텔레포트 복귀 + // PD 명시 (2026-05-08): 투명벽 폐기·떨어짐 차단 다른 방법 + // 단순·근본 방법 — 떨어진 후 검출 영역 즉시 복귀 (영구 떨어짐 X) + if (_isInitialized && transform.position.y < _startY - fallThreshold) { - Vector2 footHere = new Vector2(_collider.bounds.center.x, _collider.bounds.min.y + 0.05f); - RaycastHit2D groundUnder = Physics2D.Raycast(footHere, Vector2.down, cliffCheckDepth, groundLayerMask); - if (groundUnder.collider == null) - { - Vector3 safe = new Vector3(_startX, transform.position.y, transform.position.z); - transform.position = safe; - if (_body != null) _body.position = safe; - if (control != null) control.velocity = Vector2.zero; - _patrolPhase = 0; - SetNextPatrolTarget(); - _phaseCooldown = PHASE_COOLDOWN; - _stuckTimer = 0f; - _lastX = _startX; - _waitTimer = Random.Range(waitMinTime, waitMaxTime); - if (control != null) control.move.x = 0f; - } + Vector3 safe = new Vector3(_startX, _startY, transform.position.z); + transform.position = safe; + if (_body != null) _body.position = safe; + if (control != null) control.velocity = Vector2.zero; + _patrolPhase = 0; + SetNextPatrolTarget(); + _phaseCooldown = PHASE_COOLDOWN; + _stuckTimer = 0f; + _lastX = _startX; + _waitTimer = Random.Range(waitMinTime, waitMaxTime); + if (control != null) control.move.x = 0f; } // 이하 — Player 충돌 검출 영역 (patrol 영역과 분리) diff --git a/Assets/Scripts/Mechanics/GameOptimizer.cs b/Assets/Scripts/Mechanics/GameOptimizer.cs index 6c7a57e..a660b48 100644 --- a/Assets/Scripts/Mechanics/GameOptimizer.cs +++ b/Assets/Scripts/Mechanics/GameOptimizer.cs @@ -29,8 +29,6 @@ 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)] @@ -152,80 +150,12 @@ 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; - - // BT101 — 자체·인접 검사 = Level + AutoForeground 만 (PD Foreground = TilemapCollider X·Enemy 발판 X·검사 영역 X) - var checkTilemaps = new System.Collections.Generic.List(); - if (levelTm != null) checkTilemaps.Add(levelTm); - if (autoFgTm != null) checkTilemaps.Add(autoFgTm); - - var allTilemaps = checkTilemaps; - - foreach (var tm in checkTilemaps) - { - 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(); - // BT100 — size·offset 정정: 매우 좁은 영역(0.02) + Tile 표면 영역(offset.y=0)·절벽 위치 정확 - box.size = new Vector2(0.02f, 3f); - box.offset = new Vector2(0f, 0f); + // BT102 — 기존 CliffWalls GameObject 영역 정리 (PD 명시·투명벽 폐기) + GameObject existingCliffWalls = GameObject.Find("CliffWalls"); + if (existingCliffWalls != null) Object.Destroy(existingCliffWalls); } ///