내비게이션 시스템 (1) 

NavMesh

 

작성 기준 버전 :: 2019.2

 

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

 

이번 포스트에서는 유니티의 내비게이션 시스템에 대해서 알아보도록 하자.

 

 

내비게이션이라는 단어는 실생활에서도 많이 들어보았을 것이다. 어떠한 목적지까지 가는 경로를 알려주는 프로그램을 우리는 내비게이션이라고 부른다.

 

유니티에서도 어떤 한 지점에서 다른 지점으로 이동하는 길을 알려주는 역할을 하는 것이 바로 내비게이션 시스템이다. 그런데 원하는 지점까지 캐릭터를 조작해서 이동하면 될텐데 내비게이션 시스템이 왜 필요할까?

 

물론 플레이어는 캐릭터를 잘 조작해서 원하는 지점까지 이동할 수 있을 것이다. 하지만 플레이어가 조작하는 캐릭터가 아니라 AI가 조작하는 몬스터 같은 NPC는 어떨까?

 

일직선의 아무런 장애물이 없는 길이라면 AI가 조작하는 몬스터라도 무리없이 목적지까지 도착할 수 있겠지만, 벽이나 기둥, 상자 같은 장애물이 가득하고 구불구불한 길이라면 몬스터는 장애물에 막혀서 제대로 목적지에 도착하지 못할 것이다.

 

내비게이션 시스템은 바로 이렇게 장애물이 가득한 환경에서 AI가 최단 경로를 찾아서 목적지에 도달하는 것을 도와주기 위해서 필요한 것이다.

 

그럼 이제 본격적으로 유니티의 내비게이션 시스템에 대해서 이야기해보자.

 

유니티의 내비게이션 시스템은 기본적으로 NavMesh, NavMeshAgent, NavMeshObstacle. 이 세 가지 요소로 이루어집니다.

 

NavMesh

 

이번 포스트에서는 먼저 NavMesh에 대해서 살펴보자.

 

 

하이어라키 뷰에 우클릭하고 [3D Object > Plane]을 선택해서 평면을 하나 만들고 크기를 x는 3, z는 10으로 설정한다. 그러면 적당히 캐릭터가 움직일 만한 바닥이 만들어진다.

 

 

이 다음에는 상단 메뉴바에서 [Window > AI > Navigation]을 선택하면 내비게이션 뷰가 열린다.

 

 

내비게이션 뷰에는 Agent, Area, Bake, Object, 이렇게 네 개의 탭이 있다.

 

Object 탭

 

이 중에서 일단 Object 탭을 먼저 살펴보도록 하자.

 

Object 탭에서는 제일 상단에 Scene Filter를 볼 수 있는데 필터의 종류로는 All, Mesh Renderer, Terrains가 있다.

 

우선 All 필터는 씬에 있는 모든 오브젝트를 보여주는 필터다. 

 

그리고 Mesh Renderer 필터는 Plane처럼 Mesh Renderer 컴포넌트를 가지고 있는 게임 오브젝트만을 보여주도록 하는 필터다.

 

마지막 Terrains 필터는 유니티 엔진에서 거대한 평면에 직접 높낮이를 조절하면서 지형을 만들 수 있는 터레인 오브젝트만을 보여주도록 하는 것이다.

 

터레인이 아니거나 메시 렌더러(Mesh Renderer) 컴포넌트를 가지지 않은 게임 오브젝트를 선택하면 메시 렌더러를 가진 게임 오브젝트나 터레인을 선택해 달라는 문구가 표시된다.

 

 

배치한 Plane을 선택하면 Navigation Static을 체크할 수 있는 체크박스와 함께 다른 옵션들이 나온다. 한마디로 터레인이나 메시 렌더러 컴포넌트를 가진 게임 오브젝트만 캐릭터가 돌아다닐 수 있는 내비게이션 영역으로 설정할 수 있다는 뜻이다.

 

여기서 Navigation Static을 체크해보면 아래 쪽의 옵션들도 활성화되는 것을 볼 수 있다. Navigation Static을 체크하면 해당 메시를 캐릭터가 길을 찾을 수 있는 표면으로 설정된다.

 

우선은 아래 쪽의 두 항목은 나중에 알아보도록 하고 넘겨두도록 하자.

 

Bake 탭

 

 

Bake 탭에는 원기둥 그림과 함께 다양한 옵션들이 보이지만 그보다 먼저 제일 아래에 이 탭의 주인공처럼 보이는 Bake 버튼을 눌러보자.

 

 

Bake 버튼을 누르면 씬 뷰에서 Plane 위에 파란색 영역이 생겨난 것을 볼 수 있다. 이게 바로 캐릭터가 길을 찾아서 이동할 수 있는 영역을 의미하는 NavMesh이다.

 

참고로 Bake는 빵이나 과자같은 것을 굽는다는 뜻을 가지고 있다. 그래서 이렇게 NavMesh를 만드는 작업 역시 "NavMesh를 굽는다"라고 표현한다.

 

 

캐릭터가 돌아다닐 NavMesh를 만들기는 했지만 아무 장애물도 없어서 너무 밋밋해보이기 때문에 몇 가지 장애물을 설치해보자. 그리고 새로 만든 장애물 역시 Object 탭에서 Navigation Static으로 설정해준 뒤, Bake 탭에서 NavMesh를 구워보자.

 

 

그러면 완전히 평면이었던 파란색 영역이 배치한 장애물을 따라서 여러 면으로 쪼개지는 것을 볼 수 있다.

 

Mesh라는 단어는 3D에서는 삼각형이나 다각형 여러 개로 면을 구성하는 것을 의미한다. NavMesh는 다각형 여러 개로 캐릭터가 이동할 수 있는 표면을 구성하는 것이다. 이 면들을 이용해서 캐릭터가 찾아갈 길을 찾아내는 것이다.

 

그럼 이제부터 Bake 탭의 주요 옵션들을 하나씩 알아보도록 하자.

 

Agent Radius

 

Agent는 내비게이션 메시 위에서 움직이는 대상을 의미한다. 즉 Agent Radius는 NavMesh 위에서 움직일 대상의 반지름이다.

 

 

이 값을 1로 변경하고 NavMesh를 새로 구워보면 내비게이션 메시의 비어있는 경계 부분이 넓어지는 것을 볼 수 있다. 이것은 NavMesh 위를 돌아다닐 Agent의 Radius가 증가해서 뚱뚱해졌기 때문에 벽에 바짝 붙어서 움직일 수 없기 때문에 이렇게 된 것이다.

 

Agent Radius를 원상복구하고 NavMesh를 다시 구워보면 날씬해진 Agent가 돌아다닐 수 있는 범위가 증가한다.

 

Agent Height

 

Agent Height = 2
Agent Height = 1
Agent Height = 4

 

 Agent Height를 Agent의 키를 의미한다.

 

오르막길 아래의 작은 길을 보면서 Height를 1로 변경하면 Agent의 작아진 높이 때문에 통과할 수 있는 범위가 늘어나는 것을 볼 수 있다. 반대로 Height를 4로 변경하면 오르막길 아래의 샛길로 이동하지 못하게 된다.

 

Max Slope

 

Max Slope 값은 NavMesh에 이동할 수 있는 길로 포함될 수 있는 경사로의 최대 각도를 의미한다.

 

여기 맵에 배치된 경사로의 각도는 25도이다. 그리고 Bake 옵션의 최대 경사로 각도의 기본값은 45도이다.

 

 

그렇기 때문에 NavMesh를 구울 때 이 경사로가 이동할 수 있는 지역으로 포함된 것이다.

 

 

만약 MaxSlope 값을 25도보다 작은 20도로 변경하고 다시 구우면 이 경사로가 이동할 수 없는 지역이 되는 것을 볼 수 있다.

 

Step Height

 

그 다음 Step Height는 Agent가 가벼운 계단 정도로 여기고 올라갈 수 있는 단의 높이를 의미한다. 기본 값은 0.4로 설정되어 있다.

 

 

맵에 낮은 단으로 설치된 오브젝트의 높이는 0.25로 Step Height가 이보다 크기 때문에 이 단 역시 NavMesh로 연결되어 있다.

 

 

Step Height를 0.1로 변경하고 내비게이션 메시를 구워보면 연결된 NavMesh가 끊어져서 이동할 수 없는 지역이 되는 것을 볼 수 있다.

 

이렇게 Agent Radius, Agent Height, Max Slope, Step Height를 이용해서 내비게이션 메시의 영역을 설정할 수 있다.

 

Area 탭

 

 

Area 탭에서는 사용자가 필요한 내비게이션 메시 구역을 설정하고 그 구역을 지나가는 비용을 설정할 수 있다. 기본 Area로는 Walkable, Not Walkable, Jump. 이렇게 세 가지가 있다.

 

 

User3 위치에 Water를 추가하고 비용을 3으로 설정해보자.

 

 

그리고 맵에 추가적인 구조물을 몇 개 더 설치해보자. 이렇게 다른 쪽으로 넘어가는 두 갈래 길을 만들었다.

 

한 쪽은 바닥이 내려간 길이고 다른 한 쪽은 바닥이 올라간 다리 같은 길이다.

 

먼저 제일 낮은 바닥 부분을 제외한 구역을 선택해서 Navigation Static을 체크하고 Area는 Walkable으로 둔다. 그 다음에는 바닥을 선택해서 Navigation Static을 체크하고 Area를 Water로 설정한 다음 NavMesh를 구워보자.

 

 

그러면 다른 구역은 전부 같은 파란색으로 영역이 지정되지만 가장 낮은 바닥만 다른 색으로 지정된다.

 

반대편으로 넘어가는 블록 한 칸의 이동 비용을 1이라고 가정했을 때, 여기서 건너편으로 건너가기로 결정했을 때 이 다리를 건너는 비용은 3이고, Water로 지정된 바닥을 건너는 비용은 5이기 때문에 위로 건너는 방법이나 아래로 건너는 방법이나 이동 거리 자체는 같지만, Agent는 가급적이면 이 다리 쪽 경로를 선택하려고 할 것이다.

 

이렇게 Area마다 다른 비용을 책정해서 내비게이션 메시를 잘 구성하면 길은 쉽지만 몬스터가 자주 돌아다니는 구역과 몬스터는 자주 오지 않지만 함정이 많은 구역처럼 좀 더 다양한 레벨 디자인을 손쉽게 구성할 수 있을 것이다.

 

Agents 탭

 

 

Agents 탭에는 Bake 탭에서 본 것과 같은 그림과 옵션들이 있다. 다만 Humanoid라는 기본 타입과 함께 새로운 타입을 추가할 수 있다.

 

덩치가 큰 에이전트와 덩치가 작은 에이전트를 만들어서 덩치가 작은 에이전트는 지나갈 수 있는 곳을 덩치가 큰 에이전트는 돌아서 가야되게 만들 수 있다.

 

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

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

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 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

 

반응형

Programming 

코루틴(Coroutine) 다루기 2(코루틴 중단하기 + 코루틴 매개변수 + yield break)

 

작성 기준 버전 ::2019.2

 

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

 

이번 포스트에서는 지난 코루틴 포스트에서 다루지 못했던 코루틴 중단하기와 코루틴 함수에 매개변수 전달하기 그리고 yield break에 대해서 다뤄보도록 하자.

 

코루딘 중단하기

 

public class CoroutineTest : MonoBehaviour
{
    IEnumerator enumerator;

    void Start()
    {
        // 코루틴 함수를 직접 호출해서 중단시키려면 IEnumerator를 저장해서 사용
        enumerator = TestCoroutine();
        StartCoroutine(enumerator);
    }

    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Space))
        {
            // 코루틴 함수를 직접 호출해서 중단시키려면 IEnumerator를 저장해서 사용
            StopCoroutine(enumerator);
        }
    }

    IEnumerator TestCoroutine()
    {
        int i = 0;
        while(true)
        {
            yield return null;
            Debug.Log("Coroutine " + i);
            i++;
        }
    }
}

 

코루틴을 정지시키는 기본적인 방법의 위의 코드와 같다.

 

위 코드는 게임이 시작되면 Start 함수에 StartCoroutine으로 TestCoroutine 함수를 실행시켜 준다. 그러면 코루틴 함수 내용에 따라서 "Coroutine"이라는 로그와 함께 반복된 횟수를 출력한다. 그리고 플레이 도중에 스페이스 키를 누르면 코루틴이 멈추면서 로그 출력이 중단된다.

 

StartCoroutine(TestCoroutine());

 

보통 때는 바로 위 코드처럼 코루틴 함수를 호출했을 텐데 IEnumerator에 저장해서 실행한 이유는 TestCoroutine 함수에서 받아온 IEnumerator를 StopCoroutine에 넣어주기 위해서 이다.

 

StartCoroutine과 StopCoroutine은 이 IEnumerator를 통해서 어떤 코루틴을 실행하고 중단시킬지 확인할 수 있다.

 

코루틴 함수 이름을 문자열로 이용하기

 

StartCoroutine("TestCoroutine");

StopCoroutine("TestCoroutine");

 

이전 코루틴 포스트에서는 알려주지 않은 방법이 있는데, 코루틴을 실행시킬 때 그 코루틴 함수의 이름만으로도 실행시킬 수 있다는 것이다. 그리고 코루틴의 이름으로도 코루틴을 정지시킬 수 있.

 

어떤 면에서 보면 코루틴의 이름으로 코루틴을 시작하고 멈추는 방법이 더 낫다고 여길 수도 있다. 하지만 한 오브젝트에서 같은 이름의 코루틴이 2개 이상 실행되고 있는 상태에서 코루틴의 함수 이름 문자열로 StopCoroutine을 호출하면 이름으로 실행된 모든 코루틴이 동시에 멈춰버린다.

 

StartCoroutine(TestCoroutine());   // 코루틴 함수를 호출해서 실행한 코루틴은

StopCoroutine("TestCoroutine");    // 코루틴 이름 문자열로 중단시킬 수 없음

 

그와 더불어 위 코드처럼 코루틴 함수를 호출해서 실행한 코루틴은 코루틴 이름 문자열로 중단시킬 수 없다.

 

문자열로 코루틴을 실행하는 방법은 편리하지만 사용을 권장하지는 않는다. 그 이유는 문자열이기 때문에 오타가 발생해도 에러 표시가 되지 않아서 문제가 발생할 소지가 높기 때문이다. 그리고 이렇게 상수 문자열은 게임을 출시하는 과정에서 앱 보안을 위한 암호화 과정을 거칠 때, 코루틴 이름과 다른 문자열로 변경되어서 코루틴 함수 호출에 실패하게 되는 경우가 발생하기도 한다.

 

모든 코루틴 동시에 중단시키기

 

StopAllCoroutines();

 

코루틴을 중단시키는 마지막 방법으로는 StopAllCoroutines가 있다. StopAllCoroutines 함수를 사용하면 이 컴포넌트가 실행하고있는 모든 코루틴을 중단시킨다.

 

코루틴 함수에 매개변수 전달하기

 

IEnumerator TestCoroutine(int count)
{
    int i = 0;
    while(i < count)
    {
        yield return null;
        Debug.Log("Coroutine " + i);
        i++;
    }
}

 

그럼 이번에는 코루틴 함수에 매개변수를 전달하는 방법을 알아보자.

 

TestCoroutine 코루틴 함수를 위와 같이 매개변수를 받을 수 있게 약간 변경한다. int 타입의 count 매개변수를 받아서 count 횟수만큼 반복하게 되었다.

 

StartCoroutine(TestCoroutine(10));

 

코루틴 함수 호출 방식에서는 TestCoroutine의 매개변수에 바로 값을 넣어주면된다.

 

StartCoroutine("TestCoroutine", 10);

 

코루틴 이름 문자열로 코루틴을 실행시킬 때는 문자열의 이름 뒤에 콤마를 찍고 매개변수를 넣어주면 된다.

 

Coroutine StartCoroutine(string methodName, object value);

 

코루틴 이름 문자열로 코루틴을 실행시키면서 매개변수를 받는 StartCoroutine의 오버로드 형식은 string으로 코루틴 함수의 이름을 받고 object 타입으로 매개변수를 받는다.

 

참고로 object 타입은 C# 프로그래밍에서 모든 변수 타입의 최상위 타입이다. 그래서 이렇게 int 타입의 숫자를 넣어주면 object 타입으로 바꿔서 받는다. 그리고 TestCoroutine 함수를 호출하면서 내부적으로 int 타입으로 바꿔서 전달해준다다.

 

StartCoroutine(TestCoroutine(10));

StartCoroutine("TestCoroutine", 10);

 

그렇기 때문에 이 두 가지 호출 방식은 똑같이 동작한다.

 

코루틴 함수 이름 문자열 실행 방식의 매개변수 전달 방식의 약점

 

박싱/언박싱의 오버헤드

 

// 박싱(Boxing)
int i = 10;
object obj = i;

// 언박싱(Unboxing)
int j = (int)obj;

 

하지만 이렇게 object로 매개변수를 전달하는 방법에는 약점이 몇 가지 있다. 먼저 프로그래밍에서 다른 타입의 변수를 object 타입으로 만드는 과정을 박싱(Boxing)이라고 부르고 object 타입의 변수를 원래 타입의 변수로 되돌리는 과정을 언박싱(Unboxing)이라고 부른다.

 

이 박싱/언박싱 과정은 미세하지만 분명히 성능적인 오버헤드를 일으킨다. 게임 최적화를 위해서는 남발하지 않는게 좋다.

 

전달 가능한 매개변수의 갯수

 

IEnumerator TestCoroutine(int count, float time)
{
    yield return new WaitForSeconds(time);

    int i = 0;
    while(i < count)
    {
        yield return null;
        Debug.Log("Coroutine " + i);
        i++;
    }
}

 

그리고 두 번째 약점을 설명하기 위해서 TestCoroutine의 기능을 조금 변경하기로 했다고 가정해보자.

 

매개변수에 float 타입으로 time 변수를 추가로 받아서 그 시간만큼 기다렸다가 count 횟수만큼 반복하도록 변경했다. 이렇게 되면 매개변수가 2개로 바뀌게 된다. 

 

StartCoroutine(TestCoroutine(10, 3f));

 

그러면 코루틴 함수 자체로 호출하는 방식에서는 새로운 매개변수를 넣어달라고 에러가 표시되기 때문에 추가된 기능에 맞게 매개변수를 넣어주기만 하면 된다.

 

하지만 코루틴 함수의 이름으로 호출하는 방식에서는 매개변수를 전달할 object가 하나 뿐이라 두 번째 매개변수를 전달할 방법이 없다. 그러니까 이름으로만 호출할 때는 매개변수를 하나 밖에 쓸 수 없는 것이다.

 

물론 클래스나 구조체로 묶어서 보내는 방법도 있겠지만 굳이 그렇게 번거로운 방법쓰는 것 보다는 코루틴 함수에 바로 매개변수 여러 개를 사용하는 것이 편할 것이다.

 

yield break

 

IEnumerator ReturnCoroutine()
{
    Debug.Log("Return 1");
    yield return null;  // 코드의 제어권을 잠시 양보했다가 돌려받아서 아래 코드를 계속 진행
    Debug.Log("Return 2");
}

IEnumerator BreakCoroutine()
{
    Debug.Log("Break 1");
    yield break;    // 코루틴 함수를 이 시점에 종료
    Debug.Log("Break 2");
}

 

마지막으로는 yield break 문에 대해서 알아보도록 하자.

 

yield return을 사용할 ReturnCoroutine과 yield break를 사용할 BreakCoroutine을 만든다.

 

이 두 코루틴을 실행하면 ReturnCoroutine은 Return 1과 Return 2가 모두 출력되지만 BreakCoroutine에서는 Break 1만 출력되고 Break 2는 출력되지 않는 것을 볼 수 있다.

 

yield break가 호출된 순간에 코루틴 함수가 완전히 멈춰버린 것이다.

 

yield return은 코드의 제어권을 유니티 엔진에 잠시 넘겼다가 특정 시점이 되면 다시 받아서 코드를 진행하지만 yield break는 그 시점에 코루틴을 완전히 멈춰버린다.

 

코루틴 내부에서 특정 조건을 만족하면 yield break로 코루틴을 멈추는 방식으로 사용할 수 있다.

 

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

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

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 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

 

반응형

UI 비법서 (6) 

Image 컴포넌트

 

작성 기준 버전 :: 2019.2

 

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

 

이번 포스트에서는 유니티 UI의 기본이 되는 Image 컴포넌트에 대해서 알아보자.

 

2D Sprite 패키지

 

유니티에서 UI와 관련된 기능을 제대로 사용하기 위해서는 2D Sprite 패키지를 설치해야 한다.

 

 

2D Sprite 패키지를 임포트하기 위해서 상단 메뉴바에서 [Window > Package Manager]를 선택하고 패키지 매니저를 연다.

 

 

잠시 기다리면 설치 가능한 패키지 전체가 나올 텐데, 만약 곧바로 2D Sprite 패키지가 보이지 않으면 왼쪽 상단의 Packages 탭 아래의 [+] 버튼 옆에 있는 버튼을 클릭해서 All Packages를 선택하면 설치가능한 모든 패키지가 나온다.

 

 

그 중에서 2D Sprite를 선택하고 오른쪽 아래의 Install 버튼을 클릭한다.

 

Sprite

 

유니티 엔진에서 사용되는 이미지 리소스를 텍스쳐(Texture)라고 부른다. 이 텍스쳐 중에서도 Image 컴포넌트나 2D 게임의 오브젝트로 그려지는 스프라이트 렌더러에서 사용되는 리소스들을 스프라이트(Sprite)라고 한다. 

 

 

보통 유니티 프로젝트에 임포트되는 텍스쳐들은 자동으로 Texture Type이 Default로 정해진다. Default는 주로 3D 모델 오브젝트의 텍스쳐로 사용되는 타입이다.

 

 

UI에 사용하기 위해서는 이 Texture Type을 Sprite로 변경해주어야 한다. 임포트한 텍스쳐들을 선택하고 Texture Type을 Sprite로 변경해주자.

 

이미지 게임 오브젝트 생성하기

 

 

이미지 게임 오브젝트를 생성하기 위해서는 하이어라키 뷰에 우클릭하고 [UI > Image] 항목을 선택하면 된다.

 

이미지 게임 오브젝트를 만들 때 씬 안에 캔버스 게임 오브젝트가 없으면 자동으로 캔버스 게임 오브젝트를 생성하고 그 아래에 이미지 게임 오브젝트가 만들어진다. 이미 캔버스 게임 오브젝트가 있다면 그 캔버스 오브젝트 아래에 이미지 게임 오브젝트가 생긴다.

 

Image 컴포넌트

 

 

유니티 엔진에서 화면에 그림을 표현하기 위해 사용되는 것이 바로 이 Image 컴포넌트다. 기본 Image 컴포넌트는 화면에 그림을 보여주기만 하고 클릭한다던가 하는 상호작용이 불가능하다.

 

UI 작업을 좀 더 편하게 하기 위해서는 단축키 [2]를 눌러서 2D 작업모드로 변경하면 된다.

 

Image 컴포넌트의 프로퍼티들

 

이미지 게임 오브젝트를 선택하고 게임 오브젝트에 부착되어 있는 Image 컴포넌트를 보면 Source Image, Color, Material, Raycast Target과 같은 프로퍼티를 볼 수 있다.

 

Source Image

 

 

우선 Source Image는 이 Image 컴포넌트가 화면에 보여줄 그림을 설정할 수 있는 프로퍼티이다. 이 프로퍼티가 비어있으면 위의 이미지처럼 그냥 하얀 이미지로 화면에 표시된다.

 

 

Source Image에 다른 스프라이트를 넣어주면 하얀 이미지가 넣어준 스프라이트로 바뀌게 된다.

 

using UnityEngine.UI;

public class ImageChanger : MonoBehaviour
{
    private Image image;

    [SerializeField]
    private Sprite sprite;

    void Start()
    {
        image = GetComponent<Image>();

        // image.sprite로 Image 컴포넌트의 Source Image에 접근
        image.sprite = sprite;
    }
}

 

스크립트에서는 image.sprite를 통해서 Source Image에 접근해서 화면에 그리는 이미지를 바꿀 수 있다.

 

Color

 

 

Color 프로퍼티는 이미지의 색상을 바꿀 때 사용된다.

 

 

하얗게 표시된 색상 부분을 클릭해보면 색을 바꿀 수 있는 Color 대화상자가 표시된다. R값은 빨간 색 계열, G값은 초록 색 계열, B값은 파란 색 계열을 의미한다.

 

 

그리고 A는 알파(Alpha) 값으로 투명도를 의미한다. 수정하면 이미지를 투명하게 만들 수 있다.

 

Material

 

Material 프로퍼티는 이미지에 머티리얼을 넣어서 흐리게 보이게 만든다거나 왜곡되어 보이게 하는 것처럼 특별한 효과를 넣고자 할 때 사용된다.

 

Raycast Target

 

Raycast Target 프로퍼티는 이 이미지를 Raycast의 타깃으로 삼을 것인가를 결정하는 것이다.

 

이 프로퍼티의 기능을 이해하려면 Raycast가 무엇인지 이해해야하는데 간단하게 설명하면 클릭한 위치에 일종의 광선을 쏴서 그 광선에 맞은 오브젝트를 검출해내는 것이다.

 

한마디로 Raycast의 타깃으로 삼는다는 것은 이 오브젝트를 클릭했을 때 Raycast에 검출이 되게 한다는 의미이다.

 

이것을 확인해보려면 Image 컴포넌트가 붙어 있는 게임 오브젝트에 Button 컴포넌트를 붙여보면 된다.

 

 

Button 컴포넌트를 붙인 다음 게임을 플레이시키고 이미지를 클릭해보면 이미지가 깜빡거리면서 상호작용이 일어나고 있는 것을 알 수 있다. 하지만 Raycast Target을 끄고 버튼을 클릭해보면 더 이상 클릭이 되지 않는다.

 

이렇게 Raycast Target 옵션은 이미지가 클릭을 받아들이게 만들지 말지를 설정하는데 사용된다.

 

Image Type

 

 

Source Image를 넣으면 비어있을 때는 없던 프로퍼티들이 새로 생긴 것을 볼 수 있다.

 

Image Type은 이미지가 그려지는 방식을 결정하는 프로퍼티이다.

 

Simple

 

Simple은 보이는 그대로 이미지를 바로 보여주는 타입이다.

 

Use Sprite Mesh

 

Use Sprite Mesh는 이미지를 그리는 영역을 지정할 때, 그냥 사각형 영역으로 그릴지 아니면 이미지의 알파 영역을 무시하고 최대한 그림의 형태에 맞는 영역으로 그릴지를 결정한다.

 

 

 

화면에 그려지고 있는 초록색 이미지를 보면 그림에 투명한 부분이 많은 것을 알 수 있다.

 

 

씬 뷰의 왼쪽 상단에 Shaded라고 표시된 부분을 클릭해서 Overdraw를 선택한다.

 

 

그러면 씬 뷰가 까맣게 변하고 UI가 있는 부분은 갈색으로, UI가 겹쳐진 부분은 옅은 갈색으로 표시되는 것을 볼 수 있다.

 

이렇게 UI가 겹쳐진 것을 Overdraw라고 부르며, 이렇게 겹쳐진 부분의 픽셀을 화면이 갱신될 때마다 겹쳐진 횟수만큼 다시 그리기 때문에 반드시 필요한 경우가 아니라면 이미지가 겹쳐서 그려지는 것을 피해야 한다. 그런 의미에서 이런 쓸데없는 알파값 부분을 제외하고 그림의 형태 대로만 다시 그리도록 하는게 좋을 것이다.

 

 

Use Sprite Mesh를 체크하면 사각형으로 잡혀있던 이미지의 영역이 최대한 이미지의 영역에 가깝게 바뀐것을 볼 수 있다.

 

Preserve Aspect

 

 

Preserve Aspect는 Source Image의 원본 비율을 지켜서 그릴 것인지를 정하는 프로퍼티이다. 보통은 Image 컴포넌트가 부착된 UI 게임 오브젝트의 너비와 높이에 따라서 그림의 비율이 변형되어서 화면에 그려지지만 Preserve Aspect를 체크하면 비율을 지킨 상태로 화면에 그려지게 할 수 있다.

 

Sliced

 

Sliced 타입은 9슬라이싱이라는 기능을 사용하기 위한 것으로 작은 크기의 이미지를 모서리 부분의 해상도를 유지하고 가운데 부분을 늘어뜨려서 채워주는 방식으로 UI의 크기를 자유자재로 사용할 수 있게 도와주는 타입이다.

 

 

우선 이미지를 9슬라이싱 하기 위해서는 프로젝트 뷰에서 9슬라이싱을 적용할 스프라이트를 선택하고 인스펙터 뷰에서 Sprite Editor 버튼을 클릭하면 된다.

 

 

 

그리고 스프라이트 에디터에서 모서리 부분과 중간에 반복될 부분을 적당히 나눠주고 Apply 시키면 9슬라이싱이 적용된다.

 

 

이렇게 슬라이싱된 이미지를 넣은 Image 컴포넌트의 Image Type을 Sliced로 적용하면 이미지가 크기에 따라 늘어지지 않는 것을 볼 수 있다.

 

Fill Center

 

 

Fill Center 프로퍼티는 Sliced로 늘어난 이미지의 가운데를 채울 것인가를 결정한다.

 

Pixel Per Unit

 

 

Pixel Per Unit 프로퍼티는 이미지의 1픽셀을 유니티에서 어떤 크기로 화면에 그릴 것인가를 결정한다.

 

Tiled

 

 

Tiled 타입은 이미지를 반복으로 그려주는 타입이다.

 

Filled

 

 

Filled는 차오르는 게이지 같은 연출을 표현할 때 주로 사용된다.

 

하위 프로퍼티로는 Fill Method, Fill Origin, Fill Amount가 있다.

 

Fill Method는 Radial 360, Radial 180, Radial 90, Vertical, Horizontal이 있다.

 

Fill Origin은 채우기를 시작하는 지점을 정하는 프로퍼티인데, Fill Method마다 조금씩 다른 값을 가지고 있다.

 

그리고 Clockwise는 Radial 타입 메소드에서 사용되는 프로퍼티로 이미지를 시계방향으로 차오르게 할 지, 반시계 방향으로 차오르게 할 지를 설정하는 데 쓰인다.

 

Radial 360

 

 

Radial 360은 중심을 기준으로 360도 회전하며 이미지가 차오르게 만드는 방식이다. 

 

Fill Origin은 Top, Bottom, Left, Right로 바꿀 수 있다. 

 

이 형태는 원형 스킬 UI에서 쿨타임이 줄어드는 연출을 하고자 할때 주로 사용된다.

 

Radial 180

 

 

Radial 180은 한 쪽 변을 기준으로 180도 회전하며 이미지가 차오르게 만드는 방식이다. 

 

Fill Origin은 Top, Bottom, Left, Right로 바꿀 수 있다. 

 

Radial 90

 

 

Radial 90은 한 쪽 꼭지점을 기준으로 90도 회전하며 이미지가 차오르게 만드는 방식이다.

 

Fill Origin은 Bottom Left, Bottom Right, Top Left, Top Right로 바꿀 수 있다. 

 

Vertical

 

 

Vertical은 이미지를 위/아래로 차오르게 만드는 방식이다.

 

Fill Origin은 Top, Bottom으로 바꿀 수 있다. 

 

사각형 스킬 UI에서 스킬 쿨다운 연출이나 과열된 장비의 냉각을 연출하는데 쓰면 좋다.

 

Horizontal

 

 

Horizontal은 이미지를 좌/우로 차오르게 만드는 방식이다.

 

Fill Origin은 Left, Right로 바꿀 수 있다. 

 

로딩 바나 경험치 바처럼 차오르는 연출을 보여주는데 자주 사용한다.

 

스크립트에서 Fill Amount 값 조절하기

 

using UnityEngine;
using UnityEngine.UI;

public class ImageFiller : MonoBehaviour
{
    private Image image;

    void Start()
    {
        image = GetComponent<Image>();
    }


    float timer = 0f;
    void Update()
    {
        timer += Time.deltaTime;
        image.fillAmount = Mathf.Sin(timer) * 0.5f + 0.5f;
    }
}

 

스크립트에서는 image.fillAmount를 통해서 Image 컴포넌트의 Fill Amount 값을 조절할 수 있다.

 

Set Native Size

 

 

Set Native Size 버튼은 Image 컴포넌트가 부착된 UI 게임 오브젝트의 Width와 Height를 Source Image로 넣은 스프라이트의 해상도와 같게 만들어주는 버튼이다.

 

예를 들어 Source Image로 512x512 해상도의 스프라이트를 넣고 Set Native Size 버튼을 누르면 이미지 게임 오브젝트의 Width와 Height도 512x512로 변경된다.

 

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

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

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 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

 

반응형

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

 

반응형

Programming 

씬 불러오기

 

작성 기준 버전 :: 2019.2

 

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

 

유니티 엔진의 씬은 게임의 맵이나 레벨 개념에 해당한다. 그리고 대부분의 게임은 하나보다 많은 맵이나 레벨, 즉 씬으로 구성된다. 그래서 게임에서 다른 씬으로 넘어가기 위해서는 씬과 씬 사이를 이동하기 위해서 다른 씬을 불러오는 방법을 알아야 한다.

 

씬 세팅하기

 

 

먼저 프로젝트를 제일 처음 생성했을 때 있는 씬에 큐브 오브젝트를 생성하고 카메라 앞 왼쪽 화면에 보이게 적당히 배치한 다음 씬을 저장한다. [Ctrl + S] 단축키를 누르면 간단하게 씬의 변경 내용을 저장할 수 있다.

 

그리고 프로젝트 뷰의 Scenes 폴더 아래에 지금 로드되어 있는 씬인 Sample Scene의 이름을 Scene1로 변경한다.

 

그 다음에는 이 Scene1에서 이동하게 될 새로운 씬을 생성하자.

 

 

프로젝트 뷰에 우클릭하고 [Create > Scene] 항목을 선택하면 새로운 씬을 생성할 수 있다. 새로 생성한 씬의 이름은 Scene2로 한다.

 

 

이렇게 생성한 씬 애셋을 더블 클릭하면 하이어라키에 열려있던 씬이 Scene1에서 Scene2로 바뀐다.

 

 

그리고 Scene2에는 Shpere 게임 오브젝트를 생성해서 카메라 앞 오른쪽 화면에 보이게 배치한다. 이렇게 하면 Scene1에 있다가 Scene2를 불러오면 화면 앞에 있는 게임 오브젝트의 모양이 바뀌면서 씬이 바뀌었다는 것을 명확하게 알 수 있을 것이다.

 

Scene2를 저장하고 다시 Scene1로 돌아간다.

 

SceneMover 스크립트 작성하기

 

그 다음에는 SceneMover라는 이름으로 C# 스크립트를 생성하자.

 

using UnityEngine.SceneManagement;

 

제일 먼저 스크립트의 상단에 using UnityEngine.SceneManagement; 라는 코드를 작성한다. 이 코드는 개발자가 스크립트 에디터에게 "SceneMover.cs 파일에서 UnityEngine.SceneManagement 네임스페이스에 들어있는 씬과 관련된 기능을 사용하겠다"라고 알려주는 역할을 한다.

 

참고로 네임스페이스라는 것은 C#에서 특정한 기능을 묶어두는 데 주로 사용된다.

 

여기 UnityEngine.SceneManagement 네임스페이스에서는 유니티 엔진의 씬과 관련된 기능들이 담겨있다.

 

public class SceneMover : MonoBehaviour

{

    void Update()

    {

        if(Input.GetKeyDown(KeyCode.Space))

        {

            SceneManager.LoadScene("Scene2");

        }

    }

}

 

네임스페이스 선언이 끝나면 Update 함수에서 스페이스 키를 입력을 받았을 때, SceneManager.LoadScene 함수를 호출하게 만든다. 이 함수로 다른 씬을 불러올 수 있다. 

 

매개변수에 불러오고자하는 씬의 이름이나 번호를 넣으면 된다. 우리는 Scene1에서 Scene2로 이동할 생각이기 때문에 Scene2라는 이름을 넣어주면 된다.

 

코드를 저장하고 에디터로 돌아가서 게임 오브젝트를 하나 만들고 거기에 SceneMover 컴포넌트를 추가한다.

 

 

그리고 플레이 버튼을 누르고 스페이스 키를 눌러보면 Scene2라는 씬이 빌드 세팅에 추가되지 않았거나 애셋 번들로부터 불러올 수 없어서 로드할 수 없다는 로그가 나온다.

 

유니티에서 씬을 불러오기 위해서는 씬이 저장된 애셋 번들이 있든지 아니면 씬이 빌드 세팅에 추가되어 있어야 한다.

 

빌드 세팅에 씬 추가하기

 

씬을 빌드 세팅에 추가 시켜보자.

 

 

우선 상단 메뉴바에서 [File > Build Settings...] 항목을 선택하면 빌드 세팅 창이 열린다.

 

 

창 위쪽에 비어있는 Scenes In Build 칸을 볼 수 있는데 여기에 추가된 씬들은 게임에 포함되어 빌드된다.

 

만들어둔 Scene1과 Scene2를 Scenes In Build 칸에 끌어다 놓으면 Scenes In Build 칸에 추가한 씬이 표시될 것이다.

 

빌드 세팅 창을 끄고 다시 플레이를 시킨 뒤, 스페이스 버튼을 눌러보면 Scene1에서 Scene2로 이동하면서 Cube 오브젝트가 사라지고 Sphere 오브젝트가 나타난다.

 

이게 바로 제일 기본적인 씬 이동 방법이다.

 

Additive로 씬 불러오기

 

첫 번째 방법은 씬을 완전히 이동하는 방법이었다면 이번에는 기존의 씬을 남겨둔 상태로 새로운 씬을 겹쳐서 불러오는 방법을 알아보자.

 

public class SceneMover : MonoBehaviour

{

    void Update()

    {

        if(Input.GetKeyDown(KeyCode.Space))

        {

            SceneManager.LoadScene("Scene2", LoadSceneMode.Additive);

        }

    }

}

 

매개변수 "Scene2"뒤에 콤마(,)를 찍으면 두 번째 매개변수로 넣을 수 있는 옵션이 나타나는데, 형식이 LoadSceneMode 열거형인 것을 알 수 있다.

 

LoadSceneMode 모드에는 Single과 Addtive, 두 가지가 있는데 우선 Single은 기본 옵션으로 앞에서 구현한 것처럼 씬을 불러오면 이전 씬은 완전히 사라지고 새로운 씬으로 바뀌는 옵션이다. 그리고 Additive는 앞의 씬을 남겨두고 거기에 얹어서 새로운 씬을 불러오는 것이다.

 

두 번째 매개변수에 LoadSceneMode.Additive를 넣어준 뒤 코드를 저장하고 에디터로 돌아가서 게임을 플레이 시킨 다음에 스페이스 키를 누르면 Scene1이 남아있는 상태로 Scene2가 불러와지는 것을 볼 수 있다.

 

다만 콘솔 창을 보면 로그가 굉장히 많이 발생하고 씬을 불러오기 전보다 매우 밝은 것을 알 수 있는데, 이것은 씬 안에 소리를 감지하는 Audio Listener라는 컴포넌트와 Directional Light가 두 개가 있어서 발생하는 문제이다. 그리고 메인 카메라도 중복으로 두 개가 있는 상태이다.

 

이런 문제들 때문에 Addtive로 불러올 씬에는 불필요한 카메라나 Directional Light를 만들지 않는 것이 좋다.

 

비동기 방식 씬 불러오기

 

지금까지 사용한 LoadScene 함수는 동기 방식 함수이다. 이게 무슨 의미인가하면 LoadScene 함수로 씬을 호출하면 씬을 불러오는 과정이 끝날 때까지 다른 일을 아무 것도 하지 못한다는 뜻이다.

 

이 예시처럼 씬에 고작 오브젝트가 몇 개만 있는 게임이라면 LoadScene 함수만으로 씬을 불러와도 되겠지만 최신 게임들처럼 씬 하나에 엄청나게 많은 오브젝트들이 들어있는 무거운 게임이라면 씬을 불러오는 긴 시간동안 아무 것도 하지 못하게 될 것이다.

 

다른 씬을 불러오는 도중에 팁을 보여준다든지 플레이어에게 미니 게임을 할 수 있게 한다든지 해서 씬이 불러와지는 시간에 플레이어가 지루함을 느끼지 않도록 하려면 다른 작업을 처리할 수 있어야 한다. 거기에 필요한게 비동기 방식 씬 불러오기이다.

 

public class SceneMover : MonoBehaviour

{

    void Update()

    {

        if(Input.GetKeyDown(KeyCode.Space))

        {

            StartCoroutine(LoadSceneCoroutine());

        }

    }

 

    IEnumerator LoadSceneCoroutine()

    {

        yield return SceneManager.LoadSceneAsync("Scene2");

    }

}

 

LoadSceneAsync 함수를 사용하면 함수가 씬을 불러오는 도중에 다른 작업을 처리할 수 있게 된다.

 

단, 이 함수를 제대로 사용하려면 코루틴과 함께 사용해야 한다.

 

코드를 저장하고 에디터로 돌아가서 게임을 플레이 시킨 다음 스페이스 키를 누르면 사실 눈에 띄는 변화는 없다.

 

비동기 씬 로딩이 효과가 있으려면 그만큼 불러올 씬이 무겁고 불러올게 많아야 의미가 있다.

 

비동기 씬 불러오기 방식을 응용하는 방법은 아래의 포스트에서 확인할 수 있다.

 

[로딩 화면 구현하기(UI 방식)]

 

[로딩 화면 구현하기(로딩 씬 방식)]

 

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

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

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 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

 

반응형

Programming 

코루틴(Coroutine) 다루기

 

작성 기준 버전 :: 2019.2

 

[이 포스트는 유튜브 영상을 통해서도 시청하실 수 있습니다]

 

Update 함수는 게임 오브젝트가 활성화된 상태에서 매 프레임 호출되어 수행된다. 그래서 유니티 엔진으로 게임을 만들 때는 대부분의 게임 동작을 Update 함수에서 작동하도록 구현한다.

 

그런데 Update 함수는 멈추지 않고 계속해서 동작하는 함수이기 때문에 여기서 일시적으로 돌아가는 서브 동작을 구현하는 것과 어떤 다른 동작이 처리되는 것을 기다리는 기능을 구현하기는 매우 까다롭다.

 

그리고 Update 함수에서 해당 기능을 구현하기 어렵지 않다고 하더라도, 잠시 돌아가는 기능을 Update 함수에 모두 구현하는 것은 비대한 몸집의 Update 함수를 만들어 내서 나중에 게임을 유지보수하는 것이 매우 어려워지는 결과를 낳게 된다.

 

이렇게 한 컴포넌트 내에서 Update 함수와 따로 일시적으로 돌아가는 서브 동작을 구현하거나, 어떤 다른 작업이 처리되는 것을 기다리는 기능을 구현하는데 쓰이는 것이 바로 코루틴이다.

 

Update로 구현한 공격 딜레이

 

코루틴이 필요할 법한 간단한 예시를 들기 위해서 스페이스 키를 누르면 캐릭터가 공격했다고 가정하고 딜레이를 줘서 그 시간 동안에는 다시 공격을 하지 못하게 만드는 기능을 만들어 보자.

 

public class Attacker : MonoBehaviour

{

    public bool isDelay;

    public float delayTime = 2f;

 

    float timer = 0f;

    void Update()

    {

        if (Input.GetKeyDown(KeyCode.Space))

        {

            if (!isDelay)

            {

                isDelay = true;

                Debug.Log("Attack");

            }

            else

            {

                Debug.Log("Delay");

            }

        }

 

        // 업데이트로 구현한 공격 딜레이

        if (isDelay)

        {

            timer += Time.deltaTime;

            if (timer >= delayTime)

            {

                timer = 0f;

                isDelay = false;

            }

        }

    }

}

 

위와 같이 코드를 작성하고 플레이 해보면, 처음 스페이스 키를 누르면 "Attack" 로그가 나오지만, 딜레이가 지나기 전에 다시 누르면 "Delay" 로그가 표시된다.

 

그리고 로그가 지난 이후에 스페이스 키를 눌러야 "Attack" 로그가 출력된다.

 

간단한 기능이라 구현이 그리 어렵지는 않았지만, 앞에서 이야기한 것과 같이 게임 기능이 계속해서 추가될 때마다 "공격 딜레이가 발생했을 때만" 동작하는 코드 같은 일시적 동작 코드가 Update 함수에 계속해서 늘어나면, Update 함수가 비대화되고 유지보수가 어려워진다.

 

코루틴으로 구현한 공격 딜레이

 

똑같은 기능을 이번에는 코루틴으로 구현해보자.

 

// 코루틴으로 구현한 공격 딜레이

IEnumerator CountAttackDelay()

{

    yield return new WaitForSeconds(delayTime);

    isDelay = false;

}

 

먼저 코루틴을 사용하기 위해서는 코루틴 함수를 만들어야 한다.

 

코루틴 함수를 만드는 방법은 간단하게 반환형만 IEnumerator로 만들어주면 된다.

 

그리고 yield return이란 코드를 작성해주면 된다. 이것은 코루틴에서 동작하는 제어권을 유니티에 다시 돌려준다는 뜻이다. 이 yield return 지점에 도착하면 코루틴은 반환 타입으로 정의한 만큼 코드 동작을 중지하고 제어권을 유니티에 돌려준다. 그리고 반환 타입의 조건이 충족되면 이 다음 줄부터 다시 코루틴이 동작한다.

 

코루틴이 제어권을 얼마나 양보할 지 정하는 반환 타입에는 여러 가지가 있다.

 

// 한 프레임 기다림

yield return null;

// 게임 시간으로 1초 기다림(time scale에 영향받음)

yield return new WaitForSeconds(1f);

// 실제 시간으로 1초 기다림(time scale에 영향받지 않음)

yield return new WaitForSecondsRealtime(1f);

// 다음 FixedUpdate 끝날 때까지 기다림

yield return new WaitForFixedUpdate();

// 다음 프레임의 Update와 모든 렌더링이 끝날 때까지 기다림

yield return new WaitForEndOfFrame();

 

코루틴을 모두 작성하고 나면 Update 함수를 아래와 같이 수정하면 된다.

 

void Update()

{

    if (Input.GetKeyDown(KeyCode.Space))

    {

        if (!isDelay)

        {

            isDelay = true;

            Debug.Log("Attack");

            StartCoroutine(CountAttackDelay());

        }

        else

        {

            Debug.Log("Delay");

        }

    }

 

    // 업데이트로 구현한 공격 딜레이

    //if (isDelay)

    //{

    //    timer += Time.deltaTime;

    //    if (timer >= delayTime)

    //    {

    //        timer = 0f;

    //        isDelay = false;

    //    }

    //}

}

 

코루틴 함수는 실행할 때 일반 함수처럼 호출하는 것이 아니라, StartCoroutine 함수를 이용해서 호출해야 한다.

 

코루틴으로 공격 딜레이를 구현하면 Update 함수에서 전부 구현하는 것보다 훨씬 쉽고 간단하게 똑같은 기능을 구현할 수 있다.

 

코루틴과 관련된 포스트

 

코루틴과 관련하여 추가로 확인할 만한 포스트는 아래와 같다.

 

[코루틴 내부에서 무한 루프를 사용할 때 주의점]

 

[코루틴의 호출 시점에 대한 주의점]

 

[커스텀으로 yield return 조건 만들기]

 

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

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

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 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

 

반응형

Tutorial (9) 

UGUI 기초

 

작성 기준 버전 :: 2019.2

 

이번에는 유니티 엔진의 GUI에 대해서 알아보자.

 

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

 

게임에서 플레이어에게 게임 내의 정보를 전달하는 매개체를 유저 인터페이스, 줄여서 UI라고 부른다.

 

GUI
CUI

 

그리고 이 UI는 크게 문자로 보여주고 사용자 역시 문자를 입력해서 상호작용해야하는 Character User Interface, CUI와 이미지와 문자의 혼합된 형태로 보여지고 마우스를 이용해서 상호작용할 수 있는 Graphic User Interface, GUI로 나누어진다.

 

문자나 글자로만 상호작용하는 CUI는 컴퓨터의 성능이 모자라서 그래픽으로 UI를 보여주기 힘들던 옛날 게임에서나 볼 수 있는 방식의 UI다. 최근에 와서는 옛날 게임의 감성을 되살리고자 하는 게임에서 이 CUI 방식을 일부 차용하기도 한다.

 

하지만 컴퓨터의 성능이 충분히 올라온 지금은 대부분의 게임에서 GUI를 사용한다.

 

유니티 엔진의 GUI 시스템, UGUI

 

캔버스

 

유니티 엔진에서 사용되는 GUI 시스템을 유니티 GUI 줄여서 UGUI라고 부른다. 그럼 이제 에디터에서 UGUI의 기본부터 차근차근 살펴보자.

 

 

 

하이어라키 뷰에 우클릭 해보면 생성할 수 있는 게임 오브젝트의 종류를 볼 수 있는데 그 중에 UI 항목이 있다.

 

글자를 표현하는 Text, 그림을 표현하는 Image, 클릭할 수 있는 Button 등 UI로 사용할 수 있는 여러가지 형태의 게임 오브젝트들을 볼 수 있다.

 

 

우선 UI 게임 오브젝트 중에서 Canvas를 생성해보자. Canvas를 생성하면 씬 뷰에 하얀 선으로 직사각형이 표시되는 것을 볼 수 있다.

 

Canvas는 유니티 엔진에서 UI를 배치하기 위한 영억으로 모든 UI가 화면에 표시되기 위해서는 이 Canvas 컴포넌트가 부착된 게임 오브젝트의 자식 게임 오브젝트여야 한다.

 

 

Canvas의 설정은 용도에 따라서 여러가지가 있지만, 방금 생성한 Canvas처럼 Render Mode를 [Screen Space - Overlay]로 된 것을 기본적으로 많이 사용한다. 이 설정은 게임 해상도로 표현되는 스크린 스페이스에 UI를 그리는 설정이다.

 

이 설정에서 Canvas의 해상도는 게임의 해상도를 따른다.

 

 

게임 뷰를 보면 지금 해상도가 1920x1080으로 설정되어 있는 것을 볼 수 있는데 거기에 맞춰서 Canvas의 width와 height도 1920x1080인 것을 볼 수 있다. 게임 뷰의 해상도를 바꿔보면 Canvas의 해상도 역시 자동으로 바뀌는 것을 볼 수 있다.

 

[Screen Space - Overlay]는 일반적인 평면 UI에서 주로 사용되는 설정입니다.

 

Rect Transform 컴포넌트

 

일반 게임 오브젝트의 Transform
UI 게임 오브젝트의 Rect Transform

 

일반 게임 오브젝트와 UI 게임 오브젝트의 차이점으로는 일반 게임 오브젝트의 경우에는 Transform 컴포넌트로 씬 안에서의 위치를 표현하지만, UI 게임 오브젝트들은 Rect Transform 컴포넌트로 위치를 표현한다.

 

메인 메뉴 만들어 보기

 

간단하게 게임의 메인 메뉴 형태로 UI들을 만들어 보자.

 

2D 작업 모드

 

그 전에 씬 뷰에서 이렇게 원근감이 있는 상태로는 이동도 어렵고 UI 작업이 불편하기 때문에 키보드의 숫자 '2' 버튼을 눌러서 씬 뷰를 2D 모드로 만든다. 2D 모드는 UI 작업이나 2D 게임 작업을 위한 모드로 마우스 휠을 돌려서 확대/축소하고 휠 클릭으로 화면의 위치를 이동시킬 수 있다.

 

 

캔버스에 Button과 Text, Image를 이용해서 위의 이미지와 같이 UI를 구성해보자.

 

 

중간의 꾸미는 모양이 이미지는 이 그림을 다운로드 받아서 사용하면 된다.

 

늘 강조하던 내용이지만, 하이어라키 뷰에서 게임 오브젝트의 이름이 생성된 초기 이름 그대로이면 나중에 필요한 오브젝트를 찾기가 어려워지기 때문에 버튼 이름도 적절하게 바꿔주도록 한다.

 

참고로 유니티 엔진에서 어떤 UI가 더 위에 그려지느냐 하는 우선 순위는 하이어라키 뷰에서의 순서로 결정된다. 지금 하이어라키 뷰를 보면 "Background" Image가 다른 Text나 Button보다 하이어라키 뷰에서 상단에 있는 것을 볼 수 있다. 하지만 씬 뷰나 게임 뷰에서는 제일 뒤에 그려지고 있다.

 

이 "Background" 이미지를 조금씩 아래로 내려보면 다른 버튼과 텍스트를 하이어라키 뷰의 순서에 따라서 가리기 시작하는 것을 볼 수 있다.

 

이렇게 다른 UI 보다 앞에 나오길 바라는 UI는 하이어라키 뷰에서 아래로 옮기고, 뒤에 나오길 바라는 UI는 하이어라키 뷰에서 위로 옮겨서 UI의 순서를 조정할 수 있다.

 

이번에는 간단하게 방금 만든 메인 메뉴에 기능을 추가해보도록 하자. 먼저 MainMenu라는 이름으로 C# 스크립트를 생성한다.

 

public class MainMenu : MonoBehaviour
{
    // 새 게임 버튼을 눌렀을 때 버튼이 호출할 함수
    public void OnClickNewGame()
    {
        Debug.Log("새 게임");
    }

    // 불러오기 버튼을 눌렀을 때 버튼이 호출할 함수
    public void OnClickLoad()
    {
        Debug.Log("불러오기");
    }

    // 옵션 버튼을 눌렀을 때 버튼이 호출할 함수
    public void OnClickOption()
    {
        Debug.Log("옵션");
    }

    // 종료 버튼을 눌렀을 때 버튼이 호출할 함수
    public void OnClickQuit()
    {
#if UNITY_EDITOR // 에디터에서만 실행되는 코드
        UnityEditor.EditorApplication.isPlaying = false;    // 에디터의 플레이 모드를 중단
#else   // 빌드된 게임에서 실행되는 코드
        Application.Quit(); // 실행되고 있는 게임 프로그램을 종료
#endif
    }
}

 

코드를 저장하고 에디터로 돌아와서 "Main Menu Canvas"에 MainMenu 컴포넌트를 추가해준다.

 

 

그 다음에 각 버튼의 On Click 이벤트에 [+] 버튼을 누른 뒤, MainMenu 컴포넌트를 붙인 게임 오브젝트를 할당하고 각 버튼에 맞는 함수를 호출하도록 만든다.

 

그리고 플레이 버튼을 눌러 게임을 실행하고 각 버튼을 눌러보면 함수에 넣어둔 로그가 출력되고 마지막으로 종료 버튼을 누르면 플레이 상태가 종료되는 것을 알 수 있다.

 

이렇게 유니티에서 제공하는 UI 관련 컴포넌트들을 잘 응용하면 거의 모든 UI 기능들을 구현할 수 있다.

 

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

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

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 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

 

반응형

Physics 

Collider 컴포넌트로 충돌체크하기

 

작성 기준 버전 :: 2019.2

 

[본 포스트의 내용은 유튜브 영상을 통해서도 확인할 수 있습니다]

 

게임에서는 많은 것들이 충돌한다.

 

캐릭터가 총알이나 화살에 맞기도 하고, 달리던 자동차가 건물에 부딪히기도 하며 약간은 다른 개념으로 보안용 레이저에 도둑인 캐릭터가 감지되어 경보가 울리기도 한다.

 

이런 오브젝트의 충돌들을 처리하기 위해서는 물리적인 충돌을 처리하는 방법을 알아야 한다.

 

Collider 컴포넌트

 

유니티 엔진에서 Collider라는 컴포넌트를 이용해서 충돌을 체크한다.

 

 

유니티 엔진에서 가장 대표적으로 사용되는 콜라이더로는 Box Collider, Sphere Collider, Capsule Collider가 있다.

 

 

씬 뷰에서 Collider 컴포넌트가 붙어있는 게임 오브젝트를 선택해보면 위의 이미지와 같은 초록색 선으로 표시되는 영역이 보이는데, 이것은 Collider 컴포넌트가 충돌을 감지하는 영역의 크기를 보여준다.

 

Collider 컴포넌트의 프로퍼티

 

이번에는 각 Collider 컴포넌트의 프로퍼티들을 살펴보자.

 

우선 Collider 컴포넌트들은 공통적으로 Is Trigger 프로퍼티와 Material 프로퍼티, Center 프로퍼티를 가지고 있다. 하지만 이 중에서 Is Trigger와 Material 프로퍼티는 좀 더 뒤에서 설명하도록 하고 먼저 Center 프로퍼티부터 하나씩 살펴보자.

 

Center 프로퍼티와 그 아래에 있는 프로퍼티들은 콜라이더 영역의 위치와 크기를 조절하는데 쓰인다.

 

Center

 

 

먼저 Center 프로퍼티는 게임 오브젝트의 중심으로부터 어느 위치에 콜라이더의 중심을 둘 것인가를 설정한다. 위 이미지처럼  Y 값을 바꾸면 게임 오브젝트의 중심보다 위쪽에 약간 위쪽에 콜라이더 영역이 표시된다. 단 이때의 좌표 기준을 게임 오브젝트의 로컬 좌표를 기준으로 동작한다.

 

Box Collider의 프로퍼티

 

Center 아래의 프로퍼티들은 콜라이더의 종류마다 조금씩 다르니 하나씩 설명해보도록 하겠다.

 

Size

 

 

Box Collider의 Size 프로퍼티는 콜라이더 영역의 크기를 정하는데 쓰인다. Vector3 타입이며 xyz 각 값은 게임 오브젝트의 로컬 좌표계의 축에 일치하게 동작하며, 이 사이즈의 1 단위는 1 유니티 미터를 의미한다.

 

Sphere Collier의 프로퍼티

 

Radius

 

 

Sphere Collider의 Radius 프로퍼티 역시 콜라이더 영역의 크기를 정하는데 쓰이는데, 이 값은 구체의 반지름으로 동작한다. Radius를 1로 정하면 콜라이더 영역의 지름은 2유니티 미터가 된다.

 

Capsule Collider

 

Radius

 

 

Capsule Collider의 Radius 값은 콜라이더 영역의 두께를 정하는데 쓰인다. 참고로 이 값이 Height 값보다 커지면, 콜라이더의 영역이 Sphere Collider처럼 그냥 구체 모양이 되버린다.

 

Height

 

 

Height 값은 Capsule Collider의 길이를 정하는데 쓰인다.

 

Direction

 

 

Direction 프로퍼티는 Capsule Collider의 Height를 변경했을때 길어지는 방향을 정하는 프로퍼티다. 값으로는 X-Axis, Y-Axis, Z-Axis가 있는데, 단어 그대로 로컬 좌표계의 각 축의 방향을 따른다.

 

참고로 사람이 서있을 때의 모양이 위 아래로 길쭉한 모양이 일반적이기 때문에 사람 형태의 캐릭터에 콜라이더를 부착할 때는 Capsule Collider를 주로 사용한다. 그리고 뚱뚱한 캐릭터면 Radius 값을 늘려서 Capsule Collider의 두께를 두껍게하고, 키가 큰 캐릭터면 Height 값을 키워서 길이를 늘리는 방식으로 사용된다.

 

Is Trigger

 

그럼 이제 잠시 뒤로 미뤄두었던 Is Trigger 옵션을 보자. 이 옵션은 콜라이더가 트리거(Trigger)로 동작할지, 콜리전(Collision)으로 동작할지를 정하는 프로퍼티이다.

 

콜리전은 벽이나 바닥처럼 다른 물체를 통과하지 못하게 가로막는 장애물을 뜻하고, 트리거는 마트의 도난 방지 장치처럼 물체를 통과시키되 지나가는 물체를 감지하는 것을 의미한다.

 

 

Sphere 게임 오브젝트를 Cube 게임 오브젝트 위로 떨어지게 만든 뒤 Cube 게임 오브젝트가 가진 Box Collider의 Is Trigger 옵션을 켜둔 상태와 꺼둔 상태로 각각 플레이를 해보면 Is Trigger가 꺼져있을 때는 Sphere가 Cube위에 멈추고, 켜져있을 때는 Cube를 통과해버리는 것을 볼 수 있다.

 

 

참고로, 이렇게 게임 오브젝트가 중력과 같은 물리효과를 받게 하기 위해서는 Rigidbody 컴포넌트를 붙여줘야 한다.

 

Material

 

Material 프로퍼티는 콜라이더가 충돌할 때, 어떤 재료의 물리적인 특성을 보여줄 지를 설정할 수 있는 프로퍼티이다. 이런 종류의 머티리얼을 Physics Material이라고 하는데, 프로젝트 뷰에 우클릭하고 [Create > Physics Material]을 선택해서 생성할 수 있다.

 

 

오브젝트가 고무공처럼 튀는 것을 구현하기 위해 생성한 피직스 머티리얼에 여러가지 옵션이 있지만, 지금은 간단하게 Bounciness 옵션을 0.8로 변경하고 Bounce Combine을 "Maximum"으로 설정한다.

 

 

Sphere 게임 오브젝트의 Sphere Collider에 넣고 플레이 버튼을 눌러보면 아까 전에는 Cube 위에 얌전히 멈췄던 Sphere가 마치 고무공처럼 튀어오르는 것을 볼 수 있다.

 

Collider 충돌 감지하는 스크립트 작성하기

 

이제 이 충돌을 스크립트에서 감지하는 방법을 알아보자.


유니티 엔진에서는 콜라이더끼리 충돌했을 때, 특정한 함수를 호출해준다. 그런데 앞에서 Is Trigger 프로퍼티에 대해서 설명할 때, 이 옵션의 상태에 따라서 트리거와 콜리전으로 나뉜다고 이야기했던 것을 기억할 것이다.

 

유니티 엔진은 이 트리거와 콜리전이 충돌하는 경우를 다르게 취급하고 다른 함수를 호출해준다.

 

OnCollision 이벤트

 

public class ColliTest : MonoBehaviour

{

    // Collider 컴포넌트의 is Trigger가 false인 상태로 충돌을 시작했을 때

    private void OnCollisionEnter(Collision collision)

    {

        Debug.Log("충돌 시작!");

    }

 

    // Collider 컴포넌트의 is Trigger가 false인 상태로 충돌중일 때

    private void OnCollisionStay(Collision collision)

    {

        Debug.Log("충돌 중!");

    }

 

    // Collider 컴포넌트의 is Trigger가 false인 상태로 충돌이 끝났을 때

    private void OnCollisionExit(Collision collision)

    {

        Debug.Log("충돌 끝!");

    }

}

 

콜리전끼리 충돌했을 때는 OnCollision 계열의 이벤트가 호출된다. 충돌 과정은 3단계로 나눠서 호출되는데, 충돌이 시작할 때는 Enter, 충돌이 지속되는 동안에는 Stay, 충돌이 끝나는 순간에는 Exit가 호출된다.

 

private void OnCollisionEnter(Collision collision)

{

    // 이 컴포넌트가 부착된 게임 오브젝트의 콜라이더와 충돌한 게임 오브젝트 가져오기

    var obj = collision.gameObject;

    // 특정 컴포넌트 가져오기

    var component = collision.gameObject.GetComponent<SomeComponent>();

    // 콜라이더 가져오기

    var collider = collision.collider;

    Debug.Log("충돌 시작!");

}

 

이 콜리전과 충돌한 게임 오브젝트를 가져오기 위해서는 매개변수로 전달되는 collision에서 .gameObject 프로퍼티를 호출하면 된다. 그리고 .GetComponent 함수를 사용하면 이 게임 오브젝트에 부착된 컴포넌트를 가져올 수도 있다.

 

OnTrigger 이벤트

 

public class ColliTest : MonoBehaviour

{

    // Collider 컴포넌트의 is Trigger가 true인 상태로 충돌을 시작했을 때

    private void OnTriggerEnter(Collider other)

    {

        Debug.Log(other.name + "감지 시작!");

    }

 

    // Collider 컴포넌트의 is Trigger가 true인 상태로 충돌중일 때

    private void OnTriggerStay(Collider other)

    {

        Debug.Log(other.name + "감지 중!");

    }

 

    // Collider 컴포넌트의 is Trigger가 true인 상태로 충돌이 끝났을 때

    private void OnTriggerExit(Collider other)

    {

        Debug.Log(other.name + "감지 끝!");

    }

}

 

OnTrigger 이벤트 역시 Enter, Stay, Exit의 과정을 거친다. 이 OnTrigger 이벤트는 콜리전이 트리거에 닿았을 때, 콜리전과 트리거 양 쪽에서 모두 호출될 수 있고, 트리거와 트리거가 닿았을 때도 호출된다.

 

private void OnTriggerEnter(Collider other)

{

    // 이 컴포넌트가 부착된 게임 오브젝트의 콜라이더와 충돌한 게임 오브젝트 가져오기

    var obj = other.gameObject;

    // 특정 컴포넌트 가져오기

    var component = other.gameObject.GetComponent<SomeComponent>();

    Debug.Log(other.name + "감지 시작!");

}

 

OnTrigger 이벤트에서도 OnCollision 이벤트에서처럼 매개변수로 전달받은 Collider 타입의 other 변수를 통해서 감지한 게임 오브젝트와 거기에 부착된 컴포넌트를 가지고 올 수 있다.

 

기초적인 Collider의 사용법을 이해했다면 링크된 유튜브 영상을 통해서 이 Collider 컴포넌트의 기능을 응용해서 간단한 게임 기능을 구현하는 방법을 확인할 수 있다.

 

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

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

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 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

 

반응형

+ Recent posts