본문 바로가기

유니티 ML Agents/유니티 기초

7. 유니티 물리 충돌 처리

물리 충돌 처리 개념



물리 충돌 처리 객체 종류


콜라이더(Collider) 컴포넌트는 오브젝트의 물리 충돌을 처리하는 역할을 한다. 물리 충돌 처리 관점에서 게임 오브젝트는 4가지 종류로 나눌 수 있다.


정적 콜라이더(Static Collider)는 콜라이더가 있지만 리지드바디가 없는 게임 오브젝트이다. 정적 콜라이더는 움직이지 않는 벽, 바닥과 같은 오브젝트에 사용되며 물리 엔진은 정적 콜라이더가 움직이지 않는다고 가정하고 있다. 만일 정적 콜라이더가 이동하게 되면 물리 엔진 내부에서 지속적으로 연산이 이루어져야 하기 때문에 게임 성능 저하를 초래할 수 있다.


리지드바디 콜라이더(Rigidbody Collider)는 콜라이더와 리지드바디 컴포넌트가 함께 있는 게임 오브젝트이다. 물리 엔진에 의해 완전한 물리적 객체로 동작하며 게임에서 가장 많이 사용되는 객체 형태이다. 물리적인 충돌과 힘에 의해 반응을 한다.


키네메틱 리지드바디 콜라이더(Kinematic Rigidbody Collider)는 콜라이더와 리지드바드 컴포넌트가 함께 있으며 특별히 Kinematic 옵션이 활성화되어 있는 오브젝트이다. 키네메틱이 활성화된 오브젝트는 물리적 힘이나 충돌에 반응하지 않고 스크립트를 통해 움직일 수 있다. 평소에는 정적 콜라이더와 같이 동작하지만 상황에 따라 반응하는 방문이나 창문과 같은 객체에 사용할 수 있다.


트리거(Trigger)는 콜라이더에 Trigger 속성이 활성화된 객체이다. 단단한 객체로 동작하지 않고 물체를 단순히 통과 시키는 역할을 한다. Trigger로 설정된 객체에 다른 객체가 들어오면 OnTriggerEnter 함수를 호출한다. 콜라이더 컴포넌트에 트리거가 활성화 된 상태에서 리지드바디 컴포넌트가 추가되면 물리적 충돌 체크를 못하기 때문에 물체는 바닥에 서있지 못하고 바닥으로 가라 앉는다. 따라서 이 때는 일반적으로 리지드바디 컴포넌트의 키네메틱을 활성화시켜(Use Gravity를 비활성화 시킬 수도 있다) 중력이 작용하지 못하도록 한다.


물리 충돌 처리 방식


유니티에서 충돌 처리하는 방식은 크게 두가지가 있다. 하나는 Trigger를 사용하는 것이다. 객체의 콜라이더(Collider) 컴포넌트에 있는 Trigger 속성이 활성화되어 있으면 물체가 충돌할 때 OnTriggerEnter 함수가 호출된다. 충돌이 계속되는 시점에는 OnTriggerStay 함수가 반복적으로 호출되며 충돌이 끝나면 OnTriggerExit 함수가 호출된다.


다른 하나는 Collision을 사용하는 것이다. 객체의 Collision 컴포넌트에 Trigger 속성이 비활성화되어 있을 경우 두 객체가 충돌하면 OnCollisionEnter 함수가 호출된다. 충돌이 계속되는 시점에는 OnCollisionStay 함수가 호출되며 충돌이 끝나면 OnCollisionExit함수가 호출된다.


Trigger Collision을 차이점은 Collision 충돌 처리 할 때는 두 객체 모두 리짓바디(Ridgidbody) 컴포넌트의 Kinematic 속성이 비활성화되어 있어야 한다는 것이다.


Trigger는 단단한 객체로 동작하지 않기 때문에 Kinematic 제약이 적용되지 않는다. 따라서 충돌을 검사해야 하는 객체의 특성에 따라 어떤 방식을 사용할 지 선택하면 된다.


○ 객체 충돌 처리


타겟 객체 설정


Target 객체의 컴포너트 속성을 변경해보자. 먼저 움직이는 정적 콜라이더는 시스템에 부담을 주기 때문에 리지드바드 콜라이더로 만들기 위해 인스펙터 뷰에서 리지드바디 컴포넌트를 추가한다. 


Target이 공중에 떠 있을 수 있도록 키네메틱(Is Kinematic) 속성을 비활성화 시킨다. 충돌 체크를 위해 Trigger를 사용하기 위해 콜라이더 컴포넌트에서 Trigger 옵션을 활성화시킨다.


이제 충돌이 발생했을 때 어떤 게임 오브젝트와 충돌했는지 알 수 있게 타겟 객체에 이름을 달아주자. 주로 태그(Tag)를 사용하는데 인스펙터 뷰 상단에서 Tag 속성을 클릭해서 Add Tag 메뉴를 선택하면 새로운 태그 이름을 입력할 수 있는 창이 나오는데 Target(T)라 입력하자. 다시 인스펙터 뷰로 돌아와서 태그 항목에서 Target(T)를 선택하면 태그가 변경된 것을 확인할 수 있다. 8개의 타겟 객체 중에서 어느 것을 선택해도 상관없다 마지막에 Apply 버튼만 눌러주면 모든 타겟 객체에 동일한 속성이 부여된다. 프리팹이 적용됐기 때문이다.


객체 충돌 처리 스크립트 작성

이제 충돌 처리를 위한 스크립트를 플레이어 게임 오브젝트에 넣어보자. 인스펙터 뷰에서 PlayerController를 더블 클릭해서 에디터 화면을 열어 OnTriggerEnter 함수를 입력한다. OnTriggerEnter 함수는 Collider를 입력으로 받는데 Collider는 충돌한 상대방(Target 객체)의 콜라이더 컴포넌트를 의미한다. 어떤 객체와 충돌했는지 확인하기 위해 CompareTag 함수를 사용해 태그를 비교한다. 만일 “Target(T)” 태그를 가지고 있으면 충돌한 객체를 비활성화 시킨다. 객체를 화면에서 없애는 방법에는 Destory SetActive(false)가 있는데 Destory를 사용하면 객체가 씬에서 완전히 사라지고 SetActive(false)를 사용하면 객체가 동작을 멈추고 사용자의 시야(씬에는 안보이는 상태로 남아있다)에서만 사라지게 된다.

이제 플레이 버튼을 눌러 공을 이리저리 굴리면서 타겟에 부딪혔을 때 공이 정상적으로 없어지는지 확인해 보자.