BT5-Dev #27: Layer 8(JumpThrough) + Raycast 동적 IgnoreCollision (PD 제안)
PD 제안 채택 — PlatformEffector2D 폐기 + 표준 Drop-Through Platform 패턴: - Player(13) ↔ JumpThrough(8) 기본 통과 (Physics2D.IgnoreLayerCollision) - Player 발 Raycast (Layer 8 mask, 0.1m) + 하강 시 → IgnoreCollision(false) 임시 활성 = 착지 - 상승 시 → IgnoreCollision(true) 복구 = 통과 - 발판 떠남 → IgnoreCollision(true) 복구 변경: - GameOptimizer: SetupOneWayPlatforms → SetupJumpThroughPlatforms (Layer 8 변환·PlatformEffector2D 잔존 제거) - PlatformDropThrough.cs (신설): 발 Raycast + 동적 IgnoreCollision - PlayerController.Awake: PlatformDropThrough 자동 부착
This commit is contained in:
parent
ef97fb4291
commit
98bfbd74a2
|
|
@ -16,30 +16,29 @@ namespace Platformer.Mechanics
|
|||
QualitySettings.vSyncCount = 0;
|
||||
Time.fixedDeltaTime = 1f / 60f;
|
||||
|
||||
// BT5-Dev #22 — Layer 영역 분리: Player(13) ↔ Enemy(14) 충돌 영구 OFF.
|
||||
// IgnoreCollision 영역 instance 의존 X = 모든 Player·Enemy 영역 자동 통과 영역.
|
||||
// BT5-Dev #22 — Player(13) ↔ Enemy(14) 충돌 영구 OFF
|
||||
Physics2D.IgnoreLayerCollision(13, 14, true);
|
||||
Debug.Log($"[BT22-LayerSep] Player(13) ↔ Enemy(14) collision OFF");
|
||||
// BT5-Dev #27 — Player(13) ↔ JumpThrough(8) 충돌 기본 OFF (Raycast 시점만 동적 활성)
|
||||
Physics2D.IgnoreLayerCollision(13, 8, true);
|
||||
Debug.Log($"[BT27-LayerSep] Player(13) ↔ Enemy(14)·JumpThrough(8) collision OFF");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PD 지시 2026-05-07 — 모든 지형 Collider2D를 One-Way Platform으로 자동 변환.
|
||||
/// 위에서만 착지·측면·아래 통과. Player·Enemy·DeathZone·VictoryZone·TokenInstance·Trigger Collider 영역 제외.
|
||||
/// BT5-Dev #27 — PD 제안: Layer 8(JumpThrough) + Raycast 동적 충돌.
|
||||
/// PlatformEffector2D 폐기. 모든 일반 BoxCollider2D를 Layer 8로 변환 → 기본 통과 + Player 발 Raycast 시점만 충돌 활성.
|
||||
/// 제외: Tilemap·Player·Enemy·DeathZone·VictoryZone·TokenInstance·AttackHitbox·Trigger Collider.
|
||||
/// </summary>
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
|
||||
static void SetupOneWayPlatforms()
|
||||
static void SetupJumpThroughPlatforms()
|
||||
{
|
||||
// BT5-Dev #25 — Tilemap 영역 OneWay 영역 폐기 (모든 Tile 영역 OneWay = 일반 지면 영역도 영역 = 게임 영역 깨짐)
|
||||
// 별개 BoxCollider2D 영역 영역 영역 영역 영역 영역 발판 영역 영역 OneWay 영역 영역 적용
|
||||
int applied = 0;
|
||||
int excludedTrigger = 0, excludedActor = 0, excludedTilemap = 0;
|
||||
int applied = 0, excluded = 0;
|
||||
var allColliders = Object.FindObjectsByType<Collider2D>(FindObjectsSortMode.None);
|
||||
var appliedNames = new System.Collections.Generic.List<string>();
|
||||
foreach (var c in allColliders)
|
||||
{
|
||||
if (c == null) continue;
|
||||
if (c.isTrigger) { excludedTrigger++; continue; }
|
||||
if (c.GetComponent<UnityEngine.Tilemaps.TilemapCollider2D>() != null) { excludedTilemap++; continue; } // BT25 — Tilemap 영역 영역 영역 일반 충돌 영역
|
||||
if (c.isTrigger) { excluded++; continue; }
|
||||
if (c.GetComponent<UnityEngine.Tilemaps.TilemapCollider2D>() != null) { excluded++; continue; }
|
||||
if (c.GetComponent<PlayerController>() != null
|
||||
|| c.GetComponent<EnemyController>() != null
|
||||
|| c.GetComponent<DeathZone>() != null
|
||||
|
|
@ -47,23 +46,22 @@ namespace Platformer.Mechanics
|
|||
|| c.GetComponent<VictoryZone>() != null
|
||||
|| c.GetComponent<AttackHitbox>() != null)
|
||||
{
|
||||
excludedActor++;
|
||||
excluded++;
|
||||
continue;
|
||||
}
|
||||
|
||||
c.usedByEffector = true;
|
||||
// PlatformEffector2D 잔존 영역 제거 (BT25 누적 영향 차단)
|
||||
var effector = c.GetComponent<PlatformEffector2D>();
|
||||
if (effector == null) effector = c.gameObject.AddComponent<PlatformEffector2D>();
|
||||
effector.useOneWay = true;
|
||||
effector.surfaceArc = 180f;
|
||||
effector.rotationalOffset = 0f;
|
||||
effector.useSideFriction = false;
|
||||
effector.useSideBounce = false;
|
||||
if (effector != null) Object.Destroy(effector);
|
||||
c.usedByEffector = false;
|
||||
|
||||
// Layer 8 변환 → IgnoreLayerCollision로 기본 통과
|
||||
c.gameObject.layer = 8;
|
||||
applied++;
|
||||
if (appliedNames.Count < 8) appliedNames.Add($"{c.gameObject.name}({c.GetType().Name})");
|
||||
}
|
||||
Debug.Log($"[BT25-OneWay] applied={applied} trigger={excludedTrigger} tilemap={excludedTilemap} actor={excludedActor} total={allColliders.Length}");
|
||||
Debug.Log($"[BT25-OneWay] appliedSamples=[{string.Join(", ", appliedNames)}]");
|
||||
Debug.Log($"[BT27-JumpThrough] applied={applied} excluded={excluded} total={allColliders.Length}");
|
||||
Debug.Log($"[BT27-JumpThrough] appliedSamples=[{string.Join(", ", appliedNames)}]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
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 거리. 0.05~0.15 권장.")]
|
||||
public float footRayDistance = 0.1f;
|
||||
|
||||
Collider2D _self;
|
||||
KinematicObject _ko;
|
||||
Collider2D _activePlatform;
|
||||
int _jumpThroughMask;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_self = GetComponent<Collider2D>();
|
||||
_ko = GetComponent<KinematicObject>();
|
||||
_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -82,6 +82,8 @@ namespace Platformer.Mechanics
|
|||
// PD 지시 2026-05-07 — 동반 컴포넌트 자동 부착 (Inspector 부착 불요)
|
||||
if (GetComponent<PlayerInvulnerabilityFlash>() == null) gameObject.AddComponent<PlayerInvulnerabilityFlash>();
|
||||
if (GetComponent<Platformer.UI.ResurrectPromptUI>() == null) gameObject.AddComponent<Platformer.UI.ResurrectPromptUI>();
|
||||
// BT5-Dev #27 — Layer 8 발판 동적 충돌 (PD 제안 Raycast 방식)
|
||||
if (GetComponent<PlatformDropThrough>() == null) gameObject.AddComponent<PlatformDropThrough>();
|
||||
|
||||
// PD 지시 2026-05-07 — 사망 시 입력 차단 / 부활 시 입력 복원
|
||||
if (health != null)
|
||||
|
|
|
|||
Loading…
Reference in New Issue