using UnityEngine; namespace Platformer.Mechanics { /// /// BT5-Dev #27 — PD 제안 Layer + Raycast 동적 충돌. /// Layer 8(JumpThrough) 발판은 기본 통과(IgnoreLayerCollision). Player 하강 + 발 Raycast 시점만 IgnoreCollision(false)로 충돌 활성 → 착지. /// 점프(상승) 시 IgnoreCollision(true) 복구 → 다시 통과. /// PlayerController.Awake에서 자동 부착. /// [RequireComponent(typeof(Collider2D))] public class PlatformDropThrough : MonoBehaviour { const int JUMP_THROUGH_LAYER = 8; [Tooltip("발 raycast 거리. 0.05~0.15 권장.")] public float footRayDistance = 0.1f; Collider2D _self; KinematicObject _ko; Collider2D _activePlatform; int _jumpThroughMask; void Awake() { _self = GetComponent(); _ko = GetComponent(); _jumpThroughMask = 1 << JUMP_THROUGH_LAYER; } void Update() { if (_self == null || _ko == null) return; // Player 발 위치 (collider 하단 중심) Vector2 footPos = new Vector2(_self.bounds.center.x, _self.bounds.min.y + 0.02f); // Layer 8 발판 raycast (footRayDistance 영역만 검사) RaycastHit2D hit = Physics2D.Raycast(footPos, Vector2.down, footRayDistance, _jumpThroughMask); bool falling = _ko.velocity.y <= 0.01f; // 하강 또는 정지 bool rising = _ko.velocity.y > 0.5f; // 점프 상승 if (rising) { // 점프 → 활성 발판 통과 복구 if (_activePlatform != null) { Physics2D.IgnoreCollision(_self, _activePlatform, true); _activePlatform = null; } } else if (falling && hit.collider != null && hit.collider != _activePlatform) { // 하강 + 발판 raycast hit → 충돌 활성 (착지) Physics2D.IgnoreCollision(_self, hit.collider, false); _activePlatform = hit.collider; } else if (falling && hit.collider == null && _activePlatform != null) { // 발판 떠남 (낙하) → 활성 해제 Physics2D.IgnoreCollision(_self, _activePlatform, true); _activePlatform = null; } } void OnDrawGizmosSelected() { if (_self == null) return; Vector2 footPos = new Vector2(_self.bounds.center.x, _self.bounds.min.y + 0.02f); Gizmos.color = Color.cyan; Gizmos.DrawLine(footPos, footPos + Vector2.down * footRayDistance); } } }