Physics 

레이어로 Collider의 충돌 범위를 설정해서 특정한 충돌만 받아들이거나 무시하기

 

작성 기준 버전 :: 2019.2

 

[이 포스트의 내용은 유튜브 영상으로도 시청하실 수 있습니다]

 

이번 포스트에서는 유니티의 레이어로 Collider의 충돌 범위를 설정하는 방법을 알아보도록 하자.

 

두 개의 Collider가 충돌하면 OnCollision 혹은 OnTrigger 이벤트가 발생하며 개발자는 이 이벤트를 통해서 충돌을 감지했을 때 처리되어야 할 기능을 구현한다는 것을 기억할 것이다.

 

과연 게임에서는 어떤 상황과 이유에서 Collider의 충돌 범위를 설정해서 특정한 충돌을 받아들이거나 무시해야 할까?

 

만약 두 캐릭터가 서로를 향해서 총알을 발사한다고 생각해보자. 그런데 서로에게 발사한 총알끼리의 충돌을 무시하지 않고 그대로 두면 어떻게 될까? 총알끼리 충돌하면 서로에게 발사된 총알이 없어져 버리거나 튕겨져 나갈 것이다.

 

와! 총알을 쏴서 상대방의 총알을 막을 수 있는 게임이라니! 잘 만들면 꽤나 재밌고 멋있을 것 같은 컨셉이다.

 

하지만 대부분의 게임에서는 총알끼리의 충돌같은 건 구현하지 않고 무시하게 만들어버린다.

 

그 이유는 여러 가지가 있을 수 있는데 수많은 총알이 발생시키는 충돌로 게임의 성능이 저하될 수 있다는 것과 이런 총알로 총알을 맞출 수 있는 컨트롤 중심적인 시스템에서는 팬티만 입고 권총을 든 무시무시하고 고일 대로 고여버린 고인물이 달려와서 초보자가 쏜 총알을 모조리 막아버리고 초보자의 뚝배기를 터뜨려 버릴 수 있다는 것이다.

 

총알과 총알이 부딪히는 것 외에도 많은 문제가 있다.

 

어떠한 예외가 있을 수 있는지 살펴보자면 열심히 체력을 깎아놓은 몬스터가 힐팩에 스쳐서 건강해진다던가 플레이어는 던전 입구에서 헤매고 있는데 다른 층으로 넘어가는 콜라이더 앞에서 서성거리던 몬스터가 그 트리거를 건드려서 플레이어가 다음 층으로 넘아가던가 하는 많은 문제가 발생할 수 있다.

 

이걸 코드 레벨에서 막으려면 총알 클래스에는 충돌 검사를 할 때 충돌한 대상이 같은 총알이면 무시하는 코드를, 힐팩 클래스과 던전 층 이동용 트리거 클래스에서는 트리거에 닿은게 플레이어가 아니면 무시하는 코드를 작성해야 할 것이다. 이렇게 수동으로 일일이 예외를 막아야하는 경우가 많으면 많을수록 앞에서 언급한 것과 같은 어처구니가 없게 느껴지는 버그가 발생할 확률이 상승한다.

 

만약 이걸 별도의 코드 작업 없이 간단하고 일괄적으로 막을 수 있다면 당연히 그 방법을 써야될 것이다.

 

그게 바로 이번에 배울 유니티 레이어를 이용한 Collider 충돌 무시하기이다.

 

본격적인 내용에 들어가기에 앞서 아래에 있는 unity-mouse-input-practice.zip 파일을 다운로드 받아서 패키지를 임포트하도록 한다.

 

unity-mouse-input-practice.zip
다운로드

 

그리고 패키지에 포함되어 있는 Simple Character Test 씬을 열도록 한다.

 

 

먼저 게임를 플레이시키고 게임 뷰에 클릭해보면 클릭을 한 번 할 때마다 총알이 한 발씩 나가는 것을 볼 수 있다.

 

void Fire()
{
    //if(Input.GetMouseButtonDown(0))
    if(Input.GetMouseButton(0))
    {
        Vector3 firePos = transform.position + animator.transform.forward + new Vector3(0f, 0.5f, 0f);
        var bullet = Instantiate(bulletPrefab, firePos, Quaternion.identity).GetComponent<Bullet>();
        bullet.Fire(animator.transform.forward);
    }
}

 

SimpleCharacterController 스크립트를 열어서 Fire 함수 안에 있는 GetMouseButtonDown 함수를 GetMouseButton으로 바꾼 뒤, 코드를 저장하고 에디터로 돌아간다.

 

 

다시 게임을 플레이시키고 게임 뷰에서 마우스 왼쪽 버튼을 꾹 누르고 있으면 총알이 쏟아져 나오는 것을 볼 수 있다.

 

private void OnTriggerEnter(Collider other)
{
    if(other.GetComponent<Bullet>() == null)
    {
        Destroy(gameObject);
    }
}

 

그 다음에는 Bullet을 찾아서 스크립트 에디터를 열어보면 아래 쪽에 있는 트리거 감지 이벤트인 OnTriggerEnter에 앞에서 말한 것처럼 충돌 감지 예외를 코드 레벨에서 수동으로 처리하고 있는 것이 보일 것이다. 같은 총알끼리 부딪혔을 때는 무시하도록 작성되어 있다.

 

private void OnTriggerEnter(Collider other)
{
    //if(other.GetComponent<Bullet>() == null)
    {
        Destroy(gameObject);
    }
}

 

이 부분을 주석 처리 해버리면 어떻게 될까? 한 번 테스트 해보자.

 

 

게임을 플레이시키고 마우스를 클릭해보면 발사된 총알끼리 부딪혀서 앞으로 나가지 못하고 바로 사라져버리는 걸 볼 수 있다.

 

그럼 이걸 어떻게 코드 레벨의 예외처리 없이 원래대로 동작하게 만들 수 있을까?

 

이제부터 그걸 알아보자.

 

  

프로젝트 뷰에서 Prefabs 폴더 안에 있는 Bullet 프리팹을 더블클릭해서 프리팹 수정 씬을 열어보자. 그럼 선택된 Bullet 프리팹 게임 오브젝트의 내용을 인스펙터 뷰에서 볼 수 있는데 게임 오브젝트의 이름 아래를 보면 태그와 함께 Default라고 표시된 레이어를 찾을 수 있다.

 

레이어를 클릭해보면 Default, TrasparentFX, Ignor Raycast, Water, UI가 있다.

 

이 레이어에는 여러가지 역할이 있지만 대표적인 것이 바로 지금 배우고 있는 충돌 무시 설정이다.

 

항목들 중에서 제일 아래에 있는 [Add Layer]를 선택하면 레이어를 직접 만들 수 있다.

 

 

Bullet이라는 레이어를 만들어보자.

 

 

그리고 다시 Bullet 프리팹으로 돌아가서 레이어를 Bullet으로 설정한다.

 

그 다음은 레이어의 충돌 설정을 할 차례이다.

 

 

상단 메뉴 바에서 [Edit > Project Settings]를 선택해서 프로젝트 세팅 뷰를 연다.

 

 

이중에 Physics 탭으로 들어가면 레이어끼리의 충돌 설정을 할 수 있다. 가장 아래 쪽을 보면 직각삼각형 형태로 배치된 체크박스들을 볼 수 있는데 행이나 열마다 레이어의 이름이 적혀있는 것을 알 수 있다.

 

제일 앞 칸을 기준으로 보면 Default와 Bullet 사이는 체크가 되어있는데 이것은 Bullet 레이어와 Default 레이어의 오브젝트가 충돌하면 이 충돌을 감지하겠다는 뜻이다. 반대로 체크가 해제되면 두 레이어 사이의 충돌을 무시하겠다는 뜻이 된다.

 

우리는 Bullet끼리의 충돌을 무시할 계획이기 때문에 Bullet과 Bullet이 만나는 지점의 체크를 해제해준다.

 

프로젝트 세팅 뷰를 닫고 플레이를 시킨 뒤 총알을 발사해보자.

 

 

그럼 총알끼리 충돌해서 사라지지 않고 아주 잘 발사되는 것을 볼 수 있다.

 

단 레이어를 사용할 때 주의할 점은 사용자가 만들 수 있는 최대 레이어 갯수는 총 24개 뿐이기 때문에 불필요한 레이어를 함부로 남발하면 나중에 정작 필요한 레이어의 자리가 부족해지는 문제가 발생할 수 있다는 것이다.

 

[유니티 어필리에이트 프로그램]

아래의 링크를 통해 에셋을 구매하시거나 유니티를 구독하시면 수익의 일부가 베르에게 수수료로 지급되어 채널의 운영에 도움이 됩니다.

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 2D, 3D 모델, SDK, 템플릿, 툴 등 여러분의 콘텐츠 제작에 날개를 달아줄 다양한 에셋을 제공합니다.

assetstore.unity.com

 

Easy 2D, 3D, VR, & AR software for cross-platform development of games and mobile apps. - Unity Store

Have a 2D, 3D, VR, or AR project that needs cross-platform functionality? We can help. Take a look at the easy-to-use Unity Plus real-time dev platform!

store.unity.com

 

Create 2D & 3D Experiences With Unity's Game Engine | Unity Pro - Unity Store

Unity Pro software is a real-time 3D platform for teams who want to design cross-platform, 2D, 3D, VR, AR & mobile experiences with a full suite of advanced tools.

store.unity.com

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

반응형
  1. 료용 2020.04.22 01:51 신고

    베르님 유투브 파셨네요 좋은영상 기대하겠습니다.

    • wergia 2020.04.22 17:02 신고

      글만으로는 모자란 감이 있어서 구현 과정을 보여드리려고 만들었어요ㅎㅎ

Physics 

컴포지트 콜라이더 2D(Composite Collider 2D)

 

작성 기준 버전 :: 2019.1.4f1

 

컴포지트 콜라이더 2D 컴포넌트는 다수의 2D 콜라이더를 하나의 콜라이더로 합쳐주는 역할을 하는 컴포넌트이다. 이 컴포넌트는 주로 여러 개의 콜라이더가 하나의 콜라이더로 취급하기 위해서 사용된다.

 

두 콜라이더의 충돌 감지

 

 

그림 1

 

[그림 1]을 보면 원형의 폴리곤 콜라이더를 가진 오브젝트와 사각 콜라이더를 가진 오브젝트가 함께 겹쳐져 있으며 두 오브젝트가 같은 부모 게임 오브젝트 밑에 있는 것을 확인할 수 있다. 위와 같은 상태에서는 두 개의 각 콜라이더가 충돌을 각각 감지한다.

 

public class CollisionTest : MonoBehaviour

{

    private void OnCollisionEnter2D(Collision2D collision)

    {

        Debug.Log(string.Format("OnCollisionEnter2D :: / ", gameObject.name, collision.gameObject.name));

    }

 

    private void OnCollisionStay2D(Collision2D collision)

    {

        Debug.Log(string.Format("OnCollisionStay2D :: / ", gameObject.name, collision.gameObject.name));

    }

 

    private void OnCollisionExit2D(Collision2D collision)

    {

        Debug.Log(string.Format("OnCollisionExit2D :: / ", gameObject.name, collision.gameObject.name));

    }

}

 

위와 같이 충돌을 감지하는 코드를 작성하고,

 

그림 2
그림 3

 

콜라이더가 있는 각 오브젝트에 부착한 뒤,

 

그림 4

 

[그림 4]와 같이 아래로 떨어지는 게임 오브젝트를 만들어서 충돌 테스트를 해보면,

 

그림 5

 

[그림 5]의 로그와 같이 각각의 오브젝트가 따로 충돌을 감지하는 것을 확인할 수 있다.

 

 

컴포지트 콜라이더 2D(Composite Collider 2D)

 

이런 식으로 각각의 콜라이더가 따로 충돌을 감지하는 것이 아니라 두 콜라이더가 하나로 취급되어 충돌을 감지하고자 할 때, 컴포지트 콜라이더 2D를 사용하게 된다.

 

그림 6

 

컴포지트 콜라이더 2D 컴포넌트를 사용하는 방법은 위와 같이 통합하고자하는 콜라이더들의 상위에 컴포지트 콜라이더를 추가해주고,

 

그림 7

 

[그림 7]과 같이 하위에 속하는 콜라이더 컴포넌트들의 Used By Composite 프로퍼티를 true로 설정해주면 된다.

 

그림 8

 

그렇게 하면 상위 오브젝트를 선택했을때, [그림 8]과 같이 하위의 콜라이더들이 하나로 통합되어서 보이는 것을 볼 수 있다.

 

그림 9

 

로그에서도 상위 오브젝트에서의 충돌 체크만 발생하는 것을 알 수 있다.

 

리지드바디 2D(Rigidbody 2D)

 

그림 10

 

컴포지트 콜라이더 2D 컴포넌트를 게임 오브젝트에 부착하면 자동으로 리지드바디 2D 컴포넌트 역시 게임 오브젝트에 부착된다. 때문에 지형지물의 요소에 컴포지트 콜라이더 2D를 사용할 때는 이 리지드바디 2D 컴포넌트의 옵션에 신경써야 한다.

 

그림 11

 

옵션에 신경쓰지 않을 경우, [그림 11]처럼 캐릭터가 지형에 닿자마자 지형이 떨어지거나, 게임이 시작하자마자 지형이 추락해서 지형이 사라지는 모습을 보게 될 수도 있다.

 

그림 12

 

이렇게 컴포지트 콜라이더 2D 컴포넌트를 적용한 게임 오브젝트를 고정된 지형요소로 사용하고자 한다면 리지드바디2D의 바디타입을 Static으로 설정해야한다.

 

그림 13

 

 

 

생성 타입(Generation Type)

 

그림 14

 

컴포지트 콜라이더 2D 컴포넌트에는 생성 타입이라는 프로퍼티가 존재하는데 Synchronous와 Manual 옵션이 존재한다.

 

그림 15

 

Synchronous는 [그림 15]처럼 하위 콜라이더들이 변동되는 때마다 바로 통합된 콜라이더를 새로 만드는 옵션이고, 

 

그림 16

 

Manual은 컴포지트 콜라이더 2D 컴포넌트가 처음 부착되는 시점 호은 콜라이더 재생성(Regenerate Collider) 버튼을 누른 시점에만 콜라이더를 만드는 옵션이다.

 

그림 17

 

[그림 17]과 같이 아래에 있는 노란 원이 애니메이션에 의해서 위치가 바뀌어도 콜라이더는 따라서 움직이지 않기 때문에 빈 공간에 충돌하는 것을 알 수 있다.

 

위의 설명에서 알 수 있듯이 Synchronous 옵션은 통합된 콜라이더가 변경되는 애니메이션에 따라서 지속적으로 업데이트가 되어야하는 경우에 사용하고, 반대로 Manual은 통합된 콜라이더가 일반 지형과 같이 변경되는 경우가 없는 경우에 사용된다.

 

지오메트리 타입(Geometry Type)

 

그림 18

 

그 다음 중요한 옵션은 지오메트리 타입이다. 이 프로퍼티는 콜라이더를 생성할 때 어떤 형태로 생성할 것인가를 결정한다. 옵션 값은 Outlines와 Polygons가 있다. 

 

그림 19
그림 20

 

Outlines로 콜라이더를 생성하면 [그림 19]와 같이 내부에 아무선 선이 없이 생성되고, Polygons로 콜라이더를 생성하면 [그림 20]과 같이 내부에 선이 그어져서 나온다. 이 차이가 의미하는 것은 Outlines 옵션의 경우에는 콜라이더가 외부에 선만 그어져 있고 속은 비어있다는 뜻이고, Polygons 옵션은 내부가 꽉 차있다는 뜻이다.

 

콜라이더의 내부를 굳이 채울 필요가 있냐고 생각할 수도 있지만, 이것은 확실히 필요한 개념이다. 게임 내에서의 발생하는 충돌 감지나 레이캐스트는 주로 옆에서 날아오기 때문에 Outlines 옵션 만으로도 충분하지만 화면 밖에서 들어오는 터치나 사용자의 클릭 같은 이벤트는 개념적으로 위에서 들어오기 때문에 콜라이더의 내부가 차있는 것이 좋다.

 

public class Picker : MonoBehaviour

{

    private void Update()

    {

        if (Input.GetMouseButtonDown(0))

        {

            var hitResult2D = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), transform.up, 0.1f);

            Debug.Log("2D Raycast Result :: " + hitResult2D.collider.name);

        }

    }

}

 

위와 같이 마우스를 클릭한 지점에서 레이캐스트를 발사해서 콜라이더를 검출하는 코드를 작성해서 Outlines 옵션으로 만들어진 컴포지트 콜라이더와 Polygons 옵션으로 만들어진 컴포지트 콜라이더를 클릭하는 테스트를 진행해보면 그 차이를 명확하게 인지할 수 있다.

 

[유니티 어필리에이트 프로그램]

아래의 링크를 통해 에셋을 구매하시거나 유니티를 구독하시면 수익의 일부가 베르에게 수수료로 지급되어 채널의 운영에 도움이 됩니다.

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 2D, 3D 모델, SDK, 템플릿, 툴 등 여러분의 콘텐츠 제작에 날개를 달아줄 다양한 에셋을 제공합니다.

assetstore.unity.com

 

Easy 2D, 3D, VR, & AR software for cross-platform development of games and mobile apps. - Unity Store

Have a 2D, 3D, VR, or AR project that needs cross-platform functionality? We can help. Take a look at the easy-to-use Unity Plus real-time dev platform!

store.unity.com

 

Create 2D & 3D Experiences With Unity's Game Engine | Unity Pro - Unity Store

Unity Pro software is a real-time 3D platform for teams who want to design cross-platform, 2D, 3D, VR, AR & mobile experiences with a full suite of advanced tools.

store.unity.com

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

반응형
  1. 료용 2019.12.26 02:05

    안녕하세요 베르님 좋은글잘보고있습니다.

+ Recent posts