Unity - 물리 충돌

땡구의 개발일지·2025년 4월 17일

Unity마스터

목록 보기
8/78
post-thumbnail

가장 기초적인 물체간의 상호작용 중 하나다. 충돌에 필요한 연산량을 어떻게 줄일 수 있나 알아보자

물리 (Rigidbody)

  • 게임 오브젝트물리 엔진을 적용하는 컴포넌트. 질량, 공기저항, 중력과 같은 기본 요소와 함수를 사용해 물리처리. 물리 연산은 많은 연산량을 요구 하므로, 적절히 사용하는 것이 중요함

구성요소

  • Mass : 물리량(Kg)
  • Drag : 공기저항
  • Angular Drag : 회전저항
  • Automatic Center of Mass : 물체의 무게중심을 정중앙에 자동으로 해두기
  • Automatic Tensor : 관성저항 자동세팅
  • Use Gravity : 중력사용 여부
  • Is Kinematic : 외부 충격에 영향을 받는지, 안받는지 설정 가능
  • Interpolate : 보간. CCD와 관련있다. 키면 연산량이 증가한다
  • Collision Detection : 중요한 물체의 충돌검사에 쓴다
  • Constraints : 축에 대한 물리 연산 무시 여부를 체크할 수있다. 예를들어 Freeze Position Y에 체크하면, 낙하하지 않는다

프로젝트 세팅

  • 프로젝트 세팅에서 물리 현상을 세팅할 수 있다. 중력또한 마찬가지. 2D 물리와, 3D 물리를 구분해서 사용한다

스크립팅

  • 이전에는 gameObject, transform 과 같이 기본적으로 있었던 기본 인스턴스였다. 그래서 사진과 같이 그 잔재가 남아있다
  • 새로 만들거면 앞에 new 키워드를 붙여준다

Rigidbody 함수

  • AddForce
    • 힘 가해주기
    • 업데이트 마다 힘을 가함
    • 프레임마다 힘을 가하기 때문에 가속운동이 된다
      void FixedUpdate()
      {
      	rigidbody.AddForce(Vector3.right * x * power,ForceMode.Force);
      }
  • velocity
    • 속도 설정하기
    • 게임 오브젝트에 고정적인 힘이 가해지고 있다고 설정
      rigidbody.velocity = Vector3.right * power * xInput;
  • AddTorque()
    • 회전력 가해주기
    • 업데이트 마다 매개변수 의 물리적인 회전력을 가함
      rigidbody.AddTorque(Vector3.up * xInput * power);
  • angularVelocity
    • 회전 속도 설정하기
    • 게임 오브젝트에 고정적인 회전력이 가해지고 있다고 설정
      rigidbody.angularVelocity = Vector3.up * xInput * power;

게임을 제작하는 데 움직임은 매우 심혈을 기울여 만든다. 예시를 몇 개 조사해본다
버니합 : 버그로 탄생한 이동 기법. 벡터의 내적으로 구현하다보니 생긴 버그다
코요테 타임 : 루니 툰의 전매특허인 허공에서 달리는 모션 후는 떨어지는 연출이 기원이며, 이는 슈퍼 마리오, 셀레스트, 소닉 등 플랫폼 게임에서 땅 끝부분에서 실제로는 떨어져야 하는 거리보다 더 가도 점프를 입력할 유예시간을 지칭한다

예시) 포탄 궤적그리며 날아가기

  • 기존에는 포탄이 날아가는 방법이 이러했다
  • 이렇게 만들어보자
// 필수로 해당 컴포넌트는 가지고 있어야 한다 라는 의미
[RequireComponent(typeof(Rigidbody))]
public class Bullet : MonoBehaviour
{
    [SerializeField] Rigidbody rigid;
    private void Awake()
    {
        // 실수로 Rigidbody를 안 달았다면, 달아준다
        // ?? : null 이면 오른쪽 GetComponent, 아니면 왼쪽 rigid 반환
        rigid ??= GetComponent<Rigidbody>();

    }
    void Update()
    {
        if (rigid.velocity.magnitude > 3)
        {
            //포탄이 곡선을 그리며 날아간다
            transform.forward = rigid.velocity;
            // 오브젝트의 회전 방법 중 하나다
            // transform.forward = 벡터
            // 벡터 방향을 바라보도록(forward 앞이 그쪽을 향하도록) 회전함
        }
    }
}

충돌 (collision)

  • 충돌체 : 게임오브젝트의 물리적 충돌을 목적으로 모양을 정의
  • 게임오브젝트 간의 충돌체로 부딪힘과 반발력을 처리
  • 충돌체는 충돌상황에 있을 경우 유니티 충돌 메시지를 받아 상황을 확인
// 충돌의 메시지(이벤트) 함수. FixedUpdate 이후에 호출된다
// 충돌 시작에 호출
private void OnCollisionEnter(Collision collision)
{
    Debug.Log("Collision Enter");
}
// 충돌 중에 호출
private void OnCollisionStay(Collision collision)
{
    Debug.Log("Collision Stay");

}
// 충돌이 끝나면 호출
private void OnCollisionExit(Collision collision)
{
    Debug.Log("Collision Exit");

}

매개변수

  • 충돌은 두 개 이상의 물체가 만났을 때, 일어난다. 그래서 매개변수가 필요하다

  • private void OnCollisionEnter(Collision collision) 에서 Collision이 매개변수

    private void OnCollisionEnter(Collision collision)
    {
        Debug.Log($"{collision.gameObject.name}과 충돌 시작");
    }
    private void OnCollisionStay(Collision collision)
    {
        Debug.Log($"{collision.gameObject.name}과 충돌 중");
    
    }
    private void OnCollisionExit(Collision collision)
    {
        Debug.Log($"{collision.gameObject.name}과 충돌 끝");
    
    }

예시) 포탄이 충돌 시 폭발

  • OnCollisionEnter가 호출될 때를 이용해 폭발 이펙트를 넣어보자
  • 폭발할 때, 포탄은 삭제된다
public class Bullet : MonoBehaviour
{
    [Header("Components")]
    [SerializeField] Rigidbody rigid;

    [Header("Properties")]
    [SerializeField] GameObject explosionPrefab;

    private void OnCollisionEnter(Collision collision)
    {
        Destroy(gameObject);
        Instantiate(explosionPrefab, transform.position, transform.rotation);
    }
}
  • Destroy 이후에 position과 같은 정보를 사용할 수 있는 이유는, Destroy삭제 예정 함수이기 때문이다. 즉시 삭제는 DestroyImmediate가 있다(쓰는걸 추천하지 않음)
  • Destroy게임 오브젝트가비지 컬렉터가 돌아갈 때 삭제된다

Fake Null 조사

Material 만들기

  • 프로젝트 창에서 위와 같은 방법으로 만들 수 있다
  • Opaque : 불투명도를 설정한다

트리거 (Trigger)

  • 충돌체인데 충돌하지 않는다. 충돌 판정만 이용하는 데 쓰임
  • 충돌과 마찬가지로 3개의 함수가 있다
 private void OnTriggerEnter(Collider other)
 {
     Debug.Log("OnTriggerEnter");
 }

 private void OnTriggerStay(Collider other)
 {
     Debug.Log("OnTriggerStay");
 }

 private void OnTriggerExit(Collider other)
 {
     Debug.Log("OnTriggerExit");
 }

레이어기반 충돌 & 트리거 감지

Layer

  • 많은 오브젝트를 그룹으로 묶어 계층 단위로 관리하기 위한 기능
  • tag와 비슷함. 묶어서 관리 가능하다 보니 충돌/처리에 쓰임
  • 게임오브젝트레이어를 활용하여 충돌체간의 충돌가능 여부를 설정 가능
  • 체크 해제 하면 충돌에서 제외됨
  • edit -> ProjectSettings -> Physics -> Layer Collision Matrix

충돌체 & 트리거 종류

  • 두 게임오브젝트가 충돌하면 리지드바디의 환경설정에 따라 다른 반응을 할 수 있음
  • 일부 조합의 경우 두 게임오브젝트 중에서 하나만 충돌의 영향을 받음
  • 일반적으로 Rigidbody 컴포넌트가 있는 게임오브젝트가 물리가 적용되는 것이 원칙

정적 충돌체 (Static Collider)

  • Rigidbody가 없는 충돌체, 외부에 힘에 움직이지 않음
  • 절대로 움직이지 않는 지형, 구성요소에 주로 사용

리지드바디 충돌체 (Rigidbody Collider)

  • Rigidbody가 있는 충돌체, 외부에 힘을 받아 움직임
  • 충돌하여 힘을 받아 움직이는 물체에 사용

키네마틱 충돌체 (Kinematic Collider)

  • Kinematic Rigidbody가 있는 충돌체, 외부의 힘에 반응하지 않음
  • 움직이지만 외부 충격에는 밀리지 않는 물체에 사용
  • Kinematic 상태를 활성화/비활성화 하여 움직임 여부를 설정하는 경우에도 사용
  • 게임에서 발판 같은거에 쓴다
  • 폴가이즈의 움직이는 장애물 들이 좋은 예시

유니티 충돌체

충돌체 & 트리거 상호작용 매트릭스

  • 충돌체와 트리거의 종류에 따라 메시지가 전송되는 경우가 다름
profile
개발 박살내자

0개의 댓글