98 lines
4.4 KiB
C#
98 lines
4.4 KiB
C#
using UnityEngine;
|
|
|
|
namespace Platformer.Mechanics
|
|
{
|
|
/// <summary>
|
|
/// BT5-Dev #27 — PD 제안 Layer + Raycast 동적 충돌.
|
|
/// Layer 8(JumpThrough) 발판은 기본 통과(IgnoreLayerCollision). Player 하강 + 발 Raycast 시점만 IgnoreCollision(false)로 충돌 활성 → 착지.
|
|
/// 점프(상승) 시 IgnoreCollision(true) 복구 → 다시 통과.
|
|
/// PlayerController.Awake에서 자동 부착.
|
|
/// </summary>
|
|
[RequireComponent(typeof(Collider2D))]
|
|
public class PlatformDropThrough : MonoBehaviour
|
|
{
|
|
const int JUMP_THROUGH_LAYER = 8;
|
|
|
|
[Tooltip("발 raycast 기본 거리. velocity 영역에 따라 동적 확대.")]
|
|
public float footRayDistance = 1.0f;
|
|
|
|
Collider2D _self;
|
|
KinematicObject _ko;
|
|
Collider2D _activePlatform;
|
|
int _jumpThroughMask;
|
|
|
|
void Awake()
|
|
{
|
|
_self = GetComponent<Collider2D>();
|
|
_ko = GetComponent<KinematicObject>();
|
|
_jumpThroughMask = 1 << JUMP_THROUGH_LAYER;
|
|
Debug.Log($"[BT32-DropThrough] Awake — self={(_self != null ? "OK" : "NULL")} ko={(_ko != null ? "OK" : "NULL")} mask={_jumpThroughMask}");
|
|
}
|
|
|
|
void Start()
|
|
{
|
|
Debug.Log($"[BT32-DropThrough] Start called");
|
|
if (_self == null) return;
|
|
Vector2 footPos = new Vector2(_self.bounds.center.x, _self.bounds.min.y + 0.02f);
|
|
// BT32 — 거리 무한대 = Player 시작 위치 영역 발판 영역 영역 식별
|
|
RaycastHit2D startHit = Physics2D.Raycast(footPos, Vector2.down, Mathf.Infinity, _jumpThroughMask);
|
|
if (startHit.collider != null)
|
|
{
|
|
Physics2D.IgnoreCollision(_self, startHit.collider, false);
|
|
_activePlatform = startHit.collider;
|
|
Debug.Log($"[BT32-StartHit] dist={startHit.distance:F2} platform='{startHit.collider.gameObject.name}' layer={startHit.collider.gameObject.layer}");
|
|
}
|
|
else
|
|
{
|
|
Debug.Log($"[BT32-StartHit] no Layer 8 platform below footPos={footPos} (mask={_jumpThroughMask})");
|
|
// 마지막 수단 — 모든 Layer raycast해서 가장 가까운 영역 식별
|
|
RaycastHit2D anyHit = Physics2D.Raycast(footPos, Vector2.down, Mathf.Infinity);
|
|
if (anyHit.collider != null)
|
|
Debug.Log($"[BT32-AnyHit] anyLayer dist={anyHit.distance:F2} platform='{anyHit.collider.gameObject.name}' layer={anyHit.collider.gameObject.layer}");
|
|
else
|
|
Debug.Log($"[BT32-AnyHit] NOTHING below player");
|
|
}
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
if (_self == null || _ko == null) return;
|
|
|
|
// Player 발 위치 (collider 하단 중심)
|
|
Vector2 footPos = new Vector2(_self.bounds.center.x, _self.bounds.min.y + 0.02f);
|
|
|
|
// velocity 기반 동적 거리 (빠른 하강 시 raycast miss 차단)
|
|
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 rising = _ko.velocity.y > 0.5f; // 점프 상승
|
|
|
|
if (rising)
|
|
{
|
|
// BT5-Dev #33 — 활성 해제 = 점프(상승) 시점만. 발판 떠남(낙하)은 활성 유지 (Player 거리 영역 벗어나도 충돌 유지·복구)
|
|
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;
|
|
}
|
|
// BT33 — falling + hit X 영역 활성 해제 영역 폐기 (raycast 거리 일시 벗어남 영역 통과 복구 차단)
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|