[Unity] Collision

Lingtea_luv·2025년 4월 17일
0

Unity

목록 보기
4/30
post-thumbnail

Collision


Rigidbody

Rigidbody 컴포넌트는 게임 오브젝트에 물리엔진을 적용하는 컴포넌트로, 물체의 질량, 공기저항, 중력에 대한 연산과 기본 지원 함수를 사용하여 현실적인 물리처리가 가능하도록 만든다. 참고로 Rigidbody가 없는 물체끼리는 충돌 감지가 되지 않는다.

  1. AddForce(Vector3 force)
    매개 변수로 입력되는 x,y,z축 방향으로 물리적인 힘을 가한다. ForceMode에 따라 가하는 물리량이 다르다.
    ForceMode 설명 특징
    Force 물체의 질량과 시간에 따라 힘을 누적 가속하는 느낌
    Acceleration 질량에 영향을 받지 않고 힘을 가함 질량 무시
    Impulse 질량에 따라 순간적으로 힘을 가함 순간적인 힘, 점프 등
    VelocityChange 질량 무시, 속도만 즉시 변화 텔레포트 느낌, 질량 무시
  2. AddTorque()
    매개변수로 입력되는 축을 기준으로 회전력을 가한다.
  3. velocity
    게임 오브젝트에 가해지고 있는 힘을 의미한다. 직접 값을 설정할 수 있지만, 물리 기반이 아니기에 주의해야할 필요가 있다.
public class RigidbodyTest : MonoBehaviour
{
	// new : 부모의 rigidbody가 아닌, 새롭게 만드는 rigidbody라는 뜻
	[SerializeField] (new) Rigidbody rigid;
    [SerializeField] float power;
    private float h;
    
    // 입력은 Update에서
    private void Update()
    {
    	h = Input.GetAxis("Horizontal");
        
        // 단 Impulse의 경우 Update에서 처리하는 것이 좋다.
        if(Input.GetButtonDown("Jump"))
        {
        	rigid.AddForce(Vector3.up * power, ForceMode.Impulse)
        }
    }
    
    // AddForce와 같은 물리 연산은 FixedUpdate에서
    private void FixedUpdate() 
    {
        // 1. 지속적으로 힘 가하기 - 가속시켜주는 경우 사용
        rigid.AddForce(Vector3.right * h * power);
        // 2. 속도 설정하기 - 게임적 허용(비현실적인 움직임)
        rigid.velocity = Vector3.right * power * h;
        // 3. 회전력 가하기 
        rigid.AddTorque(Vector3.up * h * power);
        // 4. 회전 속도 설정하기
        rigid.angularVelocity = Vector3.up * power * h;
    }

}

실습 : 날아가는 방향을 바라보는 총알

// 이 스크립트는 해당 컴포넌트가 있어야 동작한다는 의미
// 이렇게 하면 Bullet 스크립트를 추가하면 자동으로 Rigidbody가 추가된다.
// 심지어 Rigidbody 삭제도 불가능
[RequireComponent(typeof(Rigidbody)]
public class Bullet : MonoBehaviour
{
	[SerializeField] Rigidbody rigid;
    [SerializeField] 
	
	private void Awake()
    {	
    	// Rigidbody가 Bullet에 있는 것이 확실한 경우
        // null이면 GetComponent를 하고 아니면 그냥 쓰고
    	rigid ??= GetComponent<Rigidbody>();
    }
    
    private void Update()
    {
    	// 속도가 일정크기 이상인 경우만 (magnitude : 벡터의 크기)
        // 이하인 경우 회전x
    	if(rigid.velocity.magnitude > 2)
        {
        	// 날아가는 방향을 바라보도록 설정
        	transform.forward = rigid.velocity;
        }   		
    }
}

Mass

물체의 질량을 의미하며 [kg] 단위를 사용한다. 물리 엔진에 기본적으로 사용되는 물리량이다.

Drag

선형 운동에 대한 저항을 의미하며, 공기저항을 생각하면 된다.

Angular Drag

회전 운동에 대한 저항을 의미하며, 공이 무한대로 굴러가는 것을 방지하기 위한 바닥과의 마찰을 생각하면 된다.

UseGravity

해당 물체의 중력 적용 여부를 결정할 수 있다. Edit - ProjectSettings - Physics 탭에서 씬에 적용될 중력의 크기와 중력의 유무를 결정할 수 있다.

Is Kinematic

물리 엔진에 영향을 주지만, 자신은 영향을 받지 않는 것을 의미한다. 문이 잠겨있을 때 통과할 수는 없지만, 열리지 않게 설정할 때 유용하게 쓰인다.

Interpolate

빠르게 움직이는 물체가 부드럽게 보이도록 보간하는 기능으로, 시각적으로 튀는 현상을 방지하기 위해 사용한다.

Collision Detection

물체의 속도가 연산 속도를 뛰어넘는 경우 물체가 충돌하지 않고 통과하는 현상이 발생한다. Collision Detection를 체크할 경우 이러한 현상을 방지할 수 있어 총알과 같이 빠른 물체에 필수적이다. 연산량이 증가하지만 중요한 오브젝트의 경우 체크하여 조금 더 현실적으로 만들 필요가 있다.

rigid.collisionDetectionMode = CollisionDetectionMode.Continuous;

Constraints

축을 기준으로 하는 제약을 의미한다. 점프가 불가능한 게임에서는 Freeze Position Y를 체크하여 Y축의 값이 변하지 않도록 막는 것이 가능하다.

rigid.constraints = RigidbodyConstraints.FreezePositionY | RigidbodyConstraints.FreezeRotation;

Collider

게임 오브젝트의 물리적 충돌을 목적으로 Collider라는 모양을 정의하여 게임 오브젝트 간의 Collider로 부딪힘과 반발력을 처리한다. Collider는 충돌이 있을 경우 유니티 충돌 메시지를 받아 상황을 확인한다.

public class CollisionTest : MonoBehaviour
{
	// 충돌(접촉)을 한 시점에 1회 호출
	private void OnCollisionEnter(Collision collision)
    {
    	Debug.Log($"{collision.gameObject.name}랑 충돌 시작");
    }
    
    // 충돌 중일 때 지속적으로 호출
    private void OnCollisionStay(Collision collision)
    {
    	Debug.Log($"{collision.gameObject.name}랑 충돌 중");
    }
    
    // 충돌(접촉)에서 벗어나는 순간 1회 호출
    private void OnCollisionExit(Collision collision)
    {
    	Debug.Log($"{collision.gameObject.name}랑 충돌 끝");
    }
}

실습 : 물체와 닿으면 폭발하는 총알

public class Bullet : MonoBehaviour
{	
	[Header("Components")]
	[SerializeField] Rigidbody rigid;
    
    [Header("Properties")]
    [SerializeField] GameObject Effect;
    
    private void OnCollisionEnter(Collision collision)
    {
    	Destroy(this.gameObject)
        // Destroy는 삭제 예정이기 때문에 this를 즉시 없애는 것이 아니다.
        // 해당 프레임의 끝에 오브젝트를 파괴한다.
        // 따라서 프레임이 끝나기 전까지는 transform을 사용하는 것이 가능하다.
        // 즉시 삭제의 경우 DestroyImmediate가 있지만 웬만해서 사용x
        Instantiate(Effect, transform.position, transform.rotation);
    }
}

위 코드의 단점은 총알을 너무 빠르게 발사하면 포신 앞에서 총알끼리 부딪혀 폭발하는 현상이 발생한다는 것이다. 따라서 충돌을 무시할 상황과 해야하는 상황을 구분지어야할 필요가 있으며, 이는 Layer를 활용하여 해결하는 것이 가능하다.

Trigger

Trigger는 하나의 Collider가 충돌을 일으키지 않고, 다른 Collider 공간에 들어가는 것을 감지하는 것을 의미한다. Trigger는 겹침 상황에 있을 경우 유니티 트리거 메시지를 받아 상황을 확인한다.

Trigger로 사용하기 위해서는 오브젝트의 인스펙터 상에 있는 RenderingMode를 TransParent로 설정하여 투명하게 만들고 Is Trigger를 체크한다.

public class TriggerTest : MonoBehaviour
{
	private void OnTriggerEnter(Collider other)
    {
    	Debug.Log("Trigger Enter!");
    }

	private void OnTriggerStay(Collider other)
    {
    	Debug.Log("Trigger Stay!");
    }
    
    private void OnTriggerExit(Collider other)
    {
    	Debug.Log("Trigger Exit!");
    }
}

Collider & Trigger 종류

static Collider

항상 같은 자리에 위치하며 절대로 움직이지 않는 물체에 사용된다. 정적 collider는 rigidbody를 가지지 않기에 정적 collider끼리는 충돌하지 않으며, 다른 rigidbody와 충돌하더라도 정적 collider는 움직이지 않는다.

rigidbody collider

움직이는 물체에 사용되는 collider로 rigidbody를 가지고 있어 모든 종류의 collider와 충돌한다. 물리엔진에 의해 완전히 시뮬레이션 되며 스크립트로부터 적용되는 충돌과 힘에 반응하여 가장 흔하게 사용되는 collider 설정이다.

kinematic rigidbody collider

rigidbody 속성에 Is Kinematic을 활성화한 경우로 상황에 따라 움직이거나 활성화/비활성화되지만 그 외의 상황에서는 정적 collider처럼 동작한다. 장애물이나 이동하는 벽 등과 같은 곳에서 활용이 되며, 이동을 하며 다른 rigidbody collider에 작용할 수 있도록 만든다.

static Trigger

트리거 또한 collider와 같은 종류가 존재하지만, static Triger은 작동 방식에 유의할 필요가 있는데, static Trigger와 static collider는 서로 상호작용하지 않기 때문이다. 따라서 움직이는 물체의 충돌이 제대로 이루어지지 않는 경우 rigidbody와 collider 설정 여부를 확인해야한다.

profile
뚠뚠뚠뚠

0개의 댓글