Unity에서는 충돌 감지 시스템을 제공한다.
단순 감지 뿐 아니라 질량, 중력, 마찰, 탄성 등 물리적 특성까지 구현되어있다.
이러한 충돌 처리는 게임에서 수많은 상호작용에 사용되는 기능이므로 잘 이해하고 숙지해야 한다.
- Rigidbody : 물리 연산의 주체. 질량, 중력, 속도, 회전력 등을 담당.
- Collider : 물리적 충돌 영역을 정의. 모양에 따라 경계가 결정.
이 두 컴포넌트를 조합하여 물리 충돌 처리가 가능하다.
이번 글에서는 이 물리 충돌 처리에 관해 정리해볼 것이다.
Rigidbody
물리 시뮬레이션을 적용하기 위한 핵심 컴포넌트다.
게임 오브젝트가 중력에 영향을 받거나, 힘(충격)을 받아 움직이거나, 회전하는 모든 물리적 현상은 Rigidbody를 통해 계산된다.
주요 속성
| Mass | 질량 (기본 단위: kg). 무거울수록 동일한 힘에 덜 움직임. F=ma 계산에 사용. 기본값 1 |
| Drag | 선형 감속. 공기저항 등 외부 저항의 역할. 0이면 감속 없음. |
| Angular Drag | 회전 감속. 회전 저항을 의미. 0이면 없음. |
| Use Gravity | 체크 시 Unity의 전역 중력(Physics.gravity) 영향을 받음. |
| Is Kinematic | 체크 시 외부 힘의 영향을 받지 않고, 스크립트로만 제어. |
| Interpolate | 프레임 간 보간 처리. 물리 움직임의 부드러움을 결정. - None / Interpolate / Extrapolate |
| Collision Detection | 충돌 검출 방식. (Discrete / Continuous 등 선택 가능) |
| Constraints | 특정 축의 이동·회전 고정 (Freeze 옵션). |
주요 메서드
| AddForce(Vector3 force) | 지정 방향으로 물리적 힘을 가함. |
| AddTorque(Vector3 torque) | 회전력을 가함. |
| velocity | 현재 물체의 선형 속도. |
| angularVelocity | 현재 물체의 회전 속도. |
주의 사항
Rigidbody는 프레임 단위가 아닌 "물리 연산 단위(Fixedupdate)"에서 계산된다.
Update()가 아닌 FixedUpdate() 내부에서 물리 제어 코드를 작성해야 한다.
Collider
오브젝트의 물리적 경계를 통해 충돌 범위를 정의하는 컴포넌트다.
실제 모델의 복잡한 메시에 관계없이, 단순한 형태의 Collider로 충돌 영역을 지정하는 게 일반적이지만
Mesh Collider를 통해 3D 모델의 실제 메시를 충돌체로 정의할 수 있다.
| Box Collider | 직육면체 형태. UI 버튼, 문, 벽 등에 사용. |
| Sphere Collider | 구체 형태. 공, 폭탄, 구체형 오브젝트에 적합. |
| Capsule Collider | 캡슐 형태. 사람형 캐릭터 충돌 범위에 자주 사용. |
| Mesh Collider | 3D 모델의 실제 메시를 충돌체로 사용. (고비용) |
IsTrigger : 체크시 실제 물리 충돌은 발생하지 않고 트리거 아벤트만 감지.
충돌 이벤트 : Collsion & Trigger
Collision (일반 충돌)
Collider + Rigidbody 가 물리적으로 맞닿았을 때 발생한다.
최소 한쪽은 IsKinematic이 비활성화되어 있어야 정상적으로 작동한다.
| OnCollisionEnter(Collision col) | 충돌 시작 시 1회 호출 |
| OnCollisionStay(Collision col) | 충돌 유지 중 매 프레임 호출 |
| OnCollisionExit(Collision col) | 충돌 종료 시 1회 호출 |
Collision 객체를 통해 충돌 지점, 법선, 충돌 대상 등 세부 정보를 얻을 수 있다.
예시 : 탄환과 부딪히면 대미지 입는 메서드 호출
void OnCollisionEnter(Collision collision)
{
if(collision.gameObject.tag == "PlayerBullet")
{
TakeDamage();
}
}
Trigger (감지 전용 충돌)
Collider의 IsTrigger가 활성화된 경우 발생한다.
실제 물리 충돌은 없지만, 오브젝트가 영역을 통과하는 것을 감지한다.
충돌로 인한 물리 이벤트가 포함되지 않는 대부분의 공격, 스킬, 아이템 상호작용 등은 이것을 통해 이루어진다.
| OnTriggerEnter(Collider other) | 트리거 영역 진입 시 1회 호출 |
| OnTriggerStay(Collider other) | 트리거 내부에 있는 동안 지속 호출 |
| OnTriggerExit(Collider other) | 트리거 영역을 벗어날 때 호출 |
예시 : 탄환의 Collider 영역에 Enemy 태그 보유 오브젝트가 들어오면 작동.
void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Enemy"))
{
Enemy enemy = other.GetComponent<Enemy>();
if (enemy != null) enemy.TakeDamage(dmg);
gameObject.SetActive(false);
}
}
2D 물리
Unity는 3D물리와 별도로 완전 독립적인 2D 물리 엔진 (Box2D 기반)을 제공한다.
| Rigidbody → Rigidbody2D | Collider → Collider2D |
| BoxCollider → BoxCollider2D | SphereCollider → CircleCollider2D |
| OnCollisionEnter → OnCollisionEnter2D | OnTriggerEnter → OnTriggerEnter2D |
+ 충돌 그룹을 관리하기 위해 Layer와 Tag를 활용할 수 있다.
문제 상황
오브젝트 풀링을 활용한 탄환 시스템에서, 단순히 전진하는 탄환이 아닌 AddForce 등 물리력을 구현하는 경우
void CountTime()
{
_deactCount -= Time.deltaTime;
if (_deactCount <= 0)
{
gameObject.SetActive(false);
}
}
void ActivateAction()
{
_deactCount = _deactiveTime;
_rb.AddForce(transform.forward * _shotForce, ForceMode.Impulse);
}
이렇게 간단하게 카운트가 다 되면 비활성화 하는 메서드와 활성화 메서드를 정의할 수 있다.
활성화와 동시에 AddForce를 통해 rigidbody에 물리력을 가해서 포물선 운동처럼 발사하는 코드다.
문제는 이렇게 코드를 작성하면 비활성화 된 오브젝트에 여전히 이전 물리력이 남아있게 된다.
그래서 다시 활성화했을 때, 탄환이 Addforce와 이전 물리력을 합산받아 이상한 방향으로 발사되게 된다.
해결
해결법은 간단하다.
_rb.linearVelocity = Vector3.zero;
탄환이 활성화 혹은 비활성화 되는 순간에 rigidbody의 velocity를 초기화 해주면 해결된다.
혹은 탄환이 생성 될 때 Start 등을 통해 초기화 하는 방법도 있을 수 있다.
Tag 비교 팁
other.tag == "TagName"
이 방식은 런 타임 중string을 통해 비교하기 때문에 문자열 상수 검색과 비교가 일어나 약간의 오버헤드가 있고, 오타나 존재하지 않는 태그를 비교해도 에러 없이 통과된다.
other.CompareTag("TagName")
반면 이런식으로 CompareTag를 사용하면 내부적으로 태그 인덱스 기반 비교를 수행해 더 빠르고, 존재하지 않는 태그를 비교하면 에디터 경고를 발생시켜 안정성이 높다.
열거형처럼 존해자는 태그네임을 int값을 통해 탐색한다고 보면 된다.
즉 속도 + 안정성 면에서 후자가 훨씬 효율적이기에 IDE에서도 해당 코드 사용 권장 알림이 뜬다.
'Unity' 카테고리의 다른 글
| Unity - EventSystem (이벤트 시스템) (0) | 2025.10.20 |
|---|---|
| Unity - Coroutine, yield, Invoke, IEnumerator (0) | 2025.10.17 |
| Unity - Transform, 위치 이동 (0) | 2025.10.15 |
| Unity - 오브젝트(Object), 컴포넌트(Component), 오브젝트 풀링(Object Pooling) (0) | 2025.10.14 |
| Unity - 생명주기 (Life Cycle) (1) | 2025.10.13 |