From a6e0c0d56d43868c97203b0b4c5a652037878af4 Mon Sep 17 00:00:00 2001 From: swrring Date: Thu, 7 May 2026 18:16:01 +0900 Subject: [PATCH] =?UTF-8?q?BT5-Dev=20#40:=20ContactFilter2D=20mask=20?= =?UTF-8?q?=EB=8F=99=EC=A0=81=20=EA=B0=B1=EC=8B=A0=20(=EA=B0=9C=EB=B0=9C?= =?UTF-8?q?=ED=8C=80=EC=9E=A5=20=EC=A7=84=EB=8B=A8=C2=B7KinematicObject=20?= =?UTF-8?q?raycast=20=EC=A0=95=ED=95=A9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PD 지시: 개발팀과 논의 후 보고 개발팀장 Opus 직접 진단: 근본 원인: - KinematicObject.Start()에서 contactFilter.SetLayerMask() 한 번 캐싱 - 이후 Physics2D.IgnoreLayerCollision으로 Layer Matrix 토글해도 contactFilter는 갱신 X - body.Cast() raycast 영역 contactFilter 활용 = Layer Matrix 영역 무관 - 본 PM 19회 시도 모두 raycast 영역 미적용 = 발판 충돌 그대로 감지 해결 (Unity Kinematic2D 표준 Drop-Through 패턴): - PlayerController.UpdateContactFilterForDropThrough — velocity.y > 0 (상승) 영역 Layer 16 mask 비활성 - contactFilter.SetLayerMask() 매 프레임 동적 갱신 = raycast가 발판 영역 무시 - GameOptimizer Physics2D.IgnoreLayerCollision(13, 16, false) 라인 폐기 (Layer Matrix 항시 ON 유지) - BT39 Coroutine 영역 폐기 본 PM 자인: - KinematicObject body.Cast() vs Rigidbody2D OnCollisionEnter 별도 경로 미인지 - ContactFilter2D 캐싱 동작 미인지 - 19회 시도 모두 Rigidbody collision callback 영역 (raycast 영역 무관) 동작: - 점프 상승 (velocity.y > 0.01) → contactFilter mask Layer 16 비트 제거 → raycast 발판 영역 무시 → 통과 - 하강·정지 → mask 복원 → raycast 발판 영역 감지 → 착지 --- Assets/Scripts/Mechanics/GameOptimizer.cs | 7 +++---- Assets/Scripts/Mechanics/PlayerController.cs | 21 ++++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Assets/Scripts/Mechanics/GameOptimizer.cs b/Assets/Scripts/Mechanics/GameOptimizer.cs index 965ea9d..1b43337 100644 --- a/Assets/Scripts/Mechanics/GameOptimizer.cs +++ b/Assets/Scripts/Mechanics/GameOptimizer.cs @@ -60,10 +60,9 @@ namespace Platformer.Mechanics applied++; if (appliedNames.Count < 8) appliedNames.Add($"{c.gameObject.name}({c.GetType().Name})"); } - Debug.Log($"[BT38-DropThrough] applied={applied} excluded={excluded} total={allColliders.Length}"); - Debug.Log($"[BT38-DropThrough] appliedSamples=[{string.Join(", ", appliedNames)}]"); - // 기본 = Player(13) ↔ JumpThrough(16) 충돌 ON. PlayerController.Update에서 점프 시 동적 토글 - Physics2D.IgnoreLayerCollision(13, 16, false); + Debug.Log($"[BT40-DropThrough] applied={applied} excluded={excluded} total={allColliders.Length}"); + Debug.Log($"[BT40-DropThrough] appliedSamples=[{string.Join(", ", appliedNames)}]"); + // BT40 — Layer Matrix는 항시 ON. PlayerController.UpdateContactFilterForDropThrough에서 raycast contactFilter mask 동적 갱신 } } } diff --git a/Assets/Scripts/Mechanics/PlayerController.cs b/Assets/Scripts/Mechanics/PlayerController.cs index f513c92..f7485e5 100644 --- a/Assets/Scripts/Mechanics/PlayerController.cs +++ b/Assets/Scripts/Mechanics/PlayerController.cs @@ -157,9 +157,9 @@ namespace Platformer.Mechanics if (IsGrounded) LastGroundedPosition = transform.position; } - // BT5-Dev #39 — 점프 시작 시 Coroutine으로 0.3초 동안 Layer 16 통과 유지 (Physics step 지연 차단) + // BT5-Dev #40 — 개발팀장 진단: KinematicObject.Start() contactFilter 캐싱 우회 + // Physics2D.IgnoreLayerCollision은 raycast contactFilter 영역 무관. SetLayerMask 직접 갱신 의무. const int JUMP_THROUGH_LAYER = 16; - bool _jumpThroughActive; void UpdateJumpState() { @@ -170,8 +170,6 @@ namespace Platformer.Mechanics jumpState = JumpState.Jumping; jump = true; stopJump = false; - // BT39 — 점프 시작 시 즉시 IgnoreLayerCollision 활성 + Coroutine으로 0.3초 유지 - if (!_jumpThroughActive) StartCoroutine(JumpThroughRoutine()); break; case JumpState.Jumping: if (!IsGrounded) @@ -191,15 +189,18 @@ namespace Platformer.Mechanics jumpState = JumpState.Grounded; break; } + + // BT40 — Drop-Through: velocity.y > 0(상승) 영역 Layer 16 mask 비활성, 그 외 활성 + UpdateContactFilterForDropThrough(); } - System.Collections.IEnumerator JumpThroughRoutine() + void UpdateContactFilterForDropThrough() { - _jumpThroughActive = true; - Physics2D.IgnoreLayerCollision(13, JUMP_THROUGH_LAYER, true); - yield return new WaitForSeconds(0.3f); - Physics2D.IgnoreLayerCollision(13, JUMP_THROUGH_LAYER, false); - _jumpThroughActive = false; + int baseMask = Physics2D.GetLayerCollisionMask(gameObject.layer); + bool ascending = velocity.y > 0.01f; + int mask = ascending ? (baseMask & ~(1 << JUMP_THROUGH_LAYER)) : baseMask; + contactFilter.SetLayerMask(mask); + contactFilter.useLayerMask = true; } protected override void ComputeVelocity()