본문 바로가기
프로그래밍/C#

[C#]🎮 유니티 게임 개발의 핵심: 충돌(Collision)과 트리거(Trigger) 완벽 정복 가이드 🚀

by 다다면체 2025. 4. 11.
728x90
반응형

안녕하세요! 👋 게임 속 세상이 살아 움직이는 것처럼 느껴지게 만드는 핵심 요소 중 하나는 바로 상호작용입니다. 캐릭터가 벽에 부딪히고, 아이템을 줍고, 특정 영역에 들어갔을 때 이벤트가 발생하는 등, 이러한 모든 상호작용의 기반에는 유니티의 충돌(Collision)트리거(Trigger) 시스템이 있습니다.

이번 시간에는 게임 오브젝트 간의 물리적 부딪힘을 감지하는 '충돌'과, 특정 영역 진입/이탈을 감지하는 '트리거'에 대해 깊이 있게 알아보겠습니다. 단순히 기능을 나열하는 것을 넘어, 실제 게임 개발 현장에서 마주칠 수 있는 문제 상황과 해결 노하우, 그리고 최적화 팁까지! 🧐 여러분의 게임에 생동감을 불어넣을 준비, 되셨나요? 자, 그럼 시작해봅시다! ✨

반응형

1. 모든 상호작용의 시작: 콜라이더 (Collider) 컴포넌트 🧱⚙️

**콜라이더(Collider)**는 유니티 물리 엔진이 오브젝트의 형태와 경계를 인식할 수 있도록 도와주는 눈에 보이지 않는 형태입니다. 게임 오브젝트에 콜라이더 컴포넌트를 추가해야만 다른 오브젝트와의 충돌 또는 트리거 감지가 가능해집니다.

🔹 다양한 콜라이더 종류:

유니티는 다양한 형태의 콜라이더를 제공하여, 오브젝트의 모양과 용도에 맞게 선택할 수 있습니다.

  • Box Collider: 가장 기본적인 사각형 형태. 벽, 바닥, 상자 등 각진 오브젝트에 주로 사용됩니다. 성능 부담이 적습니다.
  • Sphere Collider: 구 형태. 공, 구체 형태의 아이템 등에 적합하며, 회전 시 형태 변화가 없어 계산이 빠릅니다.
  • Capsule Collider: 캡슐 형태. 주로 캐릭터의 콜라이더로 많이 사용됩니다. 키나 반지름 조절이 용이합니다.
  • Mesh Collider: 오브젝트의 실제 3D 모델 메시(Mesh)를 기반으로 복잡한 형태의 콜라이더를 생성합니다. 매우 정밀한 충돌 감지가 가능하지만, 그만큼 성능 부담이 가장 큽니다. 꼭 필요한 경우에만 사용하는 것이 좋습니다. (💡 Tip: 복잡한 지형이나 구조물에 사용하되, 움직이는 오브젝트에는 가급적 사용을 피하고, 사용할 경우 Convex 옵션을 활성화하여 성능을 개선할 수 있습니다.)
  • Wheel Collider, Terrain Collider 등: 자동차 바퀴, 유니티 터레인(지형) 등 특정 목적에 맞게 특화된 콜라이더도 존재합니다.

🔹 Is Trigger 속성: 충돌과 트리거의 갈림길 🤔

모든 콜라이더 컴포넌트에는 Is Trigger라는 중요한 체크박스 속성이 있습니다.

  • Is Trigger 체크 해제 (기본값): 해당 콜라이더는 물리적인 충돌을 감지합니다. 오브젝트끼리 부딪히면 서로 밀어내거나 튕겨 나가는 등의 물리적 상호작용이 발생합니다. (예: 벽에 부딪히는 공)
  • Is Trigger 체크: 해당 콜라이더는 물리적인 충돌을 일으키지 않고, 다른 콜라이더가 자신의 영역에 들어오거나 나가는 것만을 감지하는 트리거 영역으로 작동합니다. 오브젝트는 서로 통과하게 됩니다. (예: 아이템 획득 영역, 특정 구역 진입 감지)

🔹 충돌 감지의 필수 파트너: Rigidbody 컴포넌트 💪

콜라이더만으로는 완벽한 충돌/트리거 감지가 어렵습니다. 특히, 움직이는 오브젝트가 다른 오브젝트와의 충돌 또는 트리거를 능동적으로 감지하고 관련 이벤트를 발생시키려면 Rigidbody 컴포넌트가 필수적입니다.

  • Rigidbody: 오브젝트에 물리 법칙(중력, 힘, 충돌 반응 등)을 적용하고, 물리 엔진의 제어를 받도록 합니다.
  • 충돌 조건: 두 오브젝트가 충돌했을 때 OnCollisionEnter와 같은 충돌 이벤트 함수가 호출되려면, 최소한 충돌하는 두 오브젝트 중 하나에는 Rigidbody 컴포넌트가 있어야 합니다. (단, 두 오브젝트 모두 Kinematic Rigidbody인 경우는 제외될 수 있습니다 - 이 경우엔 주로 트리거를 사용합니다.)
  • 트리거 조건: 트리거 이벤트(OnTriggerEnter 등)가 발생하려면, 최소한 트리거 영역으로 들어오거나 나가는 오브젝트 중 하나에는 Rigidbody 컴포넌트가 있어야 합니다.

[심층 분석] 왜 Rigidbody가 필요할까? 유니티의 물리 엔진은 Rigidbody가 부착된 오브젝트를 중심으로 물리 계산을 수행합니다. 콜라이더는 형태 정보만 제공할 뿐, 스스로 움직이거나 물리적 상호작용을 주도하지 못합니다. Rigidbody가 있어야 물리 엔진이 해당 오브젝트의 이동, 회전, 충돌 감지 및 반응을 적극적으로 처리할 수 있게 되는 것입니다. Rigidbody가 없는 콜라이더는 주로 '정적인' 환경 요소(벽, 바닥 등)로 간주됩니다.


2. 실제 부딪힘을 감지하다: 충돌 이벤트 함수 💥

Is Trigger가 꺼진 콜라이더들이 서로 물리적으로 부딪혔을 때 호출되는 함수들입니다. 이 함수들은 충돌이 발생한 스크립트가 포함된 게임 오브젝트에서 정의되어야 합니다.

  • OnCollisionEnter(Collision collision): 두 콜라이더가 처음 접촉하는 순간 단 한 번 호출됩니다.
  • OnCollisionStay(Collision collision): 두 콜라이더가 접촉하고 있는 동안 매 프레임(또는 물리 업데이트 주기마다) 호출됩니다.
  • OnCollisionExit(Collision collision): 두 콜라이더가 접촉 상태에서 떨어지는 순간 단 한 번 호출됩니다.

🔹 Collision 클래스: 충돌 정보의 보고 🧐

위 함수들은 Collision 타입의 매개변수를 받습니다. 이 collision 객체에는 충돌에 대한 유용한 정보들이 담겨 있습니다.

  • collision.gameObject: 나와 충돌한 상대방 게임 오브젝트.
  • collision.collider: 나와 충돌한 상대방 콜라이더 컴포넌트.
  • collision.transform: 나와 충돌한 상대방의 Transform 컴포넌트.
  • collision.contacts: 충돌 지점(들)에 대한 정보 배열 (ContactPoint 구조체). 각 ContactPoint는 접촉 위치(point), 법선 벡터(normal) 등을 포함합니다. (💡 Tip: 총알이 맞은 정확한 위치에 파티클 효과를 생성하거나, 충돌 각도에 따라 다른 반응을 보이게 할 때 유용합니다.)
  • collision.relativeVelocity: 충돌 시 두 오브젝트 간의 상대 속도.
using UnityEngine;

public class PlayerCollision : MonoBehaviour
{
    void OnCollisionEnter(Collision collision)
    {
        // 충돌한 오브젝트의 태그가 "Enemy"라면
        if (collision.gameObject.CompareTag("Enemy"))
        {
            Debug.Log("적과 충돌했습니다!");
            // 여기에 플레이어 체력 감소 등의 로직 추가
        }

        // 충돌 지점 정보 출력 (첫 번째 접촉 지점)
        if (collision.contacts.Length > 0)
        {
            ContactPoint contact = collision.contacts[0];
            Debug.Log($"충돌 지점: {contact.point}, 법선 벡터: {contact.normal}");
        }
    }

    void OnCollisionStay(Collision collision)
    {
        // 지속적으로 "Wall" 태그를 가진 오브젝트와 접촉 중일 때
        if (collision.gameObject.CompareTag("Wall"))
        {
            Debug.Log("벽에 계속 붙어있습니다...");
        }
    }

    void OnCollisionExit(Collision collision)
    {
        if (collision.gameObject.CompareTag("Enemy"))
        {
            Debug.Log("적과의 충돌 상태에서 벗어났습니다.");
        }
    }
}

3. 영역 침범을 감지하다: 트리거 이벤트 함수 ✨

콜라이더의 Is Trigger 속성이 켜져 있을 때, 다른 콜라이더(Rigidbody가 있거나, 들어오는 대상에 Rigidbody가 있어야 함)가 해당 영역에 들어오거나, 머물거나, 나갈 때 호출되는 함수들입니다. 물리적인 반발력 없이 감지만 수행합니다.

  • OnTriggerEnter(Collider other): 다른 콜라이더가 트리거 영역 안으로 처음 들어오는 순간 단 한 번 호출됩니다.
  • OnTriggerStay(Collider other): 다른 콜라이더가 트리거 영역 안에 머무는 동안 매 프레임(또는 물리 업데이트 주기마다) 호출됩니다.
  • OnTriggerExit(Collider other): 다른 콜라이더가 트리거 영역 밖으로 나가는 순간 단 한 번 호출됩니다.

🔹 Collider other 매개변수:

트리거 함수들은 Collider 타입의 매개변수 other를 받습니다. 이는 트리거 영역 안으로 들어오거나 나간 상대방 오브젝트의 콜라이더를 의미합니다. Collision 객체와 달리 물리적 충돌 정보(접촉점 등)는 포함하지 않습니다.

  • other.gameObject: 트리거 영역과 상호작용한 상대방 게임 오브젝트.
  • other.tag: 상대방 게임 오브젝트의 태그.
  • other.GetComponent<T>(): 상대방 게임 오브젝트에서 특정 컴포넌트를 가져올 수 있습니다.
using UnityEngine;

public class ItemPickupZone : MonoBehaviour
{
    // 이 스크립트가 있는 게임 오브젝트의 콜라이더는 Is Trigger가 체크되어 있어야 합니다.
    void OnTriggerEnter(Collider other)
    {
        // 트리거 영역에 들어온 오브젝트의 태그가 "Player"라면
        if (other.CompareTag("Player"))
        {
            Debug.Log("플레이어가 아이템 획득 영역에 들어왔습니다!");
            // 여기에 아이템 획득 처리 로직 추가
            // 예: other.GetComponent<PlayerInventory>().AddItem(this.itemData);

            // 아이템 획득 후 아이템 오브젝트 비활성화 또는 파괴
            gameObject.SetActive(false); // or Destroy(gameObject);
        }
    }

    // OnTriggerStay는 예를 들어, 지속적인 데미지를 주는 용암 지역 등에 활용 가능
    void OnTriggerStay(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            // 초당 데미지 계산 등
            // Debug.Log("플레이어가 용암 지역에 머무는 중...");
            // other.GetComponent<PlayerHealth>().TakeDamage(damagePerSecond * Time.deltaTime);
        }
    }

    void OnTriggerExit(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            Debug.Log("플레이어가 아이템 획득 영역에서 나갔습니다.");
            // 특정 영역을 벗어났을 때의 로직 (예: 버프 효과 제거)
        }
    }
}

[문제 해결 과정 상세 기록] 충돌/트리거가 작동하지 않을 때 체크리스트:

  1. 콜라이더 확인: 상호작용하려는 두 오브젝트 모두에 콜라이더 컴포넌트가 부착되어 있는지 확인합니다. 크기와 위치가 올바른지도 확인하세요. (Scene 뷰에서 초록색 외곽선으로 확인)
  2. Rigidbody 확인:
    • 충돌(Collision): 최소 한쪽 오브젝트에 Rigidbody가 있는지 확인합니다. (보통 움직이는 쪽에 추가)
    • 트리거(Trigger): 최소 한쪽 오브젝트(보통 움직이는 쪽)에 Rigidbody가 있는지, 그리고 트리거 역할을 하는 콜라이더의 Is Trigger가 체크되어 있는지 확인합니다.
  3. 스크립트 위치 확인: OnCollision... 또는 OnTrigger... 함수를 포함한 스크립트가 Rigidbody 또는 Collider가 부착된 바로 그 게임 오브젝트에 추가되어 있는지 확인합니다. (자식 오브젝트에 있으면 안 됩니다!)
  4. 함수 이름/매개변수 확인: 함수 이름의 대소문자(OnCollisionEnter 등)와 매개변수 타입(Collision, Collider)이 정확한지 확인합니다.
  5. Is Trigger 설정 확인: 의도한 대로 설정되었는지 다시 확인합니다. 충돌을 원하는데 Is Trigger가 켜져 있거나, 트리거를 원하는데 꺼져 있으면 안 됩니다.
  6. 레이어 충돌 매트릭스 확인 (다음 섹션): 특정 레이어 간의 충돌이 꺼져 있지 않은지 확인합니다.
  7. 오브젝트 활성화 상태: 상호작용하려는 오브젝트나 관련 스크립트가 비활성화(SetActive(false))되어 있지 않은지 확인합니다.
  8. Kinematic Rigidbody: Rigidbody가 Kinematic으로 설정된 경우, 물리적인 힘에 반응하지 않습니다. OnCollisionEnter 등은 Kinematic이 아닌 Rigidbody와 충돌할 때 호출될 수 있지만, Kinematic끼리의 충돌은 감지 방식이 다를 수 있습니다. 트리거는 일반적으로 Kinematic Rigidbody와 잘 작동합니다.

4. 선택적 상호작용: 충돌 레이어 및 매트릭스 🎯📊

게임이 복잡해지면 모든 오브젝트가 서로 충돌할 필요는 없습니다. 예를 들어, 플레이어의 총알은 적에게만 맞고 다른 플레이어 총알이나 아이템과는 충돌하지 않아야 할 수 있습니다. 이럴 때 **충돌 레이어(Layer)**와 **충돌 매트릭스(Physics Collision Matrix)**를 사용합니다.

🔹 충돌 레이어 설정 및 관리:

  1. 유니티 에디터 상단의 Edit > Project Settings > Tags and Layers 로 이동합니다.
  2. Layers 섹션에서 비어있는 사용자 레이어(User Layer 8부터)에 원하는 이름을 지정합니다. (예: "Player", "Enemy", "PlayerBullet", "Environment")
  3. 씬(Scene) 또는 프리팹(Prefab)에서 게임 오브젝트를 선택하고, 인스펙터(Inspector) 창 상단의 Layer 드롭다운 메뉴에서 해당 오브젝트에 적절한 레이어를 할당합니다.

🔹 충돌 매트릭스 설정:

  1. Edit > Project Settings > Physics (3D) 또는 Physics 2D (2D) 로 이동합니다.
  2. 하단에 Collision Matrix가 표시됩니다. 이 행렬은 각 레이어 쌍 간의 충돌 허용 여부를 나타냅니다.
  3. 체크박스를 선택하면 해당 레이어 쌍 간의 충돌/트리거 상호작용이 허용되고, 체크를 해제하면 무시됩니다.

[실무 경험 기반 팁] 레이어 활용의 중요성:

  • 성능 최적화: 불필요한 충돌 계산을 건너뛰므로 게임 성능 향상에 매우 중요합니다. 특히 오브젝트 수가 많거나 복잡한 물리 연산이 필요할 때 효과적입니다.
  • 게임 디자인 유연성: 특정 오브젝트 그룹 간의 상호작용을 세밀하게 제어하여 다양한 게임 메커니즘을 구현할 수 있습니다. (예: 아군끼리는 통과, 적과 플레이어만 충돌)
  • Raycast 필터링: 물리 기반의 레이캐스트(Raycast)를 사용할 때, 특정 레이어만 감지하도록 필터링하는 데에도 레이어가 활용됩니다. (예: 바닥 감지 레이캐스트는 "Ground" 레이어만 확인)

레이어 설정은 프로젝트 초기에 계획하고 꾸준히 관리하는 것이 좋습니다. 나중에 복잡하게 얽힌 상호작용을 정리하는 것보다 훨씬 효율적입니다!


🌟 결론:

지금까지 유니티의 충돌 및 트리거 시스템의 핵심 요소들을 깊이 있게 살펴보았습니다. 콜라이더의 종류와 Is Trigger 설정, Rigidbody의 역할, 충돌 및 트리거 이벤트 함수의 활용법, 그리고 레이어와 매트릭스를 이용한 상호작용 제어까지! 💪

 

이 개념들은 단순히 오브젝트가 부딪히는 것을 넘어, 게임 내 거의 모든 상호작용의 기초가 됩니다. 아이템 획득, 문 열기, 함정 발동, 적 감지, 스킬 발동 영역 등 무궁무진한 게임 메커니즘을 구현할 수 있는 강력한 도구들이죠. ✨

 

처음에는 다소 복잡하게 느껴질 수 있지만, 직접 다양한 콜라이더와 설정을 적용해보고, 이벤트 함수 안에 Debug.Log를 찍어가며 작동 방식을 눈으로 확인하는 것이 가장 좋은 학습 방법입니다. 오늘 배운 내용을 바탕으로 여러분의 게임 월드에 풍부한 상호작용을 구현해보세요! 궁금한 점이 있다면 언제든지 댓글로 남겨주세요. 😉

728x90
반응형