BT5-Dev #31: Level Tilemap Layer 8 변환 + Raycast 동적 거리·Start 즉시 활성 (충돌 진단 결과)

[BT30-Collide] name='Level' layer=0 — Player 충돌 GameObject = Level Tilemap 확정.
PD 의도 = Level Tilemap 영역 전체 Drop-Through (점프 시 통과 + 하강 시 Raycast 착지)

본 PM 자인 (BT28 떨어짐 원인):
- Raycast 거리 0.1m 너무 짧음 → velocity 빠른 하강 시 miss
- 시작 시 즉시 활성 X → Player 시작 위치 발판 영역 통과 = 떨어짐

정정:
- GameOptimizer: TilemapCollider2D 제외 영역 폐기 → Level Tilemap도 Layer 8 변환
- PlatformDropThrough.Start: 시작 시 즉시 1회 raycast → Player 시작 위치 발판 영역 충돌 활성 (떨어짐 차단)
- PlatformDropThrough.Update: footRayDistance 0.1 → 0.5 + velocity 기반 동적 거리 (Mathf.Max + |vy|*deltaTime + 0.1)

동작:
- 시작 시 [BT31-StartHit] 출력 + Player 발판 위 정상 정착
- 점프 시 IgnoreCollision(true) 복구 = 통과
- 하강 시 raycast hit → IgnoreCollision(false) = 착지
This commit is contained in:
깃 관리자 2026-05-07 17:26:45 +09:00
parent 1570aaf657
commit 0eea12d945
2 changed files with 24 additions and 28 deletions

View File

@ -31,8 +31,9 @@ namespace Platformer.Mechanics
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)] [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
static void SetupJumpThroughPlatforms() static void SetupJumpThroughPlatforms()
{ {
// BT5-Dev #29 — 일반 지면 Tilemap 일반 충돌 복원 + Foreground 발판만 Layer 8. // BT5-Dev #31 — [BT30-Collide] 진단 결과: Player 충돌 GameObject = 'Level'(Tilemap, Layer 0).
// 일반 지면(Level TilemapCollider2D) = Layer 0 = 착지 정합 / 발판(Foreground·별개 BoxCollider) = Layer 8 = Drop-Through // PD 의도 = Level Tilemap 영역 전체 Drop-Through (점프 시 통과 + 하강 시 Raycast로 착지).
// 모든 Collider Layer 8 변환 (Tilemap 포함). PlatformDropThrough Raycast 거리 충분히 크게 + Start 즉시 활성.
int applied = 0, excluded = 0; int applied = 0, excluded = 0;
var allColliders = Object.FindObjectsByType<Collider2D>(FindObjectsSortMode.None); var allColliders = Object.FindObjectsByType<Collider2D>(FindObjectsSortMode.None);
var appliedNames = new System.Collections.Generic.List<string>(); var appliedNames = new System.Collections.Generic.List<string>();
@ -40,8 +41,6 @@ namespace Platformer.Mechanics
{ {
if (c == null) continue; if (c == null) continue;
if (c.isTrigger) { excluded++; continue; } if (c.isTrigger) { excluded++; continue; }
// 일반 지면 Tilemap 제외 (Layer 0 정상 충돌)
if (c.GetComponent<UnityEngine.Tilemaps.TilemapCollider2D>() != null) { excluded++; continue; }
if (c.GetComponent<PlayerController>() != null if (c.GetComponent<PlayerController>() != null
|| c.GetComponent<EnemyController>() != null || c.GetComponent<EnemyController>() != null
|| c.GetComponent<DeathZone>() != null || c.GetComponent<DeathZone>() != null
@ -60,26 +59,8 @@ namespace Platformer.Mechanics
applied++; applied++;
if (appliedNames.Count < 8) appliedNames.Add($"{c.gameObject.name}({c.GetType().Name})"); if (appliedNames.Count < 8) appliedNames.Add($"{c.gameObject.name}({c.GetType().Name})");
} }
Debug.Log($"[BT31-JumpThrough] applied={applied} excluded={excluded} total={allColliders.Length}");
// BT29 — Foreground GameObject(TilemapRenderer만 부착·Collider 미부착)에 TilemapCollider2D 동적 추가 + Layer 8 Debug.Log($"[BT31-JumpThrough] appliedSamples=[{string.Join(", ", appliedNames)}]");
var foreground = GameObject.Find("Foreground");
if (foreground != null)
{
var fgTc = foreground.GetComponent<UnityEngine.Tilemaps.TilemapCollider2D>();
if (fgTc == null)
{
fgTc = foreground.AddComponent<UnityEngine.Tilemaps.TilemapCollider2D>();
}
foreground.layer = 8;
Debug.Log($"[BT29-Foreground] TilemapCollider2D added·Layer 8 applied to '{foreground.name}'");
}
else
{
Debug.Log($"[BT29-Foreground] 'Foreground' GameObject not found");
}
Debug.Log($"[BT29-JumpThrough] applied={applied} excluded={excluded} total={allColliders.Length}");
Debug.Log($"[BT29-JumpThrough] appliedSamples=[{string.Join(", ", appliedNames)}]");
} }
} }
} }

View File

@ -13,8 +13,8 @@ namespace Platformer.Mechanics
{ {
const int JUMP_THROUGH_LAYER = 8; const int JUMP_THROUGH_LAYER = 8;
[Tooltip("발 raycast 거리. 0.05~0.15 권장.")] [Tooltip("발 raycast 기본 거리. velocity 영역에 따라 동적 확대.")]
public float footRayDistance = 0.1f; public float footRayDistance = 0.5f;
Collider2D _self; Collider2D _self;
KinematicObject _ko; KinematicObject _ko;
@ -28,6 +28,20 @@ namespace Platformer.Mechanics
_jumpThroughMask = 1 << JUMP_THROUGH_LAYER; _jumpThroughMask = 1 << JUMP_THROUGH_LAYER;
} }
void Start()
{
// BT5-Dev #31 — 게임 시작 시 즉시 raycast 1회 → Player 시작 위치가 발판 위면 즉시 충돌 활성 (떨어짐 차단)
if (_self == null) return;
Vector2 footPos = new Vector2(_self.bounds.center.x, _self.bounds.min.y + 0.02f);
RaycastHit2D startHit = Physics2D.Raycast(footPos, Vector2.down, footRayDistance, _jumpThroughMask);
if (startHit.collider != null)
{
Physics2D.IgnoreCollision(_self, startHit.collider, false);
_activePlatform = startHit.collider;
Debug.Log($"[BT31-StartHit] Player 시작 위치 발판 영역 충돌 활성: {startHit.collider.gameObject.name}");
}
}
void Update() void Update()
{ {
if (_self == null || _ko == null) return; if (_self == null || _ko == null) return;
@ -35,8 +49,9 @@ namespace Platformer.Mechanics
// Player 발 위치 (collider 하단 중심) // Player 발 위치 (collider 하단 중심)
Vector2 footPos = new Vector2(_self.bounds.center.x, _self.bounds.min.y + 0.02f); Vector2 footPos = new Vector2(_self.bounds.center.x, _self.bounds.min.y + 0.02f);
// Layer 8 발판 raycast (footRayDistance 영역만 검사) // velocity 기반 동적 거리 (빠른 하강 시 raycast miss 차단)
RaycastHit2D hit = Physics2D.Raycast(footPos, Vector2.down, footRayDistance, _jumpThroughMask); float dist = Mathf.Max(footRayDistance, Mathf.Abs(_ko.velocity.y) * Time.deltaTime + 0.1f);
RaycastHit2D hit = Physics2D.Raycast(footPos, Vector2.down, dist, _jumpThroughMask);
bool falling = _ko.velocity.y <= 0.01f; // 하강 또는 정지 bool falling = _ko.velocity.y <= 0.01f; // 하강 또는 정지
bool rising = _ko.velocity.y > 0.5f; // 점프 상승 bool rising = _ko.velocity.y > 0.5f; // 점프 상승