BT5-Dev #102: 투명벽 폐기·y 검출 텔레포트 (PD 명시 채택)
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 영역 발판 위 배치)
This commit is contained in:
parent
0aead1ea49
commit
725c7105e3
|
|
@ -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 영역과 분리)
|
||||
|
|
|
|||
|
|
@ -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<UnityEngine.Tilemaps.TilemapCollider2D>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <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;
|
||||
|
||||
// BT101 — 자체·인접 검사 = Level + AutoForeground 만 (PD Foreground = TilemapCollider X·Enemy 발판 X·검사 영역 X)
|
||||
var checkTilemaps = new System.Collections.Generic.List<UnityEngine.Tilemaps.Tilemap>();
|
||||
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<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>();
|
||||
// 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
Loading…
Reference in New Issue