Unity - Week 02

이응민·2024년 12월 2일

Unity

목록 보기
2/12

스크립트로 오브젝트 생성

먼저 Circle 오브젝트를 프리팹으로 설정해주고 빈 오브젝트를 하나 만들어서 거기에 오브젝트를 생성하는 스크립트를 컴포넌트로 추가해준다. 그리고 [SerializeField]를 이용해 Circle 프리팹을 Inspector에서 적용할 수 있다.

위 코드에서 random 클래스를 이용해 특정 범위 내에서 원이 생성되도록 설정했고 쿼터니언을 이용해 원이 z축 방향으로 30도 회전돼서 생성되도록 설정했다. 그리고 Instantiate함수는 오브젝트를 생성하는 함수인데 함수의 인자로 먼저 오브젝트, 위치, 회전을 받았는데 인자를 바꿔 적용할 수 있다.

스크립트로 오브젝트를 생성 후 움직이게 하는 방법은 오브젝트를 생성한 후 해당 프리팹에 움직이는 스크립트를 따로 생성해서 하나의 스크립트가 하나의 역할만 할 수 있도록 해준다.

오브젝트 생성 스크립트

오브젝트 이동 스크립트

위 코드에서 transform.Translate함수 내에 있는 transform.up 변수는 해당 오브젝트의 local space 내에서 y축 방향을 가리키고 있으므로 오브젝트의 회전 방향을 포함하고 있다. 그래서 이동할때 회전된 방향으로 오브젝트가 이동한다.

오브젝트 찾기

오브젝트는 스크립트 내에서 GameObject.Find("Object")로 찾을 수 있지만 성능이 좋은 함수는 아니다. 게다가 이름으로 찾는 함수이기 때문에 이름이 바뀐다면 찾기 어려울 수 있다. 그리고 오브젝트의 Inspector에서 Tag를 통해 오브젝트들을 그룹화할 수 있는데 스크립트에서 GameObject.FindGameObjectWithTag("Tag")를 통해 찾을 수 있다(여러개의 오브젝트를 찾을 때는 GameObject.FindGameObjectsWithTag("Tag")를 사용한다).

입력 데이터 처리

키보드 입력은 Update에서 처리한다. Input 클래스에서 키보드의 입력은 세 가지로 다룰 수 있는데 GetKey(누르고 있음), GetKeyDown(누름), GetKeyUp(뗌) 이렇게 세 가지 함수가 있다. 먼저 캐릭터의 이동을 키보드로 다뤄보자. 유니티에서는 Input Manager가 있는데 게임에서의 몇 가지 기본적인 행동들을 정의하고 그 행동의 이름과 그에 대한 입력값 정해두었다. 따라서 프로그래머는 그것을 이용하면 된다.

void Update()
{
    if (Input.GetKeyDown(KeyCode.Space)) // 최초로 눌리는 프레임에 true 반환
    {
        Debug.Log("스페이스 바가 눌림");
        timeCheck = Time.time;
    }
    if (Input.GetKey(KeyCode.Space))
    {
        Debug.Log("스페이스 바가 눌려있음");
    }
    if (Input.GetKeyUp(KeyCode.Space))
    {
        Debug.Log("스페이스 바가 떼어짐");
        Debug.Log(Time.time - timeCheck);
    }
}

위 코드는 키보드의 입력 함수를 정리한 것이다. 위 함수를 이용해서 아래와 같이 코드를 짤 수 있다.

GameObject obj;
void Start()
{
    obj = GameObject.Find("people");
}
void Update()
{
    if (Input.GetKeyDown(KeyCode.Space))
    {
        obj.GetComponent<SpriteRenderer>().color = Random.ColorHSV();
    }
}

위 코드는 오브젝트를 찾아 스페이스를 눌렀을 때 오브젝트의 색깔을 랜덤하게 바꾸는 코드이다.
Input Manager에서 반환값은 -1부터 1까지이다.

float inputX = Input.GetAxis("Horizontal"); // 가로축 [-1, 1]
float inputY = Input.GetAxis("Vertical"); 	// 세로축 [-1, 1]

float inputX = Input.GetAxisRaw("Horizontal"); // 가로축 -1 또는 1
float inputY = Input.GetAxisRaw("Vertical");   // 세로축 -1 또는 1

위 함수들은 좌우 이동을 키보드로 입력 받는 것을 나타낸 것이다. 가로축으로 이동은 "Horizontal"이라는 키워드를 사용해서 Input Manager와 연결할 수 있고 입력값은 -1부터 1까지인데 Input.GetAxis함수는 키보드를 눌렀을 때 0부터 1까지 서서히 올라가고(빠르다) 키보드를 땠을때 1부터 0까지 서서히 내려간다. 캐릭터가 갑자기 멈추는 것이 아닌 서서히 멈춘다. 그래서 관성이 있는 마리오 같은 게임에서 볼 수 있다. 그에 반해 Input.GetAxisRaw함수는 0에서 바로 1로 가기 때문에 바로바로 움직인다. 그래서 "Horizontal"과 "Vertical"을 각각 입력받아 이동 방향의 벡터의 가로축 이동값(x값)과 세로축 이동값(y값)으로 사용할 수 있다. 그리고 캐릭터 이동을 다룰 때 CharacterController 클래스를 사용하는데 이것은 캐릭터 이동간의 충돌을 다룰 수 있다.

캐릭터의 이동 방향을 moveDir라는 벡터로 정하고 입력받은 x, y값을 저장한다. 그리고 방향 벡터를 정규화해서 길이가 1인 벡터로 만들어 어느 방향을 보더라도 같은 속도로 이동할 수 있도록 한다.

마우스의 입력은 Input.GetMouseButtonDown 함수를 통해서 입력 받을 수 있다. 함수의 인자로는 0, 1, 2 등 양의 정수가 들어가는데 0은 왼쪽 클릭, 1은 오른쪽 클릭, 2는 휠 클릭, 3부터는 마우스의 커스텀 키입력을 받는다. 그리고 Input.MousePosition은 마우스의 위치 값을 갖고있다. 여기서 마우스의 위치값은 screen space 상의 좌표지만 오브젝트의 좌표값은 world space에서 계산되어야 한다. 원래라면 screen space 좌표에서 view-port space 좌표로 변환하고, view-port space 좌표에서 world space상의 좌표로 변환하는 과정을 거쳐야하지만 유니티에서는 함수로 제공해준다. Camere.main.ScreenToWorldPoint(Input.mousePosition) 함수를 이용해서 screen space에서의 마우스 좌표를 world space에서의 좌표로 나타낸다. 그런데 screen space는 2차원 공간이므로 world space의 좌표로 바꿀 때 z 값은 카메라 위치의 z값이 된다. 왜냐하면 z 값은 world space에서 카메라로부터의 거리를 나타내는데 거리에 0이 인자로 들어가게 되므로 world space로 바꿀때 z 값은 카메라 위치의 z값이 된다. 따라서 z 값은 현재 오브젝트의 z 값으로 정해줘야한다.

위 코드에서 targetPos.z = transform.position.z;로 z 값을 현재 오브젝트의 z 값으로 정해주었다. 그리고 마우스 우클릭으로 오브젝트를 이동하도록 했는데 이때 transform.position을 이용한 포지션은 오브젝트의 위치를 바로 바꿔주는 것이다. 하지만 선형 보간을 이용해서 오브젝트의 이동을 구현하면 원하는 위치까지 움직이는 것을 볼 수 있다. 선형 보간은 수학적으로는 두 점이 주어졌을때 그 사이에 위치한 값을 추정하기 위해 직선거리에 따라 선형적으로 계산하는 방법이다.

위 식에서 d1d_1는 0과 1사이의 값이다. 이번에 사용한 Vector3.lerp함수는 벡터의 선형 보간 함수인데 인자로는 처음 첨, 끝 점, 그리고 t라는 [0, 1]의 범위를 갖는 값이다. 따라서 deltaTime 동안 계속 t의 값이 업데이트되면서 처음 점과 끝 점 사이의 값으로 오브젝트의 위치가 바뀌면서 이동하는 것처럼 보이는 것이다.

위 실행화면에서 보는 것처럼 이동하는 와중에 다른 곳을 찍으면 실시간으로 가야되는 위치가 바뀌게 되므로 이동하는 방향이 바뀐다.

마우스의 드래그의 이동은 world space에서 오브젝트가 차지하고 있는 물리적인 부분을 설정해야한다. 따라서 오브젝트에 collider component를 추가해야한다. 그리고 OnMouseDown, OnMouseUp 유니티 메세지를 이용해서 물리적으로 오브젝트를 선택했을 때 오브젝트가 선택됐음을 설정해줘야한다.

위 코드에서 보이는 것처럼 오브젝트가 선택됐을때 isSelect가 true가 되어야하는데 유니티 메세지를 이용해서 isSelect 여부를 선택한다.

다음으로는 충돌을 포함한 이동이다. transform.position을 이용한 이동은 단순한 좌표 바꾸기지만 CharacterController를 이동하면 오브젝트에 물리적인 상호작용을 위한 캡슐이 생긴다. 따라서 충돌까지 구현할 수 있다. 이것을 사용할 때는 collider 2D 컴포넌트를 꺼줘야한다.

2D 이미지(스프라이트)

유니티에서 2D 그래픽 오브젝트는 스프라이트(sprites)라고 한다. 스파라이트 렌더러(sprite renderer) 컴포넌트를 통해서 화면에 스프라이트를 렌더링하고 씬에서 표시되는 결과물을 제어한다. 직교(othographic) 좌표계와 원근(perspective) 좌표계가 있는데 직교 좌표계에서는 원근감이 없이 물체가 멀리 있던 가까이 있던 원래 크기로 보여지고 원근 좌표계에서는 거리에 따라 오브젝트의 크기가 달라진다. 스프라이트에서는 collider 2D를 사용해 2D 오브젝트의 충돌 영역을 따로 설정해줘야한다.

9-슬라이싱(9-slicing)

9슬라이싱은 여러 에셋 필요없이 다양한 크기의 이미지를 재사용할 수 있게 해주는 기술이다. 이미지를 9개 부분으로 슬라이싱해서 스프라이트의 크기를 재조정할때 스프라이트가 비례를 유지할수 있도록 다른 방법으로 확대하거나 타일링할수 있도록 하는(격자 모양으로 반복) 가능도 있다.

위 그림처럼 스프라이트를 9개의 구간으로 나눠서(slicing) A부터 I까지 문자를 붙여놨다. 아래의 사항들은 이미지의 크기를 변경할 때 각 문자별 상황이다.

  • 네 개의 코너(A, C, G, I)는 크기를 변경하지 않는다.
  • B와 H는 수평으로 늘어나거나 타일한다.
  • D와 F는 수직으로 늘어나거나 타일한다.
  • E는 수평과 수직 방향 모두로 늘어나거나 타일한다.

이미지에 9-슬라이싱을 적용하기 위해서 원본 이미지에서 Inspector에 sprite editor를 눌러준다.

그리고 초록색 점을 이동해서 영역을 나눠준다.

그럼 9-슬라이싱이 적용된 것이다.

타일 맵

타일 맵은 스프라이트를 타일 형태로 제작 후 타일과 같이 배치하여 게임 월드를 표현하는 방식이다. 먼저 Tile Palette은 타일 맵에 사용될 타일들을 미리 등록해두는 저장소이고 Tile Asset은 Tile Palette에 등록될 리소스들이다. Grid Object에서 타일 맵의 오브젝드들을 관리하고 Tilemap Object는 Tile Asset을 실제로 배치하는 공간으로 타일 형태의 게임 월드이다. 즉, Tile Palette에 등록해둔 Tile Asset들을 Tile Object에 배치해서 맵을 구성하고 이를 Gird Object가 관리하는 것이다.

타일 맵을 만들때 카메라와 EventSystem(UI->EventSystem)이 필요하다. Asset에다가 폴더를 하나 만든다. 그 폴더를 들어가서 Tile Palette(Rectangular)를 하나 만들어준다.

아래 그림은 Tile Palette를 클릭했을때 나오는 화면이다.

그리고 Open Tile Palette를 눌러준다.

그래서 Asset에서 미리 다운받은 타일을 드래그해서 등록해준다.

그리고 Hierarchy 창에서 Tile Map(Rectangular)을 생성해준다.

그리고 타일 맵에 팔레트를 이용해서 그려보면 그리드보다 타일이 크다. 유니티에서는 거리가 1 유닛으로 설정되는데 현재 설정으로 1 유닛당 100px을 그리도록 설정되어 있으므로 타일을 클릭해서 Inspector 창에서 타일 크기 512px에 맞게 1 유닛당 512px을 그리도록 설정하면 하나의 그리드에 하나의 타일이 들어가게 된다.

그리고 Tile Palette에서 Tile을 골라서 그려주면 된다.

2D 애니메이션 방식

2D 애니메이션의 표현 방식은 3가지가 기본 제공된다. 프레임 바이 프레임(frame by frame), 컷 아웃(cut out), 본 애니메이션(bone animation)이다. 프레임 바이 프레임 방식은 프레임마다 동작을 정해서 순서대로 애니메이션을 재생하는 방식이다. 컷 아웃 방식은 오브젝트, 캐릭터를 조각조각 잘라서 각각 움직이도록 하는 방식이다. 그리고 본 애니메이션 방식은 캐릭터 안에 뼈대를 만들어서 하나가 움직이면 같이 움직이도록 설계하는 것이다.

0개의 댓글