Programming 

스크립트로 게임 오브젝트 생성하고 파괴하기

 

작성 기준 버전 :: 2019.2

 

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

 

 

씬에 새로운 게임 오브젝트를 생성하는 제일 기본적인 방법은 하이어라키 뷰에 우클릭해서 생성하고자 하는 게임 오브젝트를 선택하는 것이었다. 하지만 이렇게 에디터의 하이어라키 뷰에서 생성한 게임 오브젝트는 다른 컴포넌트나 스크립트의 개입 없이는 파괴되지 않기 때문에, 정적인 오브젝트이다.

 

반대로 스크립트의 개입으로 게임 플레이 도중에 생성되고 파괴되는 것을 동적으로 오브젝트를 생성하거나 파괴한다고 한다.

 

그럼 이제부터 이렇게 스크립트를 이용해서 게임 플레이 도중에 게임 오브젝트를 생성하고 파괴하는 방법을 알아보도록 하자.

 

게임 오브젝트 생성하기

 

public class GameObjectCreator : MonoBehaviour

{

    void Start()

    {

        new GameObject();

    }

}

 

게임 오브젝트를 생성하기 위해서는 위의 예시 코드와 같이 new GameObject()라는 코드를 작성하면 된다.

 

이 코드는 C#에서는 GameObject라는 클래스의 객체를 메모리에 생성하는 코드이지만, 유니티 엔진에서는 GameObject 클래스의 객체를 메모리에 생성하면서 씬에 실제 게임 오브젝트 역시 생성하는 기능을 한다.

 

 

이대로 코드를 저장하고 에디터로 돌아가서 하이어라키 뷰에서 게임 오브젝트를 하나 생성하고, 방금 만든 GameObjectCreator 컴포넌트를 부착해준 뒤, 플레이 버튼을 보면 "New Game Object"라는 이름으로 게임이 시작되는 시점에는 씬에 없던 새로운 게임 오브젝트가 동적으로 생성된 것을 볼 수 있다.

 

하지만 이렇게 생성된 게임 오브젝트는 말 그대로 '빈' 게임 오브젝트이다. 게임에서 아무것도 없는 빈 게임 오브젝트가 할 수 있는 역할은 아마 없을 것이다. 빈 게임 오브젝트에 새로운 역할을 부여해주려면 새로운 컴포넌트를 부착해야 한다.

 

그러니 앞 단계에 이어서 게임 오브젝트에 스크립트로 컴포넌트를 붙이는 방법을 알아보자.

 

프로젝트 뷰에 우클릭해서 TestComponent라는 이름으로 C# 스크립트를 생성한다. 그리고 GameObjectCreator 스크립트 파일에서 아래와 같이:

 

public class GameObjectCreator : MonoBehaviour

{

    void Start()

    {

        var newObj = new GameObject().AddComponent<TestComponent>();        newObj.name = "Test Component Game Object";

    }

}

 

.AddComponent 함수를 사용하면 비어있는 게임 오브젝트에 스크립트로 방금 만든 TestComponent 컴포넌트를 부착할 수 있다. 

 

그리고 .name 프로퍼티를 이용하면 게임 오브젝트의 이름을 바꿀 수 있다. 이렇게 생성한 게임 오브젝트의 이름을 적절하게 바꿔주면 나중에 에디터에서 작업할 때 찾고자 하는 게임 오브젝트를 빠르게 찾을 수 있게 된다.

 

 

코드를 저장하고 에디터로 돌아가서 실행해보면 게임이 플레이되면 아까처럼 새로운 게임 오브젝트가 생성되는데 새 게임 오브젝트의 이름이 "New Game Object"가 아닌 "Test Component Game Object"인 것을 볼 수 있다. 그리고 이 "Test Component Game Object"를 하이어라키 뷰에서 클릭해보면 이렇게 TestComponent가 부착되어 있는 것을 볼 수 있다.

 

게임 오브젝트 파괴하기

 

게임 오브젝트를 생성하기만 하고 생성된 게임 오브젝트를 적절하게 제거하지 않으면 게임이 사용하는 메모리가 점점 늘어나면서 게임이 점점 느려지고 마지막엔 결국 게임이 멈춰버릴 수도 있다.

 

그럼 이제 생성된 게임 오브젝트를 스크립트로 파괴하는 방법을 알아보자.

 

이번에는 TestComponent 스크립트 파일을 연다.

 

public class TestComponent : MonoBehaviour

{

    void Start()

    {

        Destroy(gameObject);

    }

 

    private void OnDestroy()    {        Debug.Log(name + "가 파괴됨!");

 

    }

}

 

Start 함수에서 Destory 함수를 호출하고 매개변수로 파괴하고자 하는 게임 오브젝트를 넣어주면 된다. 우리는 TestComponent가 부착된 게임 오브젝트가 파괴되기를 원하기 때문에 gameObject 프로퍼티를 넣어준다.

 

그리고 OnDestroy 함수를 만들고 게임 오브젝트가 파괴될 때, 파괴되는 게임 오브젝트의 이름과 함께 파괴되었다는 로그를 남겨주는 코드를 작성한다.

 

 

코드를 저장하고 에디터로 돌아가서 플레이해보면 게임이 시작되자마자 Test Component Game Object가 파괴되었다는 로그만 남기고 사라져버린다.

 

Destroy(gameObject, 5f);

 

게임 오브젝트가 생성되자마자 바로 파괴되는 것이 아니라 일정한 시간이 지난 뒤에 파괴되는 것을 원한다면, Destroy 함수의 두 번째 매개변수에 실수형 매개변수를 넣어주면 된다.

 

유니티 스크립트 작업의 기반이 되는 C# 프로그래밍에는 함수 오버로딩이라고 하는 기능을 제공하는데 이것은 똑같은 이름의 함수라도 입력하는 매개변수에 따라서 비슷하지만 다른 동작을 하도록 구현할 수 있도록 만들어준다.

 

gameObject만 매개변수로 넣었을 때의 Destory 함수는 입력받은 게임 오브젝트를 바로 파괴하지만, 두 번째 매개변수로 실수형 숫자를 같이 넣어주면, 넣어준 숫자만큼의 시간이 지난 후에 입력받은 gameObject를 파괴하는 식으로 조금 다르게 동작한다.

 

참고로 두 번째 매개변수의 시간은 초 단위로 동작한다. 그러니까 이 TestComponent가 부착된 게임 오브젝트는 생성되고나서 5초가 지나면 파괴된다.

 

코드를 저장하고 에디터로 돌아가서 플레이 버튼을 눌러보면 게임 오브젝트가 생성되고 약 5초가 지난 뒤 파괴되는 것을 확인할 수 있다.

 

이런 식으로 스크립트로 게임 오브젝트를 생성하고 원하는 시점에 파괴되게 만들 수 있다.

 

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

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

 

에셋스토어

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

 

반응형

Animation 

애니메이터 컨트롤러의 파라미터 조절하기

 

작성 기준 버전 :: 2019.2

 

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

 

이번 섹션에서는 애니메이터 컨트롤러의 파라미터를 스크립트에서 조절하는 방법을 알아보자.

 

그 이전에 유니티 애니메이션에 대한 기초적인 지식이 필요하다면 해당 링크를 통해서 확인할 수 있다.

 

애니메이션의 기초에 대해서 설명하는 튜토리얼을 통해서 애니메이터 파라미터로 애니메이터 컨트롤러의 흐름을 조절할 수 있다는 것을 이야기했었다.

 

우선 애니메이터 컨트롤러의 파라미터와 트랜지션에 대해서 간단하게 복습해보자.

 

애니메이터 컨트롤러의 파라미터와 트랜지션

 

유니티 애니메이션에 대한 기초를 다루었던 글에서 이야기 했듯이 애니메이터 컨트롤러의 트랜지션은 스테이트와 스테이트 사이를 이어주고, 어느 방향으로 애니메이션이 흘러갈지 결졍하는 것이고, 파라미터는 이 트랜지션이 실행될 조건을 결정하는 변수이다.

 

애니메이터 컨트롤러

 

 

우선 간단한 애니메이터 컨트롤러를 만들기 위해서 씬에 게임 오브젝트를 하나 생성해보자.

 

 

그리고 추가한 게임 오브젝트에 애니메이터 컴포넌트를 부착해준다.

 

 

그 다음 프로젝트 뷰에 우클릭해서 [Create > Animator Controller] 항목을 선택하여 새 애니메이터 컨트롤러를 생성해서 게임 오브젝트에 부착된 Animator 컴포넌트의 Controller 프로퍼티에 할당해주면 된다.

 

 

Controller 프로퍼티를 할당한 다음에는 게임 오브젝트를 선택한 상태에서 상단 메뉴바의 [Window > Animation > Animator] 항목을 선택해서 애니메이터 뷰를 열어보면 비어있는 게임 오브젝트의 애니메이터 컨트롤러를 볼 수 있다.

 

애니메이션 파라미터

 

 

애니메이터 뷰를 열었다면 뷰 제목 바로 아래 있는 파라미터 탭을 클릭한 다음, 플러스 모양의 버튼을 눌러서 위 이미지처럼 각 파라미터들을 하나씩 만들어 보자.

 

이 파라미터들은 앞서 언급했듯이 한 애니메이션에서 다른 애니메이션으로 전환되는 트랜지션이 실행되는 조건의 역할을 한다. 파라미터의 종류는 여기서 볼 수 있듯이 Float은 소수점을 나타내는 실수, Int는 정수, Bool은 참/거짓을 표현하는 논리 변수, Trigget는 신호가 들어오면 트랜지션을 통과시킨 다음에 자동으로 꺼지는 타입의 변수다.

 

애니메이터 트랜지션

 

 

각 파라미터 타입을 테스트하기 위해서 위 이미지와 같이 애니메이터 컨트롤러를 세팅해보자. 스테이트를 모두 만들고 트랜지션을 연결했다면, 트랜지션의 조건을 설정할 차례다.

 

Float in

 

 

먼저 Idle 스테이트에서 Float 스테이트로 들어가는 트랜지션의 조건이다. 트랜지션 화살표를 클릭하면 인스펙터 뷰에서 해당 트랜지션을 수정할 수 있는데, 컨디션(Conditions)의 플러스 버튼을 누르면 이 트랜지션이 동작할 조건을 추가할 수 있다. 우선 조건으로 사용될 변수는 New Float으로 하고 3보다 클 때(Greater), 동작하도록 설정했다.

 

Float out

 

 

그 다음은 Float에서 Idle로 빠져나오는 트랜지션의 조건이다. 컨디션을 추가한 다음, 원래 Greater라고 적혀있는 드롭다운 메뉴를 눌러보면 Less가 있는 것을 볼 수 있다. Less는 정해진 숫자보다 작을 때를 뜻한다. 즉, 3보다 작을 때 Float에서 빠져나가서 Idle로 향하게 된다.

 

참고로, 여기에 왜 같다를 의미하는 Equal이 없는지 궁금할 수도 있다. 이것은 컴퓨터의 고질적인 부동소수점 오차라는 문제 때문이다. 예를 들어 현실적으로는 0.0001을 만 번 더하면 정확히 1이 되어야 하는데, 컴퓨터는 소수점 계산에 문제가 있어서 정확히 1이 되지 않고 1.00001이나 다른 숫자가 되는 경우가 종종 발생한다. 이 때문에 소수점 계산에 정확히 같다라는 것을 사용하기 어렵기 때문에 Equal이 빠져있는 것이다.

 

Int in

 

 

Idle에서 Int로 들어가는 조건을 설정해보자. 컨디션을 추가한 다음 New Float이라는 변수 이름이 적혀있는 드롭다운 메뉴를 선택하면 애니메이터 컨트롤러에 만들어져 있는 파라미터를 찾아서 선택할 수 있다. 그리고 Int형 파라미터는 Float과 다르게 "같다(Equal)"라는 조건을 사용할 수 있다. 파라미터의 값이 1과 같을 때 Idle에서 Int로 들어가게 설정해보자.

 

Int out

 

 

New Int의 값이 1이 아닐 때, Int에서 Idle로 빠져나오게 만든다.

 

Bool in

 

 

Idle에서 Bool로 들어가는 조건은 New Bool이 true일 때로 설정한다. Bool형 파라미터는 true 혹은 false만 설정할 수 있다.

 

Bool out

 

 

New Bool이 false가 되면 Bool에서 Idle로 빠져나오게 만들어 준다.

 

Trigger in

 

 

Idle에서 Trigger로 들어가는 조건은 New Trigger로 넣어준다. 트리거 형식은 아까 이야기했듯이 트리거가 호출되는 순간에 한 번 켜지고, 트리거 조건이 있는 트랜지션을 통과하면 자동으로 꺼지기 때문에 별다른 세부 조건이 없다.

 

Trigger out

 

 

Trigger에서 Idle로 빠져나오는 조건은 따로 만들지 않는다. 참고로 트랜지션을 선택한 다음 볼 수 있는 인스펙터 뷰의 내용 중에서 Has Exit Timer이라는 옵션이 있는데 이 옵션이 켜져있으면 트랜지션의 조건 만족되더라도 지금 실행하는 애니메이션을 끝까지 재생하기 전에는 다음 스테이트로 넘어가지 않는다. 반대로 이 옵션을 꺼두면 지금 실행되는 애니메이션이 아직 재생이 끝나지 않았더라도 트랜지션의 조건이 만족되면 그 애니메이션을 끝내고 곧바로 다음 스테이트로 넘어가게 된다.

 

테스트 해보기

 

애니메이터 컨트롤러 설정이 모두 끝났다면 이제 플레이 버튼을 누르고 게임을 실행해보자.

 

 

그리고 애니메이터 뷰에서 파라미터의 값을 하나씩 변경하면서 테스트 해보자. 파라미터의 값에 따라서 애니메이션의 흐름이 통제되는 것을 확인할 수 있다.

 

스크립트로 애니메이터 파라미터 변경하기

 

다른 섹션에서 트랜스폼 컴포넌트를 다루면서도 이야기 했지만, 이렇게 에디터에서 값을 바꾸는 방법은 실제 게임 내에선 사용할 수 없으며, 게임에서 이 애니메이터 파라미터의 값을 바꿔서 애니메이션의 흐름을 통제하기 위해서는 스크립트에서 이 애니메이터 컨트롤러의 파라미터를 바꿀 수 있어야 한다.

 

public class AnimatorParameterPractice : MonoBehaviour

{

    private Animator animator;

 

    private void Awake()

    {

        animator = GetComponent<Animator>();

    }

}

 

우선 AnimatorParameterPractice라는 이름의 C# 스크립트를 하나 생성하고, animator 멤버 변수를 하나 만든 다음, 게임이 시작되자마자 애니메이터 컨트롤러를 가져올 수 있게 Awake() 함수에서 GetComponent() 함수를 사용해서 게임 오브젝트에 부착된 Animator 컴포넌트를 가져오자.

 

참고로 GetComponent() 함수를 사용하면 지금 이 컴포넌트가 부착되어 있는 게임 오브젝트에 부착된 다른 컴포넌트를 가져올 수 있다. 지금은 Animator 컴포넌트를 가져오기 위해서 뾰족 괄호 안에<> Animator 컴포넌트 클래스 이름을 넣었습니다.

 

애니메이터의 각 파라미터 값 변경 함수

 

애니메이터 클래스 내부에는 애니메이터 안에 설정한 파라미터 값을 변경할 수 있는 함수를 제공한다.

 

Float형 변경하기

 

animator.SetFloat("New Float", 3.1f);

 

애니메이터의 Float형 파라미터의 값을 변경하려면 SetFloat() 함수를 사용하면 된다. 첫 번째 매개변수로 변경하고자 하는 파라미터의 이름을 넣고, 두 번째 매개변수에 값을 넣어준다.

 

Int형 파라미터 값 변경하기

 

animator.SetInteger("New Int"1);

 

Int형 파라미터의 값은 SetInteger() 함수로 변경할 수 있다.

 

Bool형 파라미터 값 변경하기

 

animator.SetBool("New Bool", true);

 

Bool형 파라미터 값은 SetBool() 함수로 변경할 수 있다.

 

Trigger형 파라미터 신호 주기

 

animator.SetTrigger("New Trigger");

 

Trigger형 파라미터는 SetTrigger() 함수를 사용하면 해당 파라미터의 신호가 켜진다.

 

키보드를 누르면 각 파라미터 값 바뀌게 하기

 

void Update()

{

    if (Input.GetKeyDown(KeyCode.F))

    {

        animator.SetFloat("New Float"3.1f);

    }

 

    if (Input.GetKeyUp(KeyCode.F))

    {

        animator.SetFloat("New Float"2.9f);

    }

 

    if (Input.GetKeyDown(KeyCode.I))

    {

        

animator.SetInteger("New Int"

1);

    }

 

    if (Input.GetKeyUp(KeyCode.I))

    {

        

animator.SetInteger("New Int"

, 0);

    }

 

    if (Input.GetKeyDown(KeyCode.B))

    {

        

animator.SetBool("New Bool"

true);

    }

 

    if (Input.GetKeyUp(KeyCode.B))

    {

        animator.SetBool("New Bool"

false

);

    }

 

    if (Input.GetKeyDown(KeyCode.T))

    {

        

animator.SetTrigger("New Trigger");

    }

}

 

AnimatorParameterPractice 클래스의 업데이트 함수에 위와 같은 코드를 작성해서 키보드를 눌렀다 뗄 때, 각 파라미터 값이 바뀌도록 해보자.

 

 

코드를 모두 작성했으면 코드를 저장하고 에디터로 돌아가서 애니메이터 컨트롤러가 붙어있는 게임 오브젝트에 AnimatorParameterPractice 컴포넌트를 부착한 뒤, 애니메이터 뷰를 켜고 플레이 버튼을 누른다. 

 

그리고 게임이 실행되면 지정한 키인 F, I, B T를 눌러보면 키보드를 눌렀다 뗄 때마다 파라미터의 값이 바뀌고 그에 따라 애니메이션의 흐름이 통제되는 것을 볼 수 있다.

 

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

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

 

에셋스토어

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

 

반응형

Transform 

게임 오브젝트의 공간 정보

 

작성 기준 버전 :: 2019.2

 

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

 

이번 섹션에서는 게임 오브젝트의 공간 정보를 관리하는 트랜스폼 컴포넌트에 대해서 알아보자.

 

본 내용에 앞서 벡터좌표계, 게임 오브젝트와 컴포넌트에 관한 지식이 필요하다면 링크된 글들을 읽어보면 도움이 된다.

 

트랜스폼 컴포넌트(Transform Component)

 

 

[그림 1]

 

우선 트랜스폼 컴포넌트는 게임 오브젝트에 필수로 부착되는 컴포넌트로, 인스펙터 뷰에서 보면 [그림 1]과 같이 Vector3 형식의 포지션(Position), 로테이션(Rotation), 스케일(Scale) 프로퍼티를 사용자에게 공개하고 있다.

 

 

프로퍼티의 이름에 맞게 포지션 프로퍼티는 게임 오브젝트의 위치 정보를 수정할 수 있다.

 

 

로테이션 프로퍼티는 회전 정보를 가지고 이를 수정할 수 있다.

 

 

스케일 프로퍼티는 크기 정보에 관여한다.

 

이렇게 인스펙터 뷰에서 보이는 트랜스폼 컴포넌트로 씬 안에 있는 게임 오브젝트의 위치를 옮기거나, 회전시키고, 그 크기를 바꿀 수 있다. 하지만 인스펙터 뷰에서 트랜스폼 컴포넌트의 내용을 변경하는 것은 게임 중에는 불가능한 일로 고정된 건물이나 물건같은 오브젝트에나 사용할 수 있는 방법이다.

 

플레이어, 몬스터와 같은 캐릭터, 총알, 화살 같은 투사체, 말, 자동차 같은 탈 것처럼 게임 안에서 플레이어의 조작이나 AI의 조작을 따라서 움직일 게임 오브젝트들은 스크립트를 이용해서 이동시켜야 한다.

 

 

스크립트로 트랜스폼 컴포넌트 다루기

 

트랜스폼 컴포넌트 접근하기

 

public class TransformController : MonoBehaviour

{

    void Start()

    {

        Transform myTransformComponent = transform;

    }

}

 

커스텀 컴포넌트가 부착된 게임 오브젝트의 트랜스폼 컴포넌트를 가져오기 위해서는 모노비헤이비어(MonoBehaviour) 클래스를 통해서 상속받은 transform 프로퍼티를 호출하면 된다.

 

 

transform 프로퍼티를 어디서 상속받는지 궁금할 수도 있다. 그럴 때는 트랜스폼 컨트롤러 클래스가 상속받는 모노비헤이비어 클래스를 클릭하고 F12키를 눌러서 모노비헤이비어 클래스 파일로 이동한 다음, 같은 과정을 컴포넌트(Component) 클래스가 나올 때까지 반복하면 된다. 그러면 컴포넌트 클래스에 정의된 transform 프로퍼티를 확인할 수 있다.

 

위치 이동시키기

 

position으로 직접 이동시키기

 

그럼 제일 먼저 트랜스폼 컴포넌트를 이용해서 게임 오브젝트를 이동시켜보자.

 

public void MovePosition(Vector3 newPosition)

{

    transform.position = newPosition;

}

 

게임 오브젝트의 위치 정보를 다루는 포지션 프로퍼티에 접근하기 위해서는 위의 예시 코드와 같이 transform.position을 이용하면 된다.

 

float timer = 0f;

void Update()

{

    timer += Time.deltaTime;

    MovePosition(new Vector3(0f, Mathf.Cos(timer), 0f));

}

 

방금 만든 Update() 함수에서 MovePosition() 함수를 호출한다. 게임 오브젝트의 위치를 코사인 그래프에 따라서 위 아래로 움직이도록 만들어진 코드이다.

 

 

이 코드를 게임 오브젝트에 부착하고 에디터에서 플레이 시켜보면 코사인 그래프의 높이에 따라 게임 오브젝트가 위 아래로 천천히 움직이는 것을 볼 수 있다.

 

Translate() 함수로 이동시키기

 

위에서 position으로 이동시키기는 말그대로 트랜스폼 컴포넌트의 position 프로퍼티에 직접 위치를 넣어서 이동시키는 방법이다.

 

float timer = 0f;

void Update()

{

    timer += Time.deltaTime;

    MovePositionUseTranslate(new Vector3(0f, Mathf.Cos(timer), 0f));

}

 

public void MovePositionUseTranslate(Vector3 moveDirection)

{

    transform.Translate(moveDirection);

}

 

Translate() 함수는 position 프로퍼티에 직접 위치를 집어넣어서 이동시키는 것과는 달리 게임 오브젝트가 이동하고자 하는 방향과 속력인 벡터를 매개변수로 받아 그 벡터의 방향과 길이만큼 게임 오브젝트를 이동시키는 함수이다.

 

 

위 코드를 저장하고 플레이해보면 position을 이용한 오브젝트 이동에서는 1 ~ -1 사이에서만 움직이던 것과는 달리 Translate() 함수를 이용한 이동에서는 훨씬 큰 폭으로 움직이는 것을 볼 수 있다. 이것은 이동 방향 벡터가 코사인 그래프를 따라서 바뀌는 동안에 0보다 값이 커지면 위로, 0보다 작아지면 아래로 움직이기 때문이다.

 

position 이동과 Translate() 이동의 비교

 

public class TranslateMover : TransformController

{

    void Update()

    {

        MovePositionUseTranslate(new Vector3(0f, 0.1f, 0f));

    }

}

 

public class PositionMover :

 TransformController

{

    void Update()

    {

              MovePosition(new Vector3(0f, 0.1f, 0f));

    }

}

 

두 이동 방식을 비교하기 위해서 TransformController를 상속받는 두 클래스를 만들어보았다. PositionMover 클래스는 매 프레임 MovePosition() 함수를 호출해서 (0, 0.1, 0) 벡터를 넣어주고, TranslateMover 클래스는 매 프레임 MovePositionUseTranslate() 함수를 호출해서 역시 같은 벡터를 넣어주고 있다.

 

 

에디터로 돌아가서 게임 오브젝트 두 개를 만들고 이 두 컴포넌트를 각각 붙여주고 플레이하면 TranslateMover 컴포넌트를 붙인 게임 오브젝트만 저 멀리 올라가버리는 것을 볼 수 있다. 하지만 PositionMover 컴포넌트를 붙인 게임 오브젝트는 시작되는 순간에 (0, 0.1, 0) 좌표로만 이동한 다음에 그대로 움직이지 않는 것을 보면, 두 방법의 차이를 이해할 수 있다.

 

 

 

 

 

회전시키기

 

rotation으로 회전시키기

 

void Start()

{

    transform.rotation = new Quaternion();

}

 

게임 오브젝트를 회전시키기 위해서는 transform.rotation 프로퍼티를 사용하면 된다. 다만, 인스펙터 뷰에서 공개된 Rotation 프로퍼티가 Vector3 형식인 것과 달리 스크립트에서는 쿼터니언(Quaternion) 구조체를 사용한다.

 

Quaternion rotation = new Quaternion();

 

rotation.w

rotation.x

rotation.y

rotation.z

 

쿼터니언 구조체는 벡터와는 다른 사원수라는 체계를 사용해서 오브젝트의 회전을 표현한다. 이 사원수라는 체계는 상당히 난해한 체계이기 때문에 유니티의 공식 문서에서는 사원수에 대한 지식을 충분히 가지고 있지 않다면 쿼터니언을 직접 수정하지 않도록 권장하고 있다.

 

public void RotateRotation(Vector3 newRotation)

{

    transform.rotation = Quaternion.Euler(newRotation);

}

 

public void RotateRotation(Vector3 newRotation)

{

    transform.Rotate(newRotation);

}

 

그럼 사원수를 제대로 알지 못하면 게임 오브젝트를 회전시키지 못하게 되는가? 그렇지는 않다. 인스펙터 뷰에서처럼 3차원 벡터를 이용해서 회전을 다루는 방법을 오일러 각 체계(Euler angle system)라고 부른다. 오일러 각 체계 이용하면 xyz 각 축을 기준으로 오브젝트가 얼마나 회전한 상태인지 직관적으로 알 수 있다. 그래서 쿼터니언 구조체에는 이 오일러 각 체계의 회전을 사원수 체계의 회전으로 전환해주는 Euler() 함수가 포함되어 있다. 이 함수를 이용하면 Vector3로 표현된 각을 Quaternion으로 변환할 수 있다.

 

그리고 회전 역시 이동과 마찬가지로 rotation 프로퍼티를 직접 수정하는 방법과 Rotate() 함수를 사용하는 방법 두 가지가 있다. 그리고 그 차이점 역시 이동시키기에서의 position 직접 이동과 Translate() 함수를 이용한 이동과 비슷하다.

 

float timer = 0f;

void Update()

{

    timer += Time.deltaTime;

    RotateRotation(new Vector3(0f, ((Mathf.Cos(timer) + 1f) * 0.5f) * 360f, 0f));

}

 

 

RotateRotation() 함수를 업데이트에서 호출하도록 코드를 작성하고 플레이시켜보면 게임 오브젝트가 회전하는 것을 볼 수 있다.

 

transform.forward로 바라보는 방향 정하기

 

float timer = 0f;

void Update()

{

    timer += Time.deltaTime;

    ForwardControl(new Vector3(Mathf.Cos(timer), 0f, Mathf.Sin(timer)));

}

 

public void ForwardControl(Vector3 newForward)

{

    transform.forward = newForward;

}

 

게임 오브젝트를 회전시키는 다른 방법으로는 transform.forward 프로퍼티를 이용하면 게임 오브젝트의 forward, 즉 정면을 설정해서 특정한 방향을 바라보게 할 수 있다. 프로퍼티로 가져올 수 있는 방향으로는 forward, up, right가 있다. 

 

LookAt() 함수로 원하는 위치를 바라보게 하기

 

float timer = 0f;

void Update()

{

    timer += Time.deltaTime;

    ForwardControl(new Vector3(Mathf.Cos(timer), 0f, Mathf.Sin(timer)));

}

 

public void LookObject(Vector3 pos)

{

    transform.LookAt(pos);

}

 

transform 컴포넌트에 있는 LookAt() 함수를 사용하면 원하는 지점을 바라보게 할 수 있다. LookAt() 함수의 매개변수로 Vector3 뿐만 아니라 다른 게임 오브젝트의 트랜스폼 컴포넌트를 넣어서 다른 게임 오브젝트를 따라가며 바라보게 할 수도 있다.

 

 

크기 조절하기

 

float timer = 0f;

void Update()

{

    timer += Time.deltaTime;

    float scale = Mathf.Cos(timer) + 2f;

    Scaling(new Vector3(scale, scale, scale));

}

 

public void Scaling(Vector3 scale)

{

    transform.localScale = scale;

}

 

게임 오브젝트의 크기 조절은 transform.localScale 프로퍼티를 통해서 할 수 있다.

 

 

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

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

 

에셋스토어

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

 

반응형

Vector 

좌표와 속도를 다루기 위한 도구

 

작성 기준 버전 :: 2019.2

 

[유튜브 영상에서도 본 포스트의 내용을 시청하실 수 있습니다.]

 

이번 섹션에서는 유니티 엔진의 벡터에 대해서 알아보자.

 

게임 속에 존재하는 모든 오브젝트들은 어느 위치에 존재하거나, 어딘가를 향해서 이동한다. 아무것도 움직이지 않는 게임은 거의 존재하지 않는다. 그렇기 때문에 이렇게 오브젝트의 위치와 이동 등에 대해서 다루는 도구가 필요한데, 그것을 위한 도구가 바로 벡터이다.

 

벡터에 관한 이번 포스트를 읽기 전에 유니티의 좌표계에 대한 글을 읽어보는 것도 좋다.

 

벡터(Vector)

 

벡터에 대해서 수학이나 물리학에서는 여러 복잡한 정의가 존재하는데 간단하게 요약하자면 특정한 공간에서의 방향과 크기를 표현하는 도구로서 주로 화살표로 표시되는 개념이다.

 

[그림 1]

 

[그림 1]을 예시로 들면 오른쪽으로 뻗어나가는 X축과 위쪽으로 뻗어나가는 Y축, 두 개의 축으로 구성된 2차원 평면 공간이 있고, (2, 2) 위치를 가리키고 있는 V1 벡터와 (-1, -2) 위치를 가리키고 있는 V2 벡터, 두 개의 벡터가 2차원 공간 속에 존재하는 것을 볼 수 있다.

 

즉, 여기서는 2차원 평면이 "특정한 공간"이며, 벡터는 그 공간 안에서 방향과 크기를 표현하는 도구라고 말했듯이, 벡터를 표시한 화살표를 보는 것만으로도 이 벡터가 어느 방향을 가리키고 있고 얼마만큼의 길이를 가지는지 알 수 있다.

 

그리고 이 "특정한 공간"은 몇 차원이든 가능하지만 대부분은 사람이 쉽게 인지할 수 있는 2차원 혹은 3차원으로 정의된다. 유니티에서도 2차원과 3차원의 벡터만 사용한다.

 

벡터의 활용

 

벡터는 방향과 크기를 표현하는 도구라고 이야기했는데, 이것을 이용해 여러 가지 용도로 활용된다.

 

첫 번째 활용법은 방향이다. [그림 1]과 같이 평면에 벡터가 표시하는 좌표까지 화살표를 그리는 것으로 방향을 쉽게 알 수 있다.

 

[그림 2]

 

두 번째 활용법은 속도이다. V1과 V2가 [그림 1]에서는 서로 다른 방향을 가리키고 있는데, [그림 2]와 같이 두 벡터를 같은 방향으로 놓고 보면, V1이 V2보다 긴 것을 확인할 수 있다. 1초 동안 각 벡터의 길이만큼 이동한다고 가정하면, 당연히 같은 시간동안 V1만큼 이동한 것이 V2만큼 이동한 것보다 멀리 이동할 수 있고, 벡터의 방향 자체가 이동 방향의 의미를 가지기 때문에, 이동하고자하는 방향과 속력, 즉, 속도의 개념으로 활용되는 것이다.

 

세 번째 활용법은 좌표이다. [그림 1]에서 X축과 Y축이 교차하는 지점을 공간의 중심이라고 가정했을 때, V1 위치에 어떤 오브젝트가 있다면, 그 오브젝트는 공간의 중심으로부터 (2, 2)의 위치에 있다고 말할 수 있다.

 

벡터의 계산

 

벡터에 대한 여러가지 계산들이 존재하는데 이러한 계산 방법들을 잘 활용하면 게임의 기능을 구현하는데 유용하게 사용할 수 있다.

 

벡터의 덧셈과 뺄셈

 

두 개의 벡터는 서로 더하거나 뺄 수 있다.

 

[그림 3]

 

우선 벡터의 덧셈을 살펴보자. [그림 3]을 보면 (1, 2)의 V1과 (2, 1)의 V2를 더하면 (3, 3)의 V3가 나오는 것을 볼수 있다. V1 지점에서 V2 만큼 이동했다고 여기면 된다.

 

[그림 4]

 

또 다른 관점에서 살펴보면 두 벡터의 합은 서로 다른 방향의 두 힘이 충돌했을 때의 그 합쳐진 힘의 진행 방향으로 해석될 수도 있다.

 

[그림 5]

 

벡터의 뺄셈은 역시 (1, 2)인 V1에서 (2, 1)인 V2를 빼면 (-1, 1)인 V3가 나온다. 다만 여기서 기억할 점은 이렇게 결과 값으로 나온 V3가 V2 지점에서 시작하여 V1 방향으로 이동하는 V3'와 길이와 방향이 모두 같다는 것이다. 이것을 이용하면 V1과 V2 사이의 거리, V2에서 V1으로 가는 방향등을 구할 수 있다.

 

벡터와 스칼라의 곱셈

 

벡터는 좌표로서 공간 상에서 방향과 크기를 의미하지만 스칼라는 크기 만을 가지는 값이다. 벡터가 차원 축을 따라서 (2, 0), (1, 2, 3)과 같은 값을 가지는 것에 비해 1, 10, 24 등의 단일한 값을 의미한다.

 

[그림 6]

 

(1, 1)인 V1에 4인 스칼라 S를 곱하면 V1의 각 원소에 S를 곱하여 (4, 4)인 V2를 얻게 된다. 이렇게 벡터에 스칼라를 곱하는 계산은 주로 벡터의 크기를 원하는대로 늘이거나 줄이는 등의 계산이나, 벡터에 -1을 곱해서 현재 벡터의 반대 방향을 구하는데 주로 사용된다.

 

벡터의 길이

 

[그림 2]에서는 벡터를 나란히 놓는 원시적인 방식으로 벡터의 길이를 비교했다. 이런 방식 외에 계산적인 방식으로도 벡터의 길이를 구할 수 있다.

 

 

벡터의 길이를 구하는 공식은 위와 같다. 벡터의 각 원소를 제곱한 뒤, 모두 더하여 제곱근을 구하면, 벡터의 길이가 나온다.

 

[그림 1]

 

다시 [그림 1]을 보자. V1의 좌표는 (2, 2)이다. 이것을 공식에 대입하면 : 

 

 

위와 같은 값이 나온다. 이것은 사실 피타고라스의 정리에서 유도된 빗변의 길이를 구하는 공식이다. 벡터는 항상 각 축을 대상으로 직각을 이루는 직각 삼각형의 형태이기 때문에 이 공식으로 길이를 구할 수 있는 것이다.

 

벡터의 길이는 즉, 거리로, 벡터의 뺄셈을 이용하면 두 벡터 간의 거리를 구할 수 있다.

 

 

3차원 벡터에 대한 공식은 2차원 공식에 z축 좌표를 추가해서 계산하면 된다.

 

벡터의 정규화(Normalize)

 

벡터의 정규화는 현재 벡터의 방향을 유지한 채로 벡터의 길이를 1로 만드는 것을 의미하며, 이를 단위 벡터라고 부른다.

 

 

단위 벡터를 구하려면 벡터의 각 원소를 벡터의 길이로 나누어 주면 된다. 예를 들어 [그림 1]의 V1을 단위 벡터로 만들려면 V1의 각 원소 (2, 2)를 각각 벡터의 길이인 2.828427로 나누어주면 된다. 그러면 각 원소의 값은 (0.707106..., 0.707106...)이 된다. 이렇게 나온 단위 벡터에 대해서 다시 벡터의 길이를 구해보면 1의 근사값이 나올 것이다.

 

이런 단위벡터는 정확히 벡터의 방향만을 추출하고자 할 때 사용되는데, 주 사용처를 이야기 해보자면, 만약 캐릭터를 마우스의 방향으로 이동시키려고 할 때, (마우스 위치) - (캐릭터 위치)로 캐릭터에서 마우스 위치 방향을 찾아낼 것이다. 그런데 이 벡터를 그대로 사용하면 마우스의 거리가 멀어지면 멀어질 수록 이 이동 벡터의 길이가 길어지기 때문에 마우스와 캐릭터의 거리가 멀면 캐릭터가 빨라지고 가까워지면 캐릭터가 느려지는 문제가 발생할 것이다.

 

(마우스 위치) - (캐릭터 위치)로 찾아낸 방향을 정규화해서 단위 벡터로 만든 다음에 캐릭터의 이동 속도만 곱해주면 캐릭터가 일정한 속도로 이동한다.

 

벡터의 내적(Dot Product)

 

점곱(dot product), 내적(inner product)이라고 부르는 계산으로 계산 결과 값으로 벡터가 아닌 단일 값, 즉 스칼라 값을 내는 계산이다. 때문에 스칼라 곱이라고도 부르는데, 벡터와 스칼라의 곱셈과 헷갈려서는 안된다.

 

 

계산 공식은 위와 같다. 벡터의 각 원소끼리 곱한 뒤, 모두 더하는 것으로 벡터의 내적을 구할 수 있다.

 

이렇게 나온 계산 결과의 의미는 내적의 값이 0이면 두 벡터의 각이 90도이고, 0보다 크면 두 벡터 사이의 각도가 90도보다 작고, 0보다 작으면 각도가 90도보다 크다는 의미이다. 여기에 삼각함수를 이용하면 두 벡터 사이의 각도를 구할 수 있다.

 

벡터의 외적(Cross Product)

 

가위곱(cross product), 외적(outer product)이라고 부르는 계산으로 두 벡터와 모두 직교하는, 즉 두 벡터와의 각이 모두 90도를 이루는 벡터를 결과값으로 내며, 3차원 공간에서만 성립하는 계산이다.

 

 

외적의 계산 공식은 위와 같다. 

 

[그림 7]

 

 V1과 V2에 대해서 직교하는 벡터는 V3, V4 둘 다 될 수 있는데, 이 결과는 왼손 좌표계를 사용하느냐, 오른손 좌표계를 사용하느냐에 따라 결과가 달라진다. 왼손 좌표계에서 V2 X V1의 결과값은 V3로 나오고 오른손 좌표계에서는 V4로 나온다. 이렇게 나온 벡터를 법선 벡터(Normal Vector)라고 부른다.

 

[그림 8]

 

그래서 벡터의 외적은 [그림 8]과 같이 한 면이 바라보는 방향을 구하는 용도로 주로 사용된다.

 

 

 

 

 

유니티 엔진의 벡터

 

그러면 이제 유니티 엔진에서의 벡터에 대해서 알아보자.

 

Vector2 vector2 = new Vector2();

 

vector2.x = 1f;

vector2.y = 1f;

 

Vector3 vector3 = new Vector3();

 

vector3.x = 1f;

vector3.y = 1f;

vector3.z = 1f;

 

위의 코드 예시는 유니티에서 사용되는 Vector2 구조체와 Vector3 구조체이다. Vector2 구조체는 2차원 평면 공간에 속하는 벡터로 X축의 좌표를 표시하기 위한 x 변수와, Y축의 값을 표시하기 위한 y 변수를 가진다. Vector3 클래스는 여기에 더해 Z축을 표시하는 z 변수까지 가진다.

 

Vector2는 대부분 UI 같은 2D 공간이나 2D 게임을 제작할 때 사용되고, Vector3는 일반적인 3D 공간에서 사용된다.

 

자, 그렇다면 우리는 벡터와 관련된 기능을 전부 직접 구현해서 사용해야 할까? 아니다. 유니티에서는 이러한 벡터와 관련된 기능들을 모두 제공한다.

 

벡터의 덧셈과 뺄셈

 

Vector3 v1 = new Vector3(1f, 2f, 0f);

Vector3 v2 = new Vector3(2f, 1f, 0f);

// 벡터의 덧셈

Debug.Log("v1 + v2 = " + (v1 + v2));

// 벡터의 뺄셈

Debug.Log("v1 - v2 = " + (v1 - v2));

 

 

벡터의 덧셈과 뺄셈은 간단하게 일반 덧셈과 뺄셈을 하듯이 연산자를 사용하면 바로 구할 수 있다.

 

벡터와 스칼라의 곱셈

 

// 벡터와 스칼라의 곱셈

Vector3 v1 = new Vector3(1f, 1f, 0f);

int scalar = 4;

Debug.Log("v1 * scalar = " + (v1 * scalar));

 

 

벡터와 스칼라, 단일 정수 혹은 단일 실수와의 곱셈 역시 일반 계산과 같이 간단하다.

 

벡터의 길이

 

Vector3 v1 = new Vector3(2f, 2f, 0f);

// 벡터의 길이

Debug.Log("length of v1 = " + (v1.magnitude));

 

 

벡터의 길이는 Vector3 구조체에 포함되어 있는 magnitude 프로퍼티를 통해서 가져올 수 있다. 이것은 Vector2에서도 똑같다.

 

벡터의 정규화

 

Vector3 v1 = new Vector3(2f, 2f, 0f);

// 정규화된 단위 벡터

Vector3 normalizedVector = v1.normalized;

Debug.Log("||v1|| = " + normalizedVector);

// 단위 벡터의 길이 확인

Debug.Log("length of ||v1|| = " + normalizedVector.magnitude);

 

 

Vector3 구조체의 normalized 프로퍼티를 이용하면 정규화된 단위 벡터를 가져올 수 있다. magnitude 프로퍼티를 다시 사용해보면 단위 벡터의 길이가 1임을 확인할 수 있다.

 

벡터의 내적

 

[그림 9]

 

아래 코드 예시에 정의된 각 벡터는 [그림 9]와 같다.

 

Vector3 v1 = new Vector3(2f, 0f, 0f);

Vector3 v45 = new Vector3(1f, 1f, 0f);

Vector3 v90 = new Vector3(0f, 2f, 0f);

Vector3 v135 = new Vector3(-1f, 1f, 0f);

 

// 벡터의 내적

Debug.Log("v1 . v45 = " + Vector3.Dot(v1, v45));

Debug.Log("v1 . v90 = " + Vector3.Dot(v1, v90));

Debug.Log("v1 . v135 = " + Vector3.Dot(v1, v135));

 

// 두 벡터 사이의 각도

Debug.Log("v1 . v45 = " + Vector3.Angle(v1, v45));

Debug.Log("v1 . v90 = " + Vector3.Angle(v1, v90));

Debug.Log("v1 . v135 = " + Vector3.Angle(v1, v135));

 

 

벡터의 내적을 구하려면 Vector3 클래스의 정적 함수인 Dot 함수를 사용하면 된다. 벡터의 내적에 대해서 설명했듯이, v1과 v45 사이의 각도는 90도 보다 작기 때문에 0보다 큰 값이 나왔고, v1과 v90 사이 각은 정확히 90도이기 때문에 0, v1과 v135 사이 각은 90도보다 커서 0보다 작은 값이 나온 것을 확인할 수 있다.

 

덤으로 Vector3의 또 다른 정적 함수인 Angle 함수를 사용하면 두 벡터 사이의 각을 얻을 수 있다.

 

벡터의 외적

 

Vector3 v1 = new Vector3(2f, 0f, 0f);

Vector3 v2 = new Vector3(0f, 0f, 2f);

 

// 벡터의 외적

Debug.Log("v1 X v2 = " + Vector3.Cross(v1, v2));

 

 

벡터의 외적은 Vector3 클래스의 정적 함수인 Cross 함수를 통해서 구할수 있다.

 

이번 섹션에서는 벡터와 그 계산법을 알아보고 유니티 엔진에서는 어떻게 사용되는지 알아보았습니다.

 

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

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

 

에셋스토어

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

스크립트 작업 기초

 

작성 기준 버전 :: 2019.2

 

[본 튜토리얼의 내용을 유튜브 영상을 통해서 확인하실 수도 있습니다]

 

이번 섹션에서는 스크립트 작업으로 기초적인 커스텀 컴포넌트를 만드는 법을 배워보자.

 

본격적인 섹션 진행에 앞서 게임 오브젝트와 컴포넌트에 관련된 지식이 필요하다면 이 포스트를 참고해보자.

 

또한 이번 섹션을 진행하기 위해서는 C# 프로그래밍에 대한 기초적인 지식을 필요로 한다.

 

커스텀 컴포넌트 생성

 

[그림 1]

 

우선 커스텀 컴포넌트를 만들기 위해서 C# 스크립트를 하나 생성해보자. 프로젝트 뷰에 우클릭하여 [Create > C# Script] 항목을 선택한다.

 

 

그렇게하면 NewBehaviourScript라는 이름으로 C# 스크립트 파일이 하나 생성된다.

 

 

바로 엔터 키를 누르지 말고 파일의 이름을 ScriptingTest로 변경하고 엔터 키를 누르도록 하자. C# 스크립트 파일은 제일 처음 이름이 정해질 때, 스크립트 파일 내부의 클래스 이름이 정해지며, 스크립트 파일의 이름과 클래스의 이름이 일치하는 것을 권장하기 때문에 클래스의 이름을 처음에 제대로 정하는 것이 나중에 수정하는 것보다 좋다. 특히 나중에 파일의 이름을 바꾸면 내부의 클래스의 이름도 수동으로 바꿔야하므로 굉장히 번거롭다.

 

 

그리고 생성된 스크립트 파일을 더블클릭하면 비주얼 스튜디오가 열립니다.

 

모노비헤이비어 클래스 상속

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ScriptingTest : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

 

최초로 생성된 기본 코드는 위와 같다. 먼저 생성된 ScriptingTest 클래스가 모노비헤이비어(MonoBehaviour) 클래스를 상속받고 있는 것을 볼 수 있다. 이 유니티로 게임을 제작할 때 사용되는 C# 클래스는 이 모노비헤이비어를 상속받는 클래스과 상속받지 않는 클래스로 크게 나누어진다.

 

 

모노비헤이비어 상속 여부에 따른 차이는, 모노비헤이비어를 상속받지 않은 클래스는 게임 오브젝트에 컴포넌트로써 부착되지 못한다는 것에 있다. 때문에 컴포넌트로써 게임 오브젝트에 부착되어서 씬 내부에 존재해야하는 클래스는 모노비헤이비어를 상속받는게 필수이고, 씬에 컴포넌트로 배치되지 않고 코드 내부에서 개념적으로만 존재할 클래스는 모노비헤이비어를 상속받지 않아야 한다.

 

모노비헤이비어의 라이프 사이클

 

 

 

 

모노비헤이비어를 상속받아서 게임 오브젝트에 부착되어 동작하는 스크립트를 잘 활용하려면 모노비헤이비어의 라이프 사이클에 대해서 잘 알아두는 것이 좋다. 모노비헤이비어를 상속받는 컴포넌트는 생성되어 게임 오브젝트에 부착되는 순간부터 위의 이미지와 같은 과정을 거친다.

 

그리고 위의 모노비헤이비어 상속 파트에서 본 코드 블럭을 보면 Start() 함수와 Update() 함수가 구현되어 있는 것을 볼 수 있다. 이와 같이 거치는 과정의 이름으로 함수를 만들어두면 해당 과정을 거칠 때, 그 함수가 실행되는 구조이다.

 

그럼 각 과정이 언제 호출되는지 어떻게 구현하면 되는지에 대해서 하나씩 알아보자.

 

Awake

 

private void Awake()
{
    Debug.Log("Awake");   
}

 

Awake 과정은 스크립트 인스턴스가 로딩될 때 단 한 번 호출되는 함수이다. 컴포넌트에 대한 초기화가 필요한 경우에 사용된다. 참고로 모노비헤이비어를 상속받는 클래스는 생성자 대신에 Awake() 함수를 구현해서 사용해야 한다.

 

OnEnable

 

private void OnEnable()
{
    Debug.Log("OnEnable");   
}

 

OnEnable 과정은 모노비헤이비어를 상속받은 컴포넌트가 부착된 게임 오브젝트가 활성화될 때마다 호출되는 함수이다.

 

 

에디터의 씬에서 게임 오브젝트를 선택하면 인스펙터 뷰에서 선택한 게임 오브젝트에 대한 정보를 볼 수 있는데, 이 중에 게임 오브젝트 이름 앞에 체크박스가 있다. 이 체크박스를 클릭해보면 체크박스 상태에 따라서 게임 오브젝트가 활성화되었다 비활성화되었다하는 것을 볼 수 있다. 이렇게 게임 오브젝트가 활성화될 때마다 OnEnable() 콜백 함수가 호출되는 것이다. 참고로 게임 오브젝트가 비활성화된 상태에서는 해당 게임 오브젝트에 부착된 모든 컴포넌트가 동작을 멈춘다.

 

Start

 

private void Start()
{
    Debug.Log("Start");   
}

 

Start 과정은 Update 과정이 실행되기 직전에 단 한 번 호출된다. 모노비헤이비어의 라이프 사이클 중에 단 한 번 호출된다는 점이 Awake와 같지만 Start는 게임 오브젝트가 활성화된 경우에만 호출된다는 차이점이 있다.

 

Update

 

private int i = 5;
private void Update()
{
    i--;
    if(i >= 0)
    {
        Debug.Log("Update :: " + i);
    }
    else
    {
        Destroy(gameObject);
    }
}

 

Update 과정은 모노비헤이비어가 활성화된 상태에서 매 프레임마다 호출된다. 대부분의 게임의 동작 처리는 이 Update() 함수에서 수행되는 경우가 많다. 다만, 이 Update() 함수는 프레임마다 호출되기 때문에 프레임 드랍이 발생하는 경우에는 호출 횟수가 줄어든다. 프레임과 상관 없이 코드가 작동하기 원한다면 FixedUpdate() 함수를 사용해야 한다.

 

Update() 함수는 OnEnable() 함수를 설명하면서 이야기했듯이 게임 오브젝트가 비활성화된 상태에서는 동작하지 않는다.

 

LateUpdate

 

private void LateUpdate()
{
    Debug.Log("LateUpdate");   
}

 

LateUpdate는 단어 그대로 늦은 업데이트로 Update() 함수가 실행된 직후에 실행되는 업데이트 함수이다. Update() 함수에서 게임 로직을 처리한 직후에 처리하고 싶은 로직이 있다면 이곳에서 처리하면 된다.

 

FixedUpdate

 

private void FixedUpdate()
{
    Debug.Log("FixedUpdate");   
}

 

FixedUpdate는 매 프레임마다 호출되는 Update와 달리 지정된 시간마다 호출되는 업데이트 함수이다. 때문에 프레임이 들쭉날쭉한 상황에서도 일정한 시간마다 호출된다. 주로 호출 시간에 따라서 결과가 달라지면 안되는 물리적인 계산에 사용된다.

 

OnDisable

 

private void OnDisable()
{
    Debug.Log("OnDisable");   
}

 

OnDisable 과정은 모노비헤이비어가 비활성화되는 경우에 사용된다. 그리고 오브젝트가 삭제되는 경우에도 호출된다.

 

OnDestroy

 

private void OnDestroy()
{
    Debug.Log("OnDisable");   
}

 

OnDestory 과정은 모노비헤이비어가 제거될 때 호출된다.

 

 

위의 코드를 모두 ScriptingTest 클래스에 작성하고 플레이시켜보면 위의 이미지와 같은 순서로 로그가 발생하는 것을 볼 수 있다.

 

 

 

 

 

변수

 

우리가 게임을 만들면서 사용될 값, 공격력, 방어력, 공격속도, 이동속도, HP 등의 데이터나 정보를 담아둘 것을 변수라고 부른다. 유니티 엔진에서 스크립트를 작성하는 C#은 담고자하는 값의 종류에 따라서 변수의 종류가 나누어진다. 그럼 이 변수의 종류에 대해서 알아보도록 하자.

 

정수(int)

 

int i = 10;

 

첫 번째 변수 유형은 정수형이다. 정수형 변수 int는 0과 양의 정수, 음의 정수를 담기 위한 변수로, -2,147,483,648부터 2,147,483,647까지 담을 수 있다. 

 

남아있는 라이프의 갯수, 현재 생산된 인구 수 등의 정수로 딱 떨어지는 곳에서 사용될 수 있다.

 

실수(float)

 

float f = 3.14159f;

 

두 번째 변수 유형은 실수형이다. 실수형 변수 float은 소수를 담기 위한 변수로 일반적으로 소수점 다섯 번째자리 0.00001까지 정확도를 표현할 수 있다.

 

주로 1.2초 같은 시간이나 20.25%와 같은 확률 등을 표현할 때, 주로 사용된다.

 

문자열(string)

 

string str = "hello";

 

세 번째 변수 유형은 문자열입니다. 문자열 변수 string은 말그대로 문자들의 집합인 문자열을 담는 변수이다.

 

주로 캐릭터나 아이템의 이름, 설명, 게임에서 사용되는 대사 자막 등의 데이터를 담는데 사용된다.

 

논리값(bool)

 

bool isMoveable = true;

 

네 번째 변수 유형은 논리값이다. 논리값 변수 bool은 참(true) 혹은 거짓(false)의 상태를 가지는 변수로 주로 조건을 처리할 때 사용된다.

 

이 외에도 각 종류의 변수를 묶음 단위로 취급하는 배열 등이 있고, 일반 C# 클래스나 모노비헤이비어를 상속받은 클래스 역시 변수가 될 수 있다.

 

 

함수

 

함수는 게임 기능을 수행하기 위한 작업을 하나의 블록으로 묶은 것을 의미한다. 모노비헤이비어의 라이프 사이클에 대해서 설명하면서 본 Awake, OnEnable, Start, Update, OnDisable, OnDestroy 역시 함수이다. 일반적으로 함수는 하나의 기능 단위로 작성되는 경우가 많다.

 

int attackDamage = 10;

public bool Attack(Monster monster)
{
    monster.hp -= attackDamage;
    return monster.hp <= 0;
}

 

위의 예시 코드는 몬스터를 공격해서 체력을 공격력만큼 깎고, 몬스터의 체력이 0 이하가 되면 true를 반환하도록 코드가 작성되어 있다. 이렇게 하면 Attack() 함수를 호출하여 몬스터의 체력을 깎고 공격한 몬스터가 죽었는가에 따라서 여러가지 처리를 할 수 있게 된다.

 

 

공개 수준 결정

 

개발자는 코드를 작성하면서 변수나 함수에 대해서 공개 수준을 결정할 수 있다.

 

public int i;

protected float f;

private string str;
 
public void Function1() { }
 
protected void Function2() { }
 
private void Function3() { }

 

변수와 함수의 공개 수준은 앞에 표시된 public, protected, private 키워드를 통해서 결정된다. 이러한 공개 수준은 일반적인 C# 프로그래밍에서와 같이 public은 클래스 외부에서 접근이 가능하고 protected는 해당 클래스를 상속받은 클래스에서만 접근이 가능하다. 그리고 private는 해당 클래스의 내부에서만 사용 가능하다.

 

public class ScriptingTest : MonoBehaviour
{
    public int attackDamage = 10;
}

 

그리고 유니티 엔진만의 특징으로는 모노비헤이비어 클래스를 상속받은 클래스에서 public으로 설정된 변수는 에디터의 인스펙터 뷰에서 바로 보고 수정할 수 있다는 장점이 있다.

 

 

이러한 방식의 장점은 매번 게임의 수치가 바뀔 때마다 프로그래머가 코드를 수정하고 새로 빌드 과정을 거칠 필요없이 게임 디자이너가 에디터에서 즉석으로 값을 바꿀 수 있다는 것이다.

 

하지만 인스펙터 뷰에서 보이게 하고자 하는 모든 변수를 public으로 설정하면 코드 내부에서 어떤 클래스에서던지 접근이 가능해진다. 이런 경우를 방지하고자 protected나 private로 설정한 채로 인스펙터 뷰에 공개하고 싶을 수도 있다.

 

[SerializeField]
private int attackDamage = 10;

 

그럴 때는 SerializeField라는 어트리뷰트를 해당 변수 앞에 명시해주면 private나 protected로 둔 상태로도 인스펙터 뷰에 변수를 공개할 수 있다.

 

[HideInInspector]
public int attackDamage = 10;

 

그와 반대로 변수를 public으로 둔 상태로 인스펙터 뷰에 공개하고 싶지 않다면 HideInInspector 어트리뷰트를 붙여주면 된다.

 

모노비헤이비어 클래스를 상속받아서 만들어진 컴포넌트는 클래스를 기반으로 변수를 어떻게 구성하고 함수를 어떻게 구현하느냐에 따라서 그 컴포넌트의 기능과 역할이 정해진다. 

 

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

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

 

에셋스토어

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

 

반응형

Cloth

-

유니티 2019 버전에서의 Cloth 컴포넌트 문제

 

작성 기준 버전 :: 2019.*

 

Cloth 컴포넌트는 유니티 엔진에서 지원하는 사실적인 천의 펄럭임을 구현하기 위한 컴포넌트다.

 

2018 버전의 Cloth

 

Cloth 컴포넌트를 사용하면 위 그림과 같이 메시(Mesh)를 천과 같은 움직임을 보이도록 시뮬레이션 할 수 있다.

 

다만, 유니티 2019 버전에 들어오면서 이 Cloth 컴포넌트와 관련해서 여러가지 문제점이 제기되고 있다. 제기된 문제의 주된 내용은 다음과 같다.

 

2019 버전에서 Cloth 컴포넌트를 사용할 때,

2019 버전에서 Cloth 컴포넌트가 부착된 프리팹을 인스턴스화 했을 때,

Cloth 컴포넌트를 사용하던 2018 버전의 프로젝트를 2019 버전으로 마이그레이션 했을 때,

 

- 초당 1프레임 수준으로 렌더링 속도가 심각하게 저하됨.

- 메시(Mesh)가 심각하게 찌그러짐.

- 자연스러운 움직임이 아닌 이상하게 꿈틀거리는 움직임을 보임.

 

사실상 2019 버전에서는 Cloth 컴포넌트를 사용하기 힘든 수준의 문제들이 보고되고 있다.

 

2019 버전의 Cloth

 

유니티 2019에서 Cloth 컴포넌트를 사용해보면 처음에는 정상적으로 동작하는 것으로 보인다.

 

 

하지만 Cloth 컴포넌트의 Stretching Stifness 값을 변경해보면 문제가 바로 눈에 띈다.

2018 버전의 Cloth
2019 버전의 Cloth

 

2018버전에서는 Stretching Stifness 값을 0으로 바꾸면 펄럭일때 주름이더 세밀해지는 정도의 변화를 보이지만, 2019 버전에서는 Stretching Stifness 값을 0으로 변경하면 버텍스가 찢어지면서 형태가 완전히 무너지는 것을 볼 수 있다. 

 

때문에 2019 버전에서는 이 문제가 완전히 해결되기 전에는 Cloth 컴포넌트를 사용하지 않을 것을 권장한다.

 


 

관련 유니티 포럼 글

 

Cloth physics problems when migrate from Unity 2018 to 2019

[Cloth] [AR] Unity 2019.2.4f1 broke Cloth

[Cloth] Sudden cloth performance issues in AR

 

Cloth self-collision: Selection not saving / unselects after clicking Play

 

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

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

 

에셋스토어

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

캔버스의 분할

 

작성 기준 버전 :: 2019.2

 

유니티에서 모든 UI는 캔버스(Canvas) 위에서 그려진다. 아직 유니티 엔진을 이용한 개발에 익숙하지 못한 개발자들은 모든 UI를 한 캔버스에 만드는 경우가 많다.

 

하지만 모든 UI를 한 캔버스로 몰아넣으면 모든 UI를 그리는 과정에서 불필요한 낭비가 발생하게 된다.

 

[그림 1]

 

[그림 1]을 보면 하나의 캔버스 안에 여러 개의 이미지가 포함되어 있는 것을 볼 수 있다. Checker 오브젝트는 흰 색과 검은 색으로 이루어진 이미지이고, 그 뒤에 Background Slide라는 이름의 회색 이미지가 크게 배치되어 있다.

 

[그림 2]

 

우선 이 상태에서 UI는 어떤 과정을 통해서 그려지는지 확인하기 위해서 프레임 디버거(Frame Debugger)를 실행해보자. 프레임 디버거는 게임에서 각 프레임이 그려질 때 어떤 과정을 거쳐서 그려지는지 보여주는 디버깅 툴이다. 이것을 통해서 어떤 렌더링 과정에서 시간을 소모하는지를 확인할 수 있는 좋은 도구이다. 프레임 디버거를 실행하기 위해서는 유니티 상단 메뉴에서 [Windows > Analysis > Frame Debugger]를 선택하면 된다.

 

[그림 3]

 

그러면 [그림 3]과 같은 프레임 디버거 창이 열린다.

 

[그림 4]

 

프레임 디버거 창을 띄운 후, 플레이를 시작하고 프레임 디버거 창의 Enable 버튼을 누르면 한 프레임이 그려지는데 어떤 과정으로 몇 단계나 거쳐서 실행되는지 확인할 수 있다.

 

[그림 5]

 

이 상태에서 7 of 7 옆에 있는 넘기기 버튼을 눌러서 확인해보면 총 7단계를 거쳐서 화면이 그려지고 있고 그 중에 UI는 6, 7단계 두 단계를 거쳐서 먼저 회색 바탕이 그려지고 그 위에 체크 무늬 이미지가 그려지는 것을 볼 수 있다.

 

using UnityEngine;

using UnityEngine.UI;

 

public class FillingImage : MonoBehaviour

{

    private Image image;

 

    void Start()

    {

        image = GetComponent<Image>();

    }

 

    bool isFill = false;

    float timer = 0f;

 

    void Update()

    {

        if(timer >= 1f)

        {

            timer = 0f;

            isFill = !isFill;

        }

        timer += Time.deltaTime;

        image.fillAmount = isFill ? timer : 1f - timer; 

    }

}

 

그렇다면 이번에는 회색 바탕의 이미지인 Background Slide 오브젝트에 위와 같은 코드를 추가해서 이미지가 계속해서 채워졌다가 사라지는 동작을 반복하도록 만들어보자.

 

[그림 6]

 

코드를 모두 작성했다면 Background Slide 게임 오브젝트에 컴포넌트로 붙여준다.

 

[그림 7]

 

이것을 실행해보면 [그림 7]와 같이 보여진다. 하지만 단순히 겉으로만 보이는 상황으로는 어떤 낭비가 발생하는지 알 수 없다. 그러면 어떤 낭비가 발생하는지 확인하기 위해서 다시 프레임 디버거로 살펴보자.

 

[그림 8]

 

프레임마다 분명 7단계였던 렌더링 과정이 회색 이미지가 체커와 겹치게 되면서 8단계로 늘어나는 것을 볼 수 있다.

 

[그림 9]

 

이 8단계로 늘어난 렌더링 과정을 살펴보면 7단계일 때는 분명 회색 바탕을 먼저 그리고 체크 무늬 이미지를 그렸던 과정이 회색 바탕과 겹치지 않은 체크 무늬 이미지를 그리는 과정, 회색 바탕 이미지를 그리는 과정 그리고 회색 바탕과 겹친 체크 무늬 이미지를 그리는 과정으로 나누어진 것을 볼 수 있다. 이것은 렌더링 과정이 아주 작게 늘어난 예시로, UI 캔버스의 구조가 복잡해지면 복잡해질 수록 어떤 성능의 낭비를 가져올지 알 수 없게 된다.

 

이것을 해결하기 위한 방법이 바로 이번 글의 주제인 캔버스의 분할이다.

 

[그림 10]

 

[그림 10]을 보면 매 프레임 변동이 발생하는 Background Slide와 늘 고정되어 있는 Checker를 다른 캔버스로 나누어 배치한 것을 볼 수 있다.

 

[그림 11]

 

이렇게 캔버스를 분할한 뒤 다시 실행해서 매 프레임의 렌더링 단계를 살펴보면 다시 7단계로 줄어든 것을 확인할 수 있다.

 

[그림 12]

 

렌더링 단계 역시 살펴보면 회색 바탕을 먼저 그리고 회색 바탕과 체크 무늬 이미지가 겹치는 것과 상관없이 한꺼번에 체크 무늬 이미지를 그리는 것을 볼 수 있다.

 

이렇게 캔버스를 분할하는 것 역시 렌더링 최적화를 위한 하나의 방법이 될 수 있다. 가능하면 변동되는 타이밍이 비슷한 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

 

반응형

Explorer 2D Game Kit 분석 (4) 

게임플레이 요소 (1)

 

작성 기준 버전 :: 2019.1.4f1

 

그림 1

 

본격적으로 게임플레이와 관련된 요소들에 대해서 분석해볼 차례이다.

 

그림 2

 

기본적인 하이어라키 뷰(Hierarchy View) 상태는 스타트 씬과 비슷하지만 게임이 진행되는 씬이기 때문에 플레이어와 연관된 에셋인 Player Assets 파트와 레벨을 구성하고 있는 Level Assets 파트가 추가되어 있는 것을 알 수 있다.

 

시스템(System)

 

시스템으로 분류된 게임 오브젝트는 씬 컨트롤러(Scene Controller), 트랜지션 스타트(Transition Start), 트랜지션 데스티네이션(Transition Destination), VFX 컨트롤러(VFX Controller), 백그라운드 뮤직 플레이어(Background Music Player), 피직스 헬퍼(Physics Helper)가 있다.

 

이 중에서 씬 컨트롤러와 그리고 백그라운드 뮤직 플레이어는 지난 섹션에서 다루었으니 넘어가도록 하고, 지난 섹션에서 다루기는 했으나 트랜지션 포인트(Transition Point) 컴포넌트를 부착하고 있는 트랜지션 스타트 게임 오브젝트는 약간의 차이가 있으나 가볍게 다루고 넘어가도록 한다.

 

트랜지션 스타트 게임 오브젝트(Transition Start Game Object)

 

그림 3

 

지난 섹션에서 다루었다시피 트랜지션 스타트 게임 오브젝트는 트랜지션 포인트 컴포넌트가 부착되어 있으며 플레이어의 캐릭터가 콜라이더에 닿으면 플레이어를 다른 씬으로 보내는 역할을 한다.

 

다만, 스타트 씬에서의 트랜지션 포인트와 다른 점은, 스타트 씬에서는 콜라이더에 닿은 캐릭터가 존재하지 않기 때문에 외부에서 트랜지션 포인트를 호출해서 씬을 전환하는 방식을 사용했다면, 이제부터는 본래의 방식에 맞게 캐릭터가 콜라이더에 닿으면 다른 씬을 보내도록 구성되어 있다는 점이다.

 

그림 4

 

실제로 씬에서 트랜지션 스타트 게임 오브젝트를 선택해서 보면 발판에서 캐릭터가 뛰어내리면 콜라이더에 닿을 수 있게 배치되어 있는 것을 확인할 수 있다.

 

그리고 원래의 스타트 씬에서는 Trasitioning Game Object 프로퍼티가 비어있었는데 지금은 Ellen이라는 게임 오브젝트가 할당되어 있는 것을 알 수 있다. 이 게임 오브젝트는 씬에 배치 되어있는 플레이어의 캐릭터로, 다른 물체나 몬스터 등의 다른 캐릭터가 아닌 플레이어의 캐릭터만 닿았을 때, 씬을 이동시키기 위해서 할당해둔 것이다.

 

void OnTriggerEnter2D (Collider2D other)

{

    if (other.gameObject == transitioningGameObject)

    {

        m_TransitioningGameObjectPresent = true;

 

        if (ScreenFader.IsFading || SceneController.Transitioning)

            return;

 

        if (transitionWhen == TransitionWhen.OnTriggerEnter)

            TransitionInternal ();

    }

}

 

트리거 설정된 콜라이더에 충돌이 발생했을 때 호출되는 OnTriggerEnter2D 콜백 함수를 보면 확실히 알 수 있다. 매개변수로 넘어온 충돌체의 게임 오브젝트와 미리 할당해둔 transitioningGameObject와 비교하여 같을 경우에만, 다른 씬으로 이동시키는 구조이다.

이렇게 하지 않으면 트랜지션 포인트의 콜라이더에 플레이어의 캐릭터가 아닌 총알이나 몬스터가 닿기만 해도 씬이 이동되는 상황을 보게 될 것이다.

 

유니티 콘텐츠 팀에서 선택한 방법에도 약간의 단점이 있다. 그것은 트랜지션 스타트에 미리 캐릭터를 할당해두는 방식이기 때문에 나중에 캐릭터를 선택할 수 있는 기능을 넣게 된다면, 다른 캐릭터로 시작하면 그 캐릭터는 이 콜라이더에 닿아도 다른 씬으로 이동하지 못할 수도 있다.

 

이것은 간단하게 만들어진 예시이기 때문에 발생한 문제로, 플레이어 캐릭터에 태그나 레이어를 설정하고, 태그나 레이어로 비교해서 통과시키는 방법으로 해결할 수 있다.

 

 

트랜지션 데스티네이션 게임 오브젝트(Transition Destination Game Object)

 

그림 5

 

트랜지션 데스티네이션 게임 오브젝트는 씬 트랜지션 데스티네이션 컴포넌트(Scene Transition Destination Component)와 캐릭터 스테이트 세터 컴포넌트(Character State Setter Component)로 구성되어 있다. 이 게임 오브젝트는 플레이어의 캐릭터가 씬 이동을 할 때 목적지 역할을 한다. 첫 번째 게임 플레이 씬인 Zone1에 두 개가 배치되어 있는데, 처음 게임이 시작되었을 때 배치되는 위치인 트랜지션 데스티네이션 스타트(Transition Destination Start)와 두 번째 게임 씬인 Zone2로부터 넘어왔을 때의 도착 지점인 트랜지션 데스티네이션 프롬 Zone2(Transition Destination From Zone2)가 그것이다.

 

씬 트랜지션 데스티네이션 컴포넌트(Scene Transition Destination Component)

 

public class SceneTransitionDestination : MonoBehaviour

{

    public enum DestinationTag

    {

        A, B, C, D, E, F, G,

    }

 

    public DestinationTag destinationTag;

    [Tooltip("This is the gameobject that has transitioned.  For example, the player.")]

    public GameObject transitioningGameObject;

    public UnityEvent OnReachDestination;

}

 

씬 트랜지션 데스티네이션 컴포넌트에는 사실상 큰 기능 자체는 존재하지 않고, 씬 컨트롤러(Scene Controller)에서 씬이 전환된 직후에 씬 안에 존재하는 씬 트랜지션 데스티네이션 컴포넌트가 부착된 모든 게임 오브젝트를 가지고 와서 데스티네이션 태그(Destination Tag)를 비교해 일치하는 트랜지션 데스티네이션 게임 오브젝트의 위치에 플레이어의 캐릭터를 이동시키기 위한 표지판 역할을 한다.

캐릭터 스테이트 세터 컴포넌트(Character State Setter Component)

 

캐릭터 스테이트 세터 컴포넌트는 씬 트랜지션 테스티네이션 컴포넌트와 함께 트랜지션 데스티네이션 게임 오브젝트에 부착된 컴포넌트로, 씬 트랜지션 데스티네이션 컴포넌트가 도착 위치를 지정하는 역할을 한다면 캐릭터 스테이트 세터 컴포넌트는 씬에 도착한 직후의 캐릭터의 상태를 설정하는 역할을 한다.

 

기본적으로 공개되어 있는 프로퍼티는 Set Character Velocity, Set Character Facing Contents, Set State, Set Parameter가 있으며 Set Character Velocity는 씬에 진입했을 때의 캐릭터의 속도를 설정할 수 있고, Set Character Facing Contents는 캐릭터가 바라볼 방향, Set State는 캐릭터의 애니메이션, Set Parameter는 캐릭터 애니메이터의 매개변수 값을 설정하는 옵션이다.

 

그림 6

 

캐릭터 스테이트 세터 컴포넌트에서 눈여겨 볼 점은 [그림 5]에서와 같이 프로퍼티가 선택되지 않았을 때는 해당 프로퍼티에 연관된 옵션이 보이지 않다가 프로퍼티 값이 true로 설정되면 [그림 6]과 같이 프로퍼티와 연관된 옵션이 보이도록 에디터가 커스터마이징되어 있다는 점이다. 프로젝트 뷰에서 CharacterStateSetterEditor를 검색해서 CharacterStateSetterEditor.cs 파일을 확인해보면 어떤 식으로 프로퍼티 값에 따라서 보여줄 옵션을 설정할 수 있는지 배울 수 있다.

 

이렇게 유니티 에디터에서 필요하거나 사용되는 옵션만 보여주는 것 만으로도 에디터에서 작업하는 디자이너 개발자의 작업 효율을 크게 상승시킬 수 있다.

 

[Header("Character Velocity")]

public bool setCharacterVelocity;

public Vector2 characterVelocity;

 

[Header("Character Facing")]

public bool setCharacterFacing;

public bool faceLeft;

 

public Animator animator;

 

[Header("Character Animation State")]

public bool setState;

public string animatorStateName;

 

[Header("Character Animation Parameter")]

public bool setParameters;

public ParameterSetter[] parameterSetters;

 

그림 7

 

여기에 더불어 Header 어트리뷰트를 사용하면 [그림 7]과 같이 프로퍼티의 분류를 훨씬 명확하게 인지하도록 만들 수 있다.

 

 

VFX 컨트롤러 게임 오브젝트(VFX Controller Game Object)

 

그림 8

 

VFX 컨트롤러 게임 오브젝트는 VFX 컨트롤러 컴포넌트(VFX Controller Component)가 부착되어 있다. 이 게임 오브젝트의 목적은 캐릭터가 점프하거나 달릴 때 먼지가 일너나는 들의 이팩트를 관리하는 것이다.

 

VFX 컨트롤러 컴포넌트(VFX Controller Component)

 

VFX 컨트롤러 컴포넌트는 이펙트를 관리하는 역할의 컴포넌트이다. 이것은 다른 시스템 컴포넌트와 마찬가지로 싱글톤 패턴으로 만들어졌으며, 같은 이펙트 게임 오브젝트들이 계속해서 생성되고 파괴됨으로써 발생하는 성능 저하를 막기 위해서 오브젝트 풀링 기법을 사용하고 있다. 오브젝트 풀링 기법은 기초적인 최적화 기법으로 오브젝트가 생성/파괴될 때 발생하는 오버헤드를 막기 위해서 오브젝트를 재사용하는 기법을 말한다.

 

그림 9

 

VFX 컨트롤러 컴포넌트에서는 게임에서 사용될 VFX 프리팹들을 리스트에 담아서 관리하는데, 만약 같은 방식으로 생성되어야 하는 VFX지만 상황에 따라서 다른 VFX를 생성해야 경우, 예를 들어 캐릭터가 달릴 때 풀 바닥에서는 풀이 날리는 VFX가 발생해야 하지만, 흙 바닥에서 달릴 때는 흙 먼지가 날리는 VFX가 생성되도록 하기 위해서, Vfx Override로 특별한 경우를 정의하고 있다.

 

 

피직스 헬퍼 게임 오브젝트(Physics Helper Game Object)

 

 

피직스 헬퍼 게임 오브젝트는 피직스 헬퍼 컴포넌트(Physics Helper Component)를 가진 게임 오브젝트로서 게임 내에서 불리적인 처리에 도움을 주는 역할을 한다.

 

피직스 헬퍼 컴포넌트(Physics Helper Component)

 

피직스 헬퍼 컴포넌트는 게임이 플레이되는 상황에서 어디서든지 호출될 수 있기 때문에 싱글톤 패턴으로 작성되어 있으며, 캐릭터가 밟고 서는 플랫폼이나 타일맵에 관련된 물리적인 처리를 담당하고 있다.

 

사실 피직스 헬퍼 같은 컴포넌트는 개발자가 편의에 따라서 작성하기 나름인 스크립트이다. 게임마다 필요한 물리 연산이나 처리는 모두 다르기 마련이라, 필요한 물리 작업에 따라서 피직스 헬퍼의 내용은 천차만별로 달라질 수 있다. 다만, 이렇게 자주 사용되는 기능을 분류 별로 묶어서 어디서든지 호출할 수 있게 헬퍼 클래스로 만드는 작업은 관련된 기능을 이리저리 흩뜨려 놓는 것보다 확실히 더 나은 효율적인 작업을 보장한다.

 


 

Explorer 2D Game Kit 분석 (1) - 개요

Explorer 2D Game Kit 분석 (2) - Start 씬 해부하기 (1)

Explorer 2D Game Kit 분석 (3) - Start 씬 해부하기 (2)

Explorer 2D Game Kit 분석 (4) - 게임플레이 요소 (1)

 

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

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

 

에셋스토어

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