[Unity] 2D 타일맵 충돌 버그 — Collider Gap 문제 해결하기

shin0112·2025년 10월 23일

Unity

목록 보기
3/13

✨ 들어가며

오늘은 Unity 2D에서 플레이어가 벽에 붙어서 움직이다가 갑자기 멈추는 현상을 겪었다.
키 입력도 잘 들어가고, 로그를 찍어보면 속도도 잘 나오는데, 어느 순간 갑자기 바뀌며 캐릭터가 멈췄다.

처음에는 단순히 버그인가? 싶었고, 그러면 그냥 직접 2차원 배열 만들듯이 벽을 직접 확인하는 코드를 짜야 하나? 하는 생각을 했고...

튜터님께 질문드렸더니, 이렇게 문제를 찾거나 원인 해결을 위해선 여러 방향에서 로그를 직접 찍어보며 추적해봐야 한다는 말씀을 하셨다.

그 말을 듣고 로그 찍기를 시작했다.


🧩 문제 상황

계속해서 움직이다가 벽에 비비다 보면, 키 입력도 잘 들어가는데 갑자기 움직이지 않게 된다.

1️⃣ 로그 찍기

1. 방향키 로그

위 GIF를 보면 알 수 있듯이, 입력 자체는 정상적으로 들어온다.

2. 물리 상태 로그

물리적인 오류는 없지만, 멈춤 상태가 되면 속도(velocity)가 0으로 떨어진 상태에서 정지한다.

3. 충돌 로그

충돌체와 맞닿을 경우, 충돌 지점을 출력하는 로그를 찍었다.

[로그 본문]

private bool _wasColliding = false;
private void OnCollisionStay2D(Collision2D collision)
{
    if (!_wasColliding)
    {
        Debug.Log($"[Collision ENTER] {collision.gameObject.name}");
        _wasColliding = true;
    }

    // 충돌 지점 정보
    foreach (ContactPoint2D contact in collision.contacts)
    {
        Debug.Log(
            $"[Collision STAY] with {collision.collider.name} | " +
            $"Normal:{contact.normal:F3} | " +
            $"RelativeVel:{collision.relativeVelocity:F3}"
        );
    }
}

간단한 설명

  • _wasColliding : 충돌 중인지 확인하기 위한 bool 값
  • collision.contacts : 충돌 중인 모든 object를 담은 리스트
    • RigidbodyCollider는 한 번 부딪힐 때 한 지점만 닿는 게 아니라 여러 점이 동시에 닿을 수 있음
    • 그래서 모든 충돌 지점을 확인하려면 모든 object(contacts)를 다 확인해봐야 함.
  • contact.normal : 충돌한 표면의 방향
    • 내가 보는 화면 기준이 아니라 플레이어 기준이다.
Normal의미 (플레이어 기준 충돌체 위치)
(0, 1)아래쪽 벽
(0, -1)위쪽 벽
(1, 0)오른쪽 벽
(-1, 0)왼쪽 벽
  • collision.relativeVelocity : 속도 차이
    • 벽에 얼마나 빠르게 박았는지 or 떨어졌는지 확인

로그를 보면, 플레이어는 아래쪽 바닥과 계속 부딪히다가(0.000, 1.000) 갑자기 왼쪽 벽과 충돌(-1.000, 0.000)한 것으로 인식된다.

하지만 실제로는 캐릭터가 계속 바닥 위에 있었기 때문에,
아무것도 없는 공간에서 ‘벽과 부딪혔다’고 판정되는 이상한 상황이었다.

2️⃣ 원인 분석

처음에는 단순히 왼쪽 벽에 부딪힌 줄 알았다.
하지만 실제로는 벽이 아니라 타일 간의 미세한 틈(gap) 때문에 캐릭터가 그 사이에 끼인 상태였다.

Unity의 TilemapCollider2D는 기본적으로 각 타일마다 Collider를 개별 생성한다.
그래서 타일들이 서로 맞닿아 있어도, 물리 계산상으로는 아래처럼 “경계가 두 개” 생긴다.

[Tile1][Tile2]
	  ↑↑
	  |└ 두 번째 Collider의 경계선
	  └ 첫 번째 Collider의 경계선

즉, 타일과 타일 사이에는 눈에 보이지 않는 “이중 경계선”이 존재한다.
게다가 Floating Point(부동소수점) 오차로 인해 타일의 좌표가 100% 딱 맞지 않고 0.0001 단위로 어긋나면서 Unity는 그걸 “틈”으로 인식한다.

결과적으로

캐릭터는 바닥 위에 있는데, 물리 엔진은 캐릭터가 ‘왼쪽 벽과도 닿아 있다’고 잘못 판단.
Normal 값이 (0,1) ↔ (-1,0) 사이에서 계속 바뀌며
velocity가 순간적으로 0으로 떨어지고, 캐릭터가 멈춘다.

즉, 진짜 벽에 부딪힌 게 아니라, 타일 간 Collider의 경계선에 캐릭터가 걸린 것이었다.


3️⃣ 해결 과정

이 문제는 타일맵을 하나의 Collider로 병합하면 깔끔하게 해결된다.
CompositeCollider2D를 활용하는 방식이다.

✅ 1. Rigidbody2D 추가

  • Tilemap 오브젝트에 Rigidbody2D 추가
  • Body Type → Static

⚠️ Used by Composite만 체크해선 작동하지 않는다.
반드시 타일맵의 Rigidbody2D가 Static이어야 Unity가 병합된 Collider로 인식한다.

  • Player는 다른 물리 엔진이 동작해야하기 때문에 반드시 Dynamic으로 해줘야한다.

✅ 2. CompositeCollider2D 추가

  • TilemapCollider2D 유지한 상태로 CompositeCollider2D 추가
  • TilemapCollider2DUsed by Composite ✅
  • CompositeCollider2D 설정:
    - Geometry Type: Outlines
    - Generation Type: Synchronous

이제 Scene 뷰에서 보면, 타일 간 경계선이 전부 사라지고 하나로 연결된 주황색 Collider가 생긴다.
더 이상 “틈”이 존재하지 않는다.


🧠 정리

구분TilemapCollider2D 단독CompositeCollider2D 적용
Collider 개수타일마다 생성하나로 병합
경계선이중 경계 발생하나의 외곽선
틈(gap)존재함없음
충돌 Normal충돌 가능성 존재 (0,1 ↔ -1,0)안정적 (항상 일정)
결과캐릭터 끼임매끄러운 이동

결국 이 문제는 “플레이어가 벽에 부딪힌 게 아니라, 타일 간의 미세한 Collider 틈에 끼인 것”이었다.
그리고 그 틈을 없애주는 CompositeCollider2D로 해결했다.

✍️ 마치며

이번 문제는 단순히 “벽에 끼이는 버그”가 아니라,
TilemapCollider2D가 타일 단위로 Collider를 생성한다는 구조적인 문제였다.

이 과정을 통해 배운 점이라고 한다면, 가장 빠르게 해결하는 방법은 역시 일단 로그를 찍어라..

0개의 댓글