캐릭터 애니메이션 구현
프레임 바이 프레임을 구현하기 위해서 에셋 스토어에서 "warrior free" 라는 도트 그래픽 애니메이션을 Import해서 프로젝트에 Assets에 저장했다. 유니티 에셋 스토어에서 저장한 에셋은 상단 메뉴 바에서 window->package manager에서 확인할 수 있다. package manager에서는 유니티 프로젝트에서 사용할 수 있는 기능들을 볼 수 있다. 여기서 My Assets에 들어가면 다운받은 에셋들을 확인할 수 있다. Warrior의 기본 이미지로 오브젝트를 만들고 Animation(단축키 ctrl+6) 창을 띄운다.

Add Property를 누르고 sprite Renderer->Sprite를 누르면 애니메이션에 대해 초기 Sprite가 생긴다. 그리고 지금은 시간에 따라 스프라이트를 지정할 수 있는데 위에 시간 바 옆에 점 3개를 누르고 Seconds를 Frames로 바꿔주면 프레임마다 스프라이트를 지정할 수 있다. 그리고 Assets에서 프레임마다 스프라이트를 끌어당겨 애니메이션을 만들어준다.

그래서 6장 짜리 애니메이션을 만들었는데, 현재 Samples의 숫자를 보면 60으로 설정되어 있는데 이는 해당 애니메이션을 1초에 60프레임을 보여준다는 뜻이다. 즉 해당 애니메이션이 1초에 10번 반복된다는 것이다. 그래서 캐릭터가 엄청 빠른 속도로 움직인다. 그래서 Samples를 6로 바꾸면 애니메이션을 1초에 6프레임을 보여주는 것으로 바뀌어 해당 애니메이션을 1초 1번만 보여줘서 캐릭터가 적절한 속도로 움직인다. 현재 캐릭터의 기본 상태 애니메이션인 Warrior_Idle과 캐릭터가 뛰는 애니메이션 Warrior_Run 두 개의 애니메이션을 만들었다. 애니메이션을 만들면 Aminator Controller가 자동으로 생기는데 애니메이터 컨트롤러에서 애니메이션 관리나 전환을 할 수 있다. 애니메이터 컨트롤러에서 확인한 현재 기본적인 애니메이션은 Warrior_Idle이다.

여기서 Warrior_Run을 우클릭하고 Set as Layer Default State로 설정하면 기본 애니메이션이 Warrior_Run으로 바뀐다.
물리 적용
물리적인 효과를 적용하기 위해 Rigidbody와 Collider라고 하는 컴포넌트를 활용한다. RigidBody는 물리 갖는 오브젝트에 필수적으로 포함되어야 하는 컴포넌트로 질량, 중력 등의 데이터를 관리하는 컴포넌트이다. 그리고 Collider는 해당 오브젝트에 물리적인 충돌을 위한 오브젝트의 모양을 정의하는 컴포넌트 이다. Rigidbody를 포함하는 오브젝트는 Transform의 position등을 임의로 조작하게 되면 오브젝트가 이상하게 움직일 수 있다. 그래서 AddForce라는 함수를 사용한다. 현재 게임상의 오브젝트인 Warrior에 Box Collider 2D 컴포넌트와 Rigidbody2D 컴포넌트를 추가했다.

Collider의 크기는 툴 바에서 제일 아래에 위치한 Edit the collider geometry를 이용해 조절이 가능하다. 컴포넌트에서 직접 Size를 바꾸는 것도 가능하다. 위 사진에서 초록색 사각형이 Collider의 크기이다.

위 사진은 collider 컴포넌트의 구성 요소들이다. 여기서 IsTrigger 충돌했을때 트리거의 작동 여부를 설정해주는 것이다. IsTrigger가 Off되어 있으면 겹쳐지지 않는다. IsTrigger가 On되어있으면 오브젝트들이 겹쳐지고 겹쳐졌다는 이벤트가 발생한다. 그리고 여기서도 Eidt Collider를 통해 collider의 크기를 바꿀수 있다.

위 사진은 Rigidbody 컴포넌트의 구성 요소들이다. 여기서 Body Type은 Dynamic, Kinematic, Static 세가지가 있다. Dynamic은 중력과 힘의 영향을 받는다. Dynamic body는 모든 바디 타입과 충돌하는 가장 인터랙티브한 바디 타입이다. Kinematic body는 중력과 힘의 영향을 받지 않지만 사용자의 입력에 의해 제어되는 바디 타입이다. Static body는 전혀 움직이지 않도록 디자인되었다. 서로 충돌할 수도 없는 바디 타입이다. 그리고 Mass는 오브젝트의 질량, Gravity Scale은 오브젝트가 받는 중력의 정도이다.
만약에 게임에서 플레이어가 총을 쐈을때 다른 오브젝트와 충돌 여부를 판단할 때 매 프레임마다 실시간으로 계산하는 것은 계산량이 많아지기 때문에 쉽지않다. 그래서 Raycast라는 방법을 사용한다. 오브젝트에서 빛을 발사해서 그 빛이 다른 오브젝트에 닿는지 여부를 통해 충돌 여부를 판단한다.

Raycast를 테스트해보기 위해 위 그림과 같이 구, 캡슐, 사각형 오브젝트를 생성하고 아래에 대포에서 빛을 쏴서 빛이 닿는 오브젝트의 색을 변경하는 스크립트를 작성했다.


위 코드는 Raycast를 테스트하는 코드인데 먼저 발사 위치를 저장하기 위한 fireTrans를 선언해주고 위 오브젝트 사진에서 대포의 끝에 원의 자식 오브젝트로 빈 오브젝트를 하나 만들어준다. 그리고 스크립트를 원에 컴포넌트에 넣어주고 Inspector에서 스크립트의 Fire Trans에 발사 시작점인 이 빈 오브젝트를 넣어준다. 그리고 rotateDir는 좌우 방향을 기준으로 회전하게 되는데 Input.GetAxis("Horizontal")은 오른쪽 방향키(D키)를 누르면 0에서 1까지 양수의 값으로 증가하게 되고 왼쪽 방향키(A키)를 누르면 0에서 -1까지 음수의 값으로 감소하게 된다. 이걸 이용해서 대포가 z축 방향으로 회전해야하므로 rotateDir의 z 값에 Input.GetAxis("Horizontal")을 넣어준다. 그런데 -Input.GetAxis("Horizontal")인 이유는 오른쪽 방향키를 누르면 시계 방향으로, 왼쪽 방향키를 누르면 반시계 방향으로 회전해야하는데 오른쪽 방향키를 누르면 rotateDir의 z값이 커지는데 z축은 화면의 안쪽으로 들어가는 방향으로 증가하고 z값이 양수이면 반시계 방향으로 돌아가게 되므로 오른쪽 방향키를 눌러도 반시계 방향(원하는 방향과 반대방향)으로 회전하게 된다. 따라서 z값에 -Input.GetAxis("Horizontal")을 넣어 z값이 증가하면 반대로 감소하도록 해줘야한다. 그리고 RaycastHit2D는 많은 정보를 갖고있는데 부딪힌 지점, 부딪힌 오브젝트와의 거리, 법선 벡터등 정보를 갖고있다. 그리고 Physics2D.Raycast(fireTrans.position, fireTrans.TransformDirection(Vector2.up), 20.0f)에서 Raycast함수는 시작점, 방향, ray의 길이를 인자로 받는다. 그리고 마지막으로 hit.transform.GetComponent<SpriteRenderer>().color는 부딪힌 오브젝트의 transform을 hit이 저장하고 있으므로 그걸 이용해서 ray와 닿은 오브젝트의 색을 바꿔준다. 그리고 Raycast는 충돌과 관련된 것이므로 collider 컴포넌트를 대상 오브젝트에 넣어줘야한다.

UGUI
UGUI(Unity Graphic User Interface)는 유니티에서 제공하는 UI 시스템이다. UGUI는 Sprite Atlas관리가 편리하고 Canvas 단위로 Draw Call이 관리되며 각 UI 구성요소 간의 Depth 조절이 가능하다. 즉, 최적화가 좋다는 것이다. UI의 구성은 기본적으로 UI의 위치와 크기를 관리하는 RectTransform, UI가 그려지는 영역을 담당하는 Canvas, UI를 통해서 들어오는 이벤트를 처리하기 위한 EventSystem으로 구성되어있다. 그리고 UI는 Image, Button, Toggle, Text등 다양한 것들이 있다. Canvas는 UI의 모든 구성 요소를 배치하는 영역으로 RectTransform, Cnavas, CanvasScaler, GraphicRaycaster 등으로 구성되어있다. 하나의 Scene에 여러개의 Canvas가 존재할 수 있다. EventSystem은 UI의 구성요소가 상호작용에 반응하도록 이벤트를 받아주는 컴포넌트로 하나에 Scene에 하나만 존재할 수 있다. UI에서 그려지는 순서는 Hierarchy창에서 순서와 같다. 나중에 그려진것이 먼저 그려진 것 위에 그려지고, 부모 먼저 그려지고 나중에 자식이 그려진다.

UI를 처음으로 Scene에 넣으면 옆에 Hierarchy 창에 Canvas와 EventSystem이 자동으로 만들어지고 UI는 Canvas의 자식으로 만들어진다. Canvas의 Inspector에서 Renderer Mode를 선택할 수 있다. Renderer Mode에는 세 가지가 있는데 먼저 Screen Space - Overlay는 마지막으로 덮어씌우는 것이다. 그리고 Screen Space - Camera는 메인카메라로 Canvas의 사이즈가 맞춰지고 카메라와 UI 사이에 오브젝트가 있으면 가려진다. 마지막으로 World Space가 있는데 Canvas를 World Space 상에 배치하여 하나의 오브젝트처럼 취급한다. 모든 UI는 부모의 Anchors와 자기 자신의 Pivot으로 위치를 설정할 수 있다. Anchors와 Pivot은 정규화 되어있다.

위 그림과 같이 씬에서 현재 보이는 UI 이미지 사각형의 부모 Canvas의 앵커는 가운데에 바람개비 모양으로 보여진다. 그리고 사각형의 피벗은 (0.5, 0.5)로 사각형의 가운데이다. Canvas의 앵커가 원점(0, 0)이자 기준점이므로 사각형의 위치를 (0, 0)으로 하면 Canvas의 가운데에 위치하게 된다. 위 그림에서처럼 위치를 (-70, 0)으로 하면 앵커를 기준으로 x축으로 -70만큼 이동하게된다. 만약의 사각형에서 또 자식 UI를 만들게 되면 사각형의 앵커를 기준으로 자식 UI의 위치를 설정하게 된다.

Canvas의 Inspector에서 위 그림처럼 빨간 사각형을 누르게 되면 앵커의 프리셋이 나오게 된다. 그래서 앵커를 9가지 방향으로 프리셋내에서 정할 수 있다. 그리고 Stretch가 있는데 이것은 UI를 모서리에 맞춰서 늘리는 것이다.


Stretch로 앵커를 바꾸면 위 Scene의 사진과 같이 앵커가 길어지게 되고 그에 맞춰 이미지도 길어지게 된다. 그리고 Inspector의 내용도 바뀌게 된다. Left와 Right 항목이 새로 생기게 되는데 이것은 왼쪽, 오른쪽에서 각각 얼마만큼 띄울지를 결정하는 항목이다.


위 사진은 가로 세로 모두 Stretch를 하고 상하좌우로 각각 30만큼 간격을 띄운것이다. Stretch가 아닐때 UI의 크기를 바꿀 떄는 Scale이 아니라 Width와 Height로 크기를 조절해줘야한다. Scale항목은 크기를 가변적으로 변화시킬때, 예를 들어 게임에서 안내창이 커지면서 나타나는 것과 같이 UI의 원래 크기는 바꾸지않고 일시적으로 크기를 바꿀때 사용한다.
이미지
이미지는 Source Image 항목을 통해 이미지를 설정할 수 있다. 그리고 Image Type은 4가지가 있는데 하나는 Simple로 기본적으로인 설정이다. 그리고 slicing은 9-slicing 처럼 고정적으로 변하지 않을 부분을 설정해서 정해주는 것이다. 그리고 Tiled는 크기를 확대하면 Tile처럼 이미지가 반복적으로 보여지게 되는 것이다.

위 이미지가 Tiled를 적용하고 확대했을 때의 모습이다. 그리고 Filled는 이미지를 수치에 맞춰서 채우거나 비우는 것으로 게임으로 치면 HP나 MP바, 또는 스킬의 쿨타임을 나타낼때 볼 수 있다. Fill Method도 Horizontal, Vectical, Radial 90, 180, 360이 있다.

위 사진은 Radial 360과 Horizontal을 예시로 나타낸 것이다.
Text
유니티에서 텍스트는 텍스트를 이미지로 저장해서 필요할때마다 떼어서 쓰는 방식으로 적용된다.

그래서 한글을 쓰고 싶다면 한글을 지원하는 폰트로 이미지화 해줘야한다. Window->TextMeshPro->Font Asset Creator를 선택해서 Font Asset Creator 창을 열어주고 미리 다운받은 폰트를 Source Font File에 넣어준다. 그리고 Character Set을 선택하고 Custom Characters를 선택해주면 아래에 Custom Character List가 나온다. 그리고 게임에 쓸 단어들을 입력해줘도 된다. 하지만 모든 단어들 조합을 넣어줘도 되는데(완성형 한글2350자+자음+모음+영문자+특수기호, https://gist.github.com/taggon/a05af10cb9a38f201aefaacf3391e756) 이렇게 하면 용량이 커지기때문에 추천할 만한 방법은 아니다. 리스트를 작성하고 Generate Font Atlas를 눌러주면 완성이 되는데 이걸 저장해주면 된다. 그리고 모든 단어를 넣다보면 글씨가 깨지게 되는데 이때 Atlas Resolution의 크기를 키워주면 된다.

위 사진은 폰트를 적용한 모습과 Font Asset Creator의 모습이다.
Button
버튼은 단독으로 쓸 수 없다. 버튼은 이미지 컴포넌트와 버튼 컴포넌트로 이루어지며 자식으로 Text(TextMeshPro)를 갖는다. 버튼에 Inspector에서 Image 컴포넌트에 Raycast Target이 있는데 이것은 클릭의 대상이 될지 여부를 판단하는 것이다. Raycast Target이 체크되면 클릭으로 상호작용이 가능하고 체크가 해제되면 클릭으로 상호작용이 불가능하다. 이 기능은 UI가 여러개 겹쳐있을때 상호작용이 될 UI를 선택하는데 도움이 된다.

위 사진은 버튼 컴포넌트의 요소들이다. Interactable은 말그대로 상호작용 가능 여부에 대한 것으로 체크를 풀면 아예 상호작용이 불가능하다. 그리고 Transition은 상호작용을 어떻게 표시할 것인지에 대한 것이다. None으로 아예 구분이 없을 수도 있고, Color Tint로 상호작용을 색깔로 표시할 수 있다. 그리고 Sprite나 Animation을 이용해서 상호 작용을 표시할 수 있다. Color Tint로 버튼의 상태에 대해서 알아보자. 먼저 Normal은 일반적인 상태를 가리킨다. 그리고 Highlighted은 마우스가 버튼 위로 올라갔을때 상태를 가리킨다. 그리고 Pressed는 버튼이 클릭되었을때, 그리고 Selected는 버튼이 선택되었을 때 즉, 마지막에 선택한 버튼이라는 것을 나타낸다. 그리고 Disabled는 비활성화 상태를 나타낸다. 그리고 Fade Duration은 Highlighted 상태에서 색깔이 변하는 시간을 나타낸다. 시간이 길수록 색이 서서히 변한다. 버튼을 테스트하기 위해 버튼을 누르면 오브젝트의 색깔이 변하는 예제를 만든다.

버튼을 테스트하기 위해 가운데에 사각형 오브젝트를 하나 만들어주고 누르면 사각형 오브젝트의 색깔이 바뀌는 버튼 세개를 만들어준다.

위 소스코드는 버튼 테스트에 대한 스크립트이다. 먼저 스크립트에서 UI에 대해 접근하려면 using UnityEngine.UI 네임스페이스를 선언해줘야한다. 그리고 Inspector에서 색깔에 접근할 수 있도록 Color 구조체를 멤버변수로 선언한다. 그리고 Button에 대해 접근할 수 있는 멤버변수 btn도 선언해준다. 그래서 Awake함수 내에서 GetComponent<Button>()으로 버튼 컴포넌트에 접근한다. 그리고 버튼이 클릭됐을때 호출할 함수를 인자로 받는 OnClick.AddListener함수를 선언해서 버튼이 클릭됐을때 이벤트에 대한 행동을 다룬다. AddListener함수는 지정된 함수를 호출하는 함수이다. 버튼이 클릭됐을때 OnClick_ColorChange()함수를 선언해서 지정한 색깔로 바뀌게 설정한다. 그리고 해당 스크립트를 각 버튼에 넣어준다.

위 그림과 같이 버튼의 스크립트 컴포넌트에서 바뀔 색을 선택할 수 있다. 이제 게임을 실행하면 사각형 오브젝트를 찾고 사각형 오브젝트가 있을때 그 색을 검은색으로 바꾼다. 그리고 버튼에 따라서 지정된 색으로 사각형의 색을 바꾼다.

Toggle
Toggle은 한 번 누르면 이벤트가 발생하는 버튼과 다르게 On/Off 형식으로 효과가 지속된다.


위 실행 화면과 소스코드는 토글을 테스트하는 것으로 토글 버튼을 누르면 값이 True로 해제되면 값이 False로 유지되는 것을 볼 수 있다. 소스코드에서 버튼과 다른 것을 볼 수 있는데 TryGetComponent함수의 사용이다. GetComponent는 해당 오브젝트에 찾고자하는 컴포넌트가 없으면 유니티엔진에서 에러가 뜬다. 게임을 실행해도 오류로 인해 실행이 안된다. 그러나 TryGetComponent함수를 사용하면 오류가 뜨지않고 그냥 넘어간다. TryGetComponent함수는 bool값을 반환한다. 그리고 TryGetComponent의 인자는 대상이 될 컴포넌트가 들어간다. 즉, TryGetComponent에서 컴포넌트를 찾아 인자에 저장한다. 그리고 토글에서는 이벤트의 이름이 onValueChanged로 이름이 다른데 이벤트의 이름은 각각 컴포넌트에서 확인할 수 있다. 버튼의 이벤트의 이름은 onClick이다.

그리고 AddListener에서 처리하는 함수의 인자값도 다르다. 위 코드에서 토글의 이벤트 처리 함수 OnValueChanged_Toggle에서 인자로 bool값을 받아와 bool값을 처리한다. 토글 컴포넌트에서 인자도 확인할 수 있는데 OnValueChanged(Boolean)라고 되어있어 어떤 값을 받아와 처리하는지 알 수 있다. 그에 반에 버튼은 OnClick()이므로 void로 되어있어 아무것도 받아오지 않는다. 토글은 텍스트도 갖고있지만 TextMeshPro가 아니다.
Slider
Slider는 미리 정해진 값의 범위 내에서 Handle을 마우스 드래그를 통해서 값을 바꾸는 UI 오브젝트이다.

슬라이더의 구성은 배경의 바와 드래그로 값을 조정할 수 있는 핸들, 그리고 핸들이 지나온 곳을 나타내는 Fill Area가 있다. Slider 컴포넌트에서는 버튼처럼 각 이벤트 별로 색깔이나 sprite등을 설정할 수 있고, Fill Area의 모양과 Handle의 모양을 설정할 수 있다. 그리고 Direction에서 어느 방향으로 슬라이더가 진행될지(값이 증가하는 방향)을 설정할 수 있다. 그리고 MinValue와 MaxValue를 정할 수 있다. 여기서는 현재 MinValue가 0이고 MaxValue가 1이다. 그리고 Whole Numbers를 체크하면 슬라이더가 정수값으로만 지정된다. 슬라이더의 이벤트 이름은 On Value Changed로 실수값을 인자로 받는다.

슬라이더를 테스트하는 스크립트인데 토글과 비슷하다. 현재 MinValue가 0이고 MaxValue가 1이므로 0과 1사이의 값을 받아서 처리한다. 그래서 사운드 볼륨이라고 했을때 볼륨은 0부터 100까지라고 설정해서 전달하는 실수값에 100을 곱해줬다. 그리고 :F1을 통해서 소수 첫째자리까지 나타냈다.
사운드(Audio)
유니티에서 오디오는 일상 생활에서 사람이 소리를 듣는 방식과 비슷한 방식으로 구현되었다. 현실에서는 주변에서 다양한 상황에 대해 다양한 소리들이 발생하고 사람은 공기를 통해 전달되는 소리를 귀를 통해 인식하게된다. 월드에 오브젝트로 사운드가 발생하는 Audio Source가 존재하고 Audio Listener로 듣게 된다. 기본적으로 메인 카메라에 오디오 리스너가 있다.

위 사진은 Audio Source 오브젝트에 Audio Source 컴포넌트이다. Audio Clip 항목은 어떤 사운드를 재생할지 설정하는 항목이다. 그리고 Mute는 음소거, Play On Awake는 게임이 시작될 때 사운드를 시작할 것인지를 결정한다. 그리고 Loop는 사운드를 반복해서 재생할 것인지를 결정한다. 그리고 Priority(우선순위), Volumn, Pitch등을 정할 수 있다. Stereo Pan은 사운드가 왼쪽에서 들릴것인지 오른쪽에서 들릴 것인지를 정한다(스테레오 사운드). 오디오를 테스트하기 위해 버튼 자체에다가 Audio Source 컴포넌트를 만들고 버튼을 클릭하면 오디오가 나오도록 테스트해봤다.

버튼 테스트 스크립트와 비슷하다. TryGetComponent<AudioSound>가 없을 때 오류 메세지를 발생시키고 버튼이 클릭됐을때 AudioSource의 Play()함수를 통해 소리를 출력한다.
똥피하기 게임 만들기 - 1
지금까지 배웠던 것들을 정리해서 간단한 똥피하기 게임을 만들어본다. 먼저 Game 뷰에서 화면의 크기를 1080x1920으로 바꿔준다.

그리고 이번엔 전체 이미지 PNG에서 이미지를 잘라서 타일로 써보겠다. 먼저 스프라이트의 Inspector에서 Sprite의 모드를 Multiple로 바꿔준다. 그럼 이제 Sprite Editor에서 스프라이트를 나눌 수 있다. 스프라이트에서 사용할 부분을 사각형으로 선택해주고 Apply를 누른다.

그리고 Tile Map과 Tile Palette를 만들어서 바닥을 그려준다. 그리고 배경을 하나의 스프라이트를 골라서 Draw Type을 Tiled로 바꿔서 배경을 그려준다.

여기서 스프라이트들이 그려지는 순서가 중요하다. 각 오브젝트마다 Order in Layer(그려지는 순서)가 있는데 그 숫자가 낮을수록 먼저 그려진다. 나중에 그려지는 스프라이트가 먼저 그려지는 스프라이트를 가린다. 그래서 스프라이트가 뒤에 있을수록 Order in Layer의 숫자가 낮아야한다. 그래서 뒤에 초록 배경의 Order in Layer를 20, 앞에 TileMap의 Order in Layer를 50으로 설정해주었다. 그리고 Player를 스프라이트를 골라서 넣어준다. 그리고 이제 플레이어의 애니메이션을 설정해준다. 지금 게임에서는 가만히 있을때(Idle)와 달릴때(Run) 두 가지 애니메이션을 만들어준다. 그리고 애니메이션의 설정을 살펴보자.

Entry가 기본 상태이고 지금은 Transition을 통해 Player_Idle 애니메이션에 연결되어있다. 플레이어가 달릴 때 Player_Idle에서 Player_Run으로, 달리다가 멈췄을 때 Player_Run에서 Player_Idle로 애니메이션을 바꿔줘야하므로 Transition을 서로에게 연결시켜준다. 애니메이션을 변경하기 위한 파라미터를 Animator 창의 Parameters에서 설정할 수 있다.

파라미터로는 float, int, bool, trigger가 있다. trigger는 이벤트가 발생했을때 애니메이션을 한번만 실행시키고 끝낸다. 여기서는 캐릭터의 스피드로 애니메이션을 변경하기 위해서 파라미터로 float값을 갖는 Speed를 설정해준다. 그리고 애니메이션의 Transition의 Inspector에서 coditions에 Speed에 관련된 조건을 설정해준다. Player_Idle에서 Player_Run으로 바꿀때 Speed가 0.1보다 커야되므로 Speed를 Greater 0.1로 설정해주고 Player_Run에서 Player_Idle로 바뀔때는 0.1보다 작아야되므로 Speed를 Less 0.1로 설정해준다.

그리고 Transition에 Inspector에서 Has Exit Time은 현재 진행중인 애니메이션이 일정시간이 지날때까지 기다렸다가 다음 애니메이션으로 넘어가도록 하는 옵션이다. 그래서 Codition의 조건이 바뀌어도 일정 시간이 지나야 끝나고 다음 애니메이션으로 바뀌기 때문에 이 게임에서는 이것을 옵션을 꺼주었다. 그리고 Settings를 열면 Transition Duration이라는 항목이있는데 두 개의 애니메이션을 일정 시간동안 섞어서 움직임이 자연스럽게 변하도록 설정하는 것인데 2D 스프라이트에서는 제대로 적용이 되지 않으므로 0으로 설정해준다. 그리고 이제 키보드로 캐릭터의 움직이는 스크립트를 만들어준다. 이 스크립트에서는 캐릭터의 애니메이션의 변경 조건도 설정해준다.

위 사진이 플레이어의 움직임에 대한 스크립트이다. Animator 컴포넌트에 접근해서 SetFloat함수를 통해 Transition의 Condition인 Speed에 접근해서 키보드로 입력받은 moveDir의 값에 따라 Speed를 변화시켜 애니메이션을 바꾼다. 그리고 플레이어 캐릭터가 오른쪽으로 갈때는 오른쪽을 보고 왼쪽으로 갈때는 왼쪽을 보도록 flipX를 이용한다. flipX는 스프라이트의 좌우반전 flipY는 상하반전이다. 여기서 캐릭터 플레이어는 기본적으로 오른쪽을 보고있기 때문에 moveDir가 양수일때 즉 0.1보다 클때는 반전을 시키지 않고 moveDir가 음수일때 왼쪽으로 이동하는 것이되므로 flipX를 true로 바꿔서 좌우 반전을 시킨다. 그리고 moveDir와 transform.position을 이용해서 캐릭터를 이동시킨다.

그리고 이제 플레이어가 피해야할 Saw라는 오브젝트를 만들어준다. 그리고 플레이어와 땅, 그리고 하늘에서 떨어지는 톱날 오브젝트에 대해서 각각 충돌을 처리해야하므로 Rigidbody와 collider 컴포넌트를 넣어준다.

위 사진은 각 오브젝트의 collider 범위를 보여준다. 그리고 collider에서 IsTrigger를 모두 체크해준다. 위에서 말했듯이 IsTrigger를 체크하면 오브젝트끼리 겹쳐지고 겹쳐졌을때 충돌 이벤트를 발생시킬수 있다. IsTrigger를 체크를 해제하면 오브젝트끼리 겹치지 않는다. 그리고 피해야할 오브젝트 Saw에 AudioClip 배열을 넣어서 Saw가 Player와 부딪혔을때 소리와 Ground에 떨어졌을때 소리를 설정해준다.

위 소스코드는 Saw에 대한 스크립트인데 먼저 Saw 오브젝트에 AudioSource 컴포넌트를 추가해주고 스크립트에서 AudioClip에 대한 배열을 만들어서 각 상황에 맞는 AudioClip을 선택해서 AudioSource에서 재생하도록 했다. 그리고 캐릭터와 바닥에 Saw가 닿으면 두 가지의 소리가 나는 것을 방지하기 위해서 Saw의 state를 설정해서 플레이어나 바닥에 한 번이라도 닿으면 Saw의 state인 isAlive를 false로 만들어 소리가 한 번만 나도록 설정했다. 그리고 isAlive가 false가 되고 1초 있다가 사라지도록 coroutine을 통해서 설정했다. coroutine에 대해서는 나중에 더 자세히 배울 예정이다. 그래서 지금까지는 배경 설정, 애니메이션 설정, 오브젝트의 collider 설정, 그리고 Saw의 Trigger와 Audio 설정을 마쳤다. 점수에 대해서는 다음에 더 구현하기로 한다.