유니티에서 충돌을 표현하는 방법은 주로 2가지이다.
1. Rigidbody Component와 Collider Component의 조합을 이용한 충돌
2. RayCast를 이용한 충돌
먼저 1번부터 확인하겠다.
Rigidbody Component는 물리 시뮬레이션을 통한 GameObject의 위치 조절이다.
Rigidbody Component를 부착할 시에 Unity의 물리 엔진에 의해서 작동하며 코드의 추가없이 중력에 영향을 받던가 Collider Component와 함께 작용을 구현할 수 있다.
Script를 통해서 Rigidbody Component에 영향을 줄 수 있는데 힘을 적용한다던가 할 수 있다. 이때 Rigidbody에 대한 것은 FixedUpdate 함수에서 진행하는 것을 추천한다. 그 이유는 FixedUpdate는 유동적인 Update 함수와 반대로 고정적인 시간으로 작동하기 때문에 더 확실해진다.
https://docs.unity3d.com/kr/530/ScriptReference/Rigidbody.html
Rigidbody에 대한 Unity docs
실제로 고정적이게 딱딱 맞춰지는 것은 아니다.
https://docs.unity3d.com/kr/2021.3/Manual/ExecutionOrder.html
이벤트 함수의 실행순서에 대한 Unity Docs
위의 유니티 Docs에서 갖고온 사진이다. Physics쪽이 FixedUpdate, GameLogic 부분이 Update 함수이다. 보면 FixedUpdate는 다시 돌아가서 시작하는 부분을 볼 수 있다. 그 이유는 만약 Physics가 60fps라고 고정했다고하면 Update부분에서 갑자기 3fps를 먹을 경우 매 fps마다 FixedUpdate를 해야되는 Physics는 2fps를 잃은 것이다. 이를 방지하기 위해서 3fps만큼 반복하는 것이다. 이에반해 Update는 1번만 실행되고 다음으로 넘어간다.
다시 본론으로 돌아가서 Collider Component의 경우 Rigidbody component로 충돌을 하기 위해서는 필요하다. Collider Component는 Rigidbody Component에서 충돌을 파악하기 위해서 사용되는(Physics Engine에서 사용되는) GameObject의 범위라고 할 수 있다.
즉, Rigidbody와 Collider Component는 서로 상호보완적인 관계이다.
정리하면 콜라이더는 충돌이 일어나게 만들기 위해 리지드 바디에 함께 추가해야 하는 또 다른 유형의 컴포넌트로 두 개의 리지드 바디가 서로 충돌하더라도 두 오브젝트 모두 콜라이더가 추가되어 있지 않으면 물리 엔진은 충돌 연산을 하지 않는다. 콜라이더가 없는 리지드바디는 물리 시뮬레이션 동안 서로를 지나쳐가기만 한다.
경우에 따라서 게임 오브젝트에 리지드바디를 연결하여 충돌에 감지를 하고 싶지만, 물리 언젠으로 모션이 제어되는 것을 원하지 않을 수 있다.
이때 사용하는 옵션이 IsKinematic이다.
체크박스를 선택할 경우 IsKinematic을 사용할 수 있다.
유니티 물리엔진에서는 최적화를 위해서 리지드바디가 정의된 최소 선형 또는 속도보다 느리게 이동하면 물리엔진이 정지했다고 간주한다. 이 상태를 '휴면' 상태라고 하며, 이 최적화는 가끔 오류를 발생시킬 수 있다.
리지드바디가 없는 정적 콜라이더를 Transform을 수정하여 휴면 상태의 리지드바디와 겹치면 충돌 처리를 못한다. 이러한 경우에는 WakeUp 함수를 사용하여 게임 오브젝트를 명시적으로 깨울 수 있다.
Rigidbody의 Mass는 물리엔진에서 사용하는 단위로, kg이란 단위로 설정하는 것이 일반적이다. 그리고 이에 맞춰서 scale 같은 경우에 m단위로 사용한다.
충돌이 일어나면 물리 엔진은 충돌과 관련된 오브젝트에 있는 모든 스크립트에서 특정 이름을 가진 함수를 호출한다. 충돌이 가장 먼저 일어나는 물리 업데이트는 OnCollisionEnter 함수 호출이다. 접촉이 지속되는 상황에서는 OnCollisionStay 함수가 호출되며, 마지막으로 이 접촉 상태가 종료되었음을 나타내는 OnCollisionExit 함수가 호출된다.
트리거에 대한 것은 바로 다음으로 설명하겠지만 이와 유사하게 OnTriggerEnter, OnTriggerStay, OnTriggerExit 함수가 호출된다.
각 오브젝트의 상태에 따라서 트리거 메시지가 발생할지 충돌 메시지가 발생할지가 다르다.
Trigger 콜라이더는 Collider에서 Is Trigger로 체크박스 선택 시 선택할 수 있다.
다음과 같이 세팅을 한 후 Player.cs에 OnCollision 메서드를 추가하자.
유니티의 물리엔진이 모든 Script에 충돌 메시지를 뿌리기 때문에 어느 곳에 선언해도 문제없다.
private void OnCollisionEnter(Collision collision)
{
Debug.Log("Enter : " + collision.gameObject.name); // 부딛친 상태 이름 리턴
}
private void OnCollisionStay(Collision collision)
{
Debug.Log("Stay : " + collision.gameObject.name); // 부딛친 상태 이름 리턴
}
private void OnCollisionExit(Collision collision)
{
Debug.Log("Exit : " + collision.gameObject.name); // 부딛친 상태 이름 리턴
}
제대로 Rigidbody와 Collider을 붙여주고 메서드에 추가 시 다음과 같이 뜰 것이다.