오늘은 Unity 2D에서 플레이어가 벽에 붙어서 움직이다가 갑자기 멈추는 현상을 겪었다.
키 입력도 잘 들어가고, 로그를 찍어보면 속도도 잘 나오는데, 어느 순간 갑자기 바뀌며 캐릭터가 멈췄다.
처음에는 단순히 버그인가? 싶었고, 그러면 그냥 직접 2차원 배열 만들듯이 벽을 직접 확인하는 코드를 짜야 하나? 하는 생각을 했고...
튜터님께 질문드렸더니, 이렇게 문제를 찾거나 원인 해결을 위해선 여러 방향에서 로그를 직접 찍어보며 추적해봐야 한다는 말씀을 하셨다.
그 말을 듣고 로그 찍기를 시작했다.

계속해서 움직이다가 벽에 비비다 보면, 키 입력도 잘 들어가는데 갑자기 움직이지 않게 된다.
위 GIF를 보면 알 수 있듯이, 입력 자체는 정상적으로 들어온다.
물리적인 오류는 없지만, 멈춤 상태가 되면 속도(velocity)가 0으로 떨어진 상태에서 정지한다.
충돌체와 맞닿을 경우, 충돌 지점을 출력하는 로그를 찍었다.
[로그 본문]
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를 담은 리스트Rigidbody와 Collider는 한 번 부딪힐 때 한 지점만 닿는 게 아니라 여러 점이 동시에 닿을 수 있음contact.normal : 충돌한 표면의 방향| Normal | 의미 (플레이어 기준 충돌체 위치) |
|---|---|
| (0, 1) | 아래쪽 벽 |
| (0, -1) | 위쪽 벽 |
| (1, 0) | 오른쪽 벽 |
| (-1, 0) | 왼쪽 벽 |
collision.relativeVelocity : 속도 차이
로그를 보면, 플레이어는 아래쪽 바닥과 계속 부딪히다가(0.000, 1.000) 갑자기 왼쪽 벽과 충돌(-1.000, 0.000)한 것으로 인식된다.
하지만 실제로는 캐릭터가 계속 바닥 위에 있었기 때문에,
아무것도 없는 공간에서 ‘벽과 부딪혔다’고 판정되는 이상한 상황이었다.
처음에는 단순히 왼쪽 벽에 부딪힌 줄 알았다.
하지만 실제로는 벽이 아니라 타일 간의 미세한 틈(gap) 때문에 캐릭터가 그 사이에 끼인 상태였다.
Unity의 TilemapCollider2D는 기본적으로 각 타일마다 Collider를 개별 생성한다.
그래서 타일들이 서로 맞닿아 있어도, 물리 계산상으로는 아래처럼 “경계가 두 개” 생긴다.
[Tile1][Tile2]
↑↑
|└ 두 번째 Collider의 경계선
└ 첫 번째 Collider의 경계선

즉, 타일과 타일 사이에는 눈에 보이지 않는 “이중 경계선”이 존재한다.
게다가 Floating Point(부동소수점) 오차로 인해 타일의 좌표가 100% 딱 맞지 않고 0.0001 단위로 어긋나면서 Unity는 그걸 “틈”으로 인식한다.
결과적으로
캐릭터는 바닥 위에 있는데, 물리 엔진은 캐릭터가 ‘왼쪽 벽과도 닿아 있다’고 잘못 판단.
→Normal값이 (0,1) ↔ (-1,0) 사이에서 계속 바뀌며
→velocity가 순간적으로 0으로 떨어지고, 캐릭터가 멈춘다.
즉, 진짜 벽에 부딪힌 게 아니라, 타일 간 Collider의 경계선에 캐릭터가 걸린 것이었다.
이 문제는 타일맵을 하나의 Collider로 병합하면 깔끔하게 해결된다.
CompositeCollider2D를 활용하는 방식이다.
Rigidbody2D 추가 ⚠️
Used by Composite만 체크해선 작동하지 않는다.
반드시 타일맵의 Rigidbody2D가 Static이어야 Unity가 병합된 Collider로 인식한다.
Dynamic으로 해줘야한다.TilemapCollider2D 유지한 상태로 CompositeCollider2D 추가TilemapCollider2D의 Used by Composite ✅ CompositeCollider2D 설정:이제 Scene 뷰에서 보면, 타일 간 경계선이 전부 사라지고 하나로 연결된 주황색 Collider가 생긴다.
더 이상 “틈”이 존재하지 않는다.

| 구분 | TilemapCollider2D 단독 | CompositeCollider2D 적용 |
|---|---|---|
| Collider 개수 | 타일마다 생성 | 하나로 병합 |
| 경계선 | 이중 경계 발생 | 하나의 외곽선 |
| 틈(gap) | 존재함 | 없음 |
| 충돌 Normal | 충돌 가능성 존재 (0,1 ↔ -1,0) | 안정적 (항상 일정) |
| 결과 | 캐릭터 끼임 | 매끄러운 이동 |
결국 이 문제는 “플레이어가 벽에 부딪힌 게 아니라, 타일 간의 미세한 Collider 틈에 끼인 것”이었다.
그리고 그 틈을 없애주는 CompositeCollider2D로 해결했다.
이번 문제는 단순히 “벽에 끼이는 버그”가 아니라,
TilemapCollider2D가 타일 단위로 Collider를 생성한다는 구조적인 문제였다.
이 과정을 통해 배운 점이라고 한다면, 가장 빠르게 해결하는 방법은 역시 일단 로그를 찍어라..