🤍ref.

  1. Unity Learn John Lemon’s Haunted Jaunt: 3D Beginner

  2. Unity Documentation

✨Unity info
본 튜토리얼 문서의 유니티 버전은 2020.3v이나, 2021.3v으로 실습 후 게시글을 작성하였습니다.



플레이어 캐릭터: 1부



1. 캐릭터 모델

게임에 사용할 모델은 주로 Unity 외부에서 제작한 후 임포트해 해당 기능 활용 (존 레몬 튜토리얼에서는 3D 모델을 사용해 게임을 제작)

  • 인스턴스: 모델을 게임 오브젝트화함
    • 모델을 게임 오브젝트로 추가 => 모델의 인스턴스 생성


인스턴스 생성 방법

  1. 프로젝트 창에서 모델을 찾아 Scene view로 드래그
    • 모델을 정확히 원하는 위치에 배치할 수 있다 !
    • 모델을 Hierarchy view에 드래그하면 기본 포지션에서 게임 오브젝트 생성 가능
  2. Scene view 위에 커서를 놓고 F키를 눌러 초점을 맞춘다


JohnLemon 자식 오브젝트 - JohnLemon, Root

  • JohnLemon 오브젝트
    • Skinned Mesh Renderer : 컴포넌트를 통해 캐릭터를 볼 수 있다. => Mesh Renderer의 특별한 유형. 모델 뼈대 전체의 포지션과 회전을 기반으로 메시 모양 변경
      • 뼈대? 모델의 자식 게임 오브젝트 => JohnLemon의 뼈대는 모두 Root 게임 오브젝트의 자식임
      • Mesh Renderer: 삼각형의 mesh를 render해 볼 수 있도록 함
  • Root 오브젝트
    • Hierarchy view에서 ALT(Windows) / Option(macOS)를 누른 상태로 화살표를 클릭하면 모든 자식 오브젝트를 펼칠 수 있다 !
    • 각각의 자식 오브젝트들은 JohnLemon 바디의 일부를 구성
      • 해당 뼈대 오브젝트를 조절해 오브젝트에 움직임을 줄 수 있다 !
    • JohnLemon 캐릭터는 부모 게임 오브젝트의 Animator 컴포넌트가 모든 뼈대 오브젝트의 Transform 값 변경
      • 해당 변경사항들이 함께 작용해 캐릭터를 애니메이션화함


frame: 영상이 전환되면서 초 단위로 바뀌는 이미지들

rendering: 프레임이 화면에 표현되도록 하는 과정


2. 프리팹이란?

게임 오브젝트 또는 이미 설정된 컴포넌트가 있는 게임 오브젝트의 컬렉션을 나타내는 에셋

  • 동일한 사물의 인스턴스를 만드는 데 사용
  • 프리팹의 인스턴스를 각각 프리팹 에셋에 연결됨
    • 에셋을 변경하면 모든 씬에서 프리팹의 모든 버전이 변경


유니티에서 모델은 읽기 전용 프리팹처럼 작동한다 !

  • 읽기 전용 프리팹은 프리팹 자체 변경 불가능


읽기 전용 프리팹을 변경하고 싶을 때는 어떻게 해야 할까? => 조정이 가능한 새로운 프리팹을 만들어 저장하자 !

Hierarchy 에 있는 게임 오브젝트를 Project 창의 폴더로 드래그하면 프리팹으로 변환된다. 프로젝트를 간결하게 유지하기 위해 모든 프리팹들은 한 폴더에서 관리하자.


image

  • Original Prefab: 원본 프리팹. 해당 모습을 바탕으로 하는 독립적인 prefab 생성
    • 해당 프리팹에 대한 모든 변경 사항이 scene에 있는 프리팹 인스턴스에 반영
  • Prefab Variant: 기본 prefab의 property를 상속받은 후 추가 구현 기능 override
    • prefab variant에 적용된 override는 기본 prefab의 값보다 우선시됨


image

Inspector 창의 Open을 눌러 Unity 에디터를 프리팹 모드로 전환할 수 있다


image

프리팹 모드로 전환한 scene view

  • Scenes | JohnLemon: 현재 프리팹 모드에서 수정되고 있는 프리팹의 경로
    • 뒤로 이동할 경우 수정 중이던 씬으로 되돌아감
  • Auto Save 버튼은 되도록 비활성화하자 !
    • 활성화할 경우 에디터 속도저하

3. 캐릭터 애니메이션화

해당 튜토리얼에서는 걷기 애니메이션(walking animation)과 대기 애니메이션(idle animation)을 적용


Animator 컴포넌트 구조

  • Controller: 애니메이션 클립에 대한 레퍼런스를 가지고 있다 ! 다양한 애니메이션 상태 및 전환 관리
    • 상태 머신: Animator 컴포넌트가 특정 시간에 어떤 애니메이션을 설정해야 하는지 결정
      • 애니메이터 컨트롤러에서 설정된 애니메이션 클립을 기반으로 함



3.1. 애니메이터 컨트롤러

Project 창에서 [Create] -> [Animator Controller] 를 통해 애니메이터 컨트롤러 생성 가능

image

애니메이터 창의 첫 로드 화면

  • 왼쪽 패널: 애니메이터 레이어 및 애니메이터 파라미터 수정
  • 상태 머신 표시


애니메이터 파라미터는 스크립트에 의해 값이 설정되며, 상태 머신은 이러한 파라미터의 현재 값에 따라 결정을 내린다. 캐릭터가 애니메이션에 영향을 줄 수 있는 하나의 독립 변수마다 파라미터 하나가 필요하다.


애니메이터 파라미터 유형

  • float
  • int
  • bool
  • trigger: 값을 갖지 않는 형태. 한 애니메이션에서 다른 애니메이션으로의 변환 유발

각 애니메이션의 조건에 맞게 알맞은 파라미터를 설정한다. 예를 들어, John Lemon캐릭터는 걷거나 정지하는 애니메이션만 수행하므로 bool 파라미터가 가장 적절하다.


애니메이터 컨트롤러에서 애니메이션 에셋을 사용하기 위해 Project 애니메이션을 애니메이터 창으로 드래그한다.

Project 창에서 John에 대한 애니메이션 (각각 John@Idle, John@Walk)을 펼치면 서브 에셋을 확인할 수 있다.

  • 서브 에셋은 부모 게임 오브젝트의 직계 자식, 메시, 애니메이션을 보여줌

애니메이션은 애니메이터 상태(Animator States)의 애니메이터 컨트롤러에 있다 !

  • Animator States: 애니메이터 컨트롤러에 포함된 상태 머신의 일부
    • 상태 머신이 현재 상태를 어떤 상태로 할지 결정 -> 현재 상태는 플레이할 애니메이션 결정

image

  • 기본 상태: 주황색으로 표시
    • 기본 상태를 변경하려면 마우스 오른쪽 버튼 -> Set As Layer Default State 선택
    • 예제에서는 먼저 드래그한 John_Idle이 기본 상태

어떤 상태가 플레이되어야 할지 결정되지 않았으므로, 로직을 추가해 애니메이터 전환(Animator Transitions)을 만들어야 한다.



3.2. 애니메이터 전환 만들기

애니메이터 전환을 만드는 방법

  1. 오른쪽 마우스로 애니메이터 상태 클릭 -> Make Transition
    • 마우스 커서를 따라 전환 시작
  2. 전환 생성을 마치기 위해 John_Walk 상태 클릭
  3. 걷기에서 대기 상태로 전환이 가능하도록 1, 2과정 반복


image

상태 머신이 언제 애니메이터 상태가 전환될지 알 수 있도록IsWalking 파라미터를 활용해보자

  • John_Idel 에서 John_Walk 로의 연결선을 클릭 후 Inspector에서 해당 상태 전환의 설정 확인
    • Has Exit Time: 활성화될 경우 일정 시간 후 자동으로 상태 전환 수행
      • 캐릭터의 대기 상태와 걷기 상태가 입력에 따라 제어되어야하므로 비활성화
  • Condition을 추가해 애니메이터 전환 생성


Animation Transitions에 Condition 추가

image

  • Inspector에서 [Conditions] -> + 버튼을 클릭한 후 상태에 맞게 전환값 조정
    • John_Idle -> John_Walk: IsWalkingtrue로 설정
    • John_Walk -> John_Idle: IsWalkingfalse로 설정

JohnLemon 프리팹에 애니메이터 컨트롤러 할당

  1. Hierarchy view에서 JohnLemon 게임 오브젝트를 선택
  2. 애니메이터 컨트롤러를 Inspector view의 Animator 컴포넌트 -> Controller 프로퍼티로 드래그
  3. AutoSave를 비활성화했을 경우, Scene 창 오른쪽 상단의 Save 버튼 클릭



4. 캐릭터 애니메이션 개선

4.1. Rigidbody

캐릭터가 물리에 반응하도록 한다.

  • Rigidbody: 게임 오브젝트를 이동 가능한 물리 시스템의 한 부분으로 표시

    • 캐릭터가 움직이고 벽을 통과하지 못하는 등 물리적 속성 부여

    • Inspector 창에서 Rigidbody 컴포넌트를 추가할 수 있다 !

      본 튜토리얼은 3D프로젝트이므로 Rigidbody 2D컴포넌트를 추가하지 않도록 주의하자.


Root Motion

애니메이션의 이동 및 회전은 대부분 부모 오브젝트와 연관되어 발생한다. 그러나 Root 오브젝트는 부모가 없으므로 움직임에 영향을 받지 않는다. 이러한 Root 오브젝트의 움직임을 Root Motion이라고 한다.

  • Root Game Object != Prefab - Root Object
    • 프리팹 계층에서의 루트 오브젝트: 골격의 루트
    • 루트 게임 오브젝트: Animator 컴포넌트가 위치한 게임 오브젝트 (=> JohnLemon 오브젝트)
  • Apply Root Motion: 활성화시, 애니메이션에 있는 모든 이동이 모든 프레임에 적용
    • Update Mode를 통해 애니메이터가 움직임이 없어도 애니메이션 기능 부여



4.2. Update Loop

게임에서는 사용자가 다음 상황에 영향을 미치므로 프레임마다 경우의 수가 많다. 사용자의 입력이 매우 짧은 순간마다 발생하기 때문에 다음에 어떤 이미지를 출력할지 결정하는 프로그래밍도 동일한 속도로 작동한다. 게임 실행 동안 매 순간 갱신되는 결과물을 업데이트라고 부른다.

각 프레임마다 업데이트 메서드가 호출되며 새로운 이미지가 렌더링된다. 단, 업데이트 빈도와 상관없이 물리 작업을 실행하는 루프가 존재하며 FixedUpdate라고 부른다. Animator 컴포넌트는 업데이트 수행 시점을 변경할 수 있으며, 기본적으로 렌더링에 따라 업데이트를 수행한다.

Animator 업데이트 수행

  • Update에서 캐릭터 이동
  • Fixed Update에서 Rigidbody 수행

두 업데이트 수행 과정에서 업데이트 루프끼리 충돌을 일으키면 캐릭터가 오동작할 수 있다.


image

JohnLemon 프리팹을 Open한 후, Animator 컴포넌트의 Update Mode 프로퍼티를 Animate Physics로 설정

애니메이터가 Update마다 물리에 맞게 캐릭터를 이동하도록 한다. 캐릭터를 이동하는 업데이트 루프 간 경합이 사라진다.

캐릭터가 외부와 충돌한 이후 y방향으로 이동할 수 있으므로 수직 이동 방향을 제한한다.

  • Rigidbody 에서 Gravity를 비활성화 (수직 이동 제한이 확실하지 않음)
  • Rigidbody 에서 Constraints 프로퍼티 조정
    • 물리를 통해 Rigidbody의 이동 방향 제한 (좌표시스템 활용)


image

Rigidbody 컴포넌트의 Constraints 프로퍼티를 조절하여 제한할 이동 방향을 설정할 수 있다.

  • Freeze Position: 이동 방향 제한

  • Freeze Rotation: 회전 방향 제한



4.3. Collider

Rigidbody가 설정되어 있으나, 캐릭터가 Scene에서 물리적인 존재감을 가지려면 Collider가 필요하다. 일반적으로 인체 형태의 캐릭터에 Collider를 부여하려면 Capsule Collider가 가장 적합하다.

  • Collider: 물리적 충돌에 반응하도록 하는 오브젝트의 형태

image

Capsule Collider가 적용된 게임 오브젝트

Inspector 창에서 Capsule Collider 컴포넌트를 추가한 후, JohnLemon 캐릭터 형태와 근접하도록 크기와 위치를 조절한다.



플레이어 캐릭터: 2부

1. 스크립트

  • Monobehaviour: 게임 오브젝트에 연결할 수 있는 특수한 유형의 스크립트
    • 직접 작성할 수 있는 컴포넌트에 해당
  • 에셋으로 생성
  • 오브젝트에 스크립트를 컴포넌트로 추가하면 스크립트가 인스턴스화

스크립트 작성 시 주의할 점

스크립트 파일명과 클래스명이 동일한지 확인하자 ! 두 이름이 다를 경우 오류 발생


  • using지시문: 다른 파일에서 구현한 코드를 사용할 수 있도록 함
    • eg. using UnityEngine; 구문이 없을 경우 MonoBehaiviour 사용 불가능



1.1. 변수 만들기

  • 입력 관리자: 다양한 버튼 및 축을 정의해 변수명으로 접근할 수 있도록 함
    • eg. Horizontal: 수평 방향키 (A, D, 화살표 좌우 방향)


업데이트(매 프레임)마다 Input.GetAxis ("Horizontal")값을 horizontal에 지정한다.

  • Input.GetAxis ("Horizontal"): Input 클래스 내 GetAxis 메서드 탐색 및 파라미터(“Horizontal”) 기반 결과 호출


Vector3

3D 공간은 $x, y, z$ 좌표를 통해 벡터를 표현하며, 이러한 벡터를 Vector3 변수로 나타낼 수 있다. Vector3형 변수를 만들어 게임 오브젝트의 포지션 변경값을 표현해야 한다. 여러 메서드에서 벡터 변수를 사용할 수 있도록 클래스의 전역으로 Vector3 m_Movement;를 선언한다.

명명 규칙

m_: 특정 오브젝트나 오브젝트의 클래스를 식별하기 위해 사용. 멤버(member) 변수 의미 (파스칼 표기법)

  • 멤버 변수: 특정 메서드가 아닌 클래스에 속한 변수

일반적으로 public 변수는 낙타 표기법, non-public 변수는 파스칼 표기법 형식을 사용한다.


  • Set(x, y, z): 3D 좌표에 값 할당(각각 $x, y, z$)
  • Normalize(): 이동 벡터가 항상 같은 크기를 유지하도록 벡터 정규화 (벡터 방향 유지, 크기 1으로 변경)
    • 캐릭터가 대각선 방향으로 이동해도 동일한 이동 속도를 가지도록 함



1.2. Animator 컴포넌트 설정


  • Mathf.Approximately(): 2개의 float파라미터를 토대로 bool 변수 반환
    • 2개의 float값이 유사하면 true, 그러지 않으면 false 반환 (수평 변수가 0에 가까울수록 true)
  • !: bool값 반전 -> 수평값이 0이 아닐 경우 Input으로 간주
  • or 연산자를 활용해 캐릭터가 수평 혹은 수직으로 이동할 경우 isWalking 변수 true


isWalking 변수의 반환값을 Animator 컴포넌트에 알리기 위해 별도의 액세스 레퍼런스가 필요하다. GetComponent 메서드를 사용해 레퍼런스를 구할 수 있으며, Animator 레퍼런스는 클래스 전체에서 사용되므로 전역변수로 선언해야 한다.
-> Animator m_Animator;

  1. 정적 메서드: 클래스의 유형에 대해 호출
    • 클래스와 연결되어 있으나 별도의 인스턴스를 생성하지 않을 경우 사용
  2. 비정적 메서드(인스턴스 메서드): 인스턴스 이름을 사용하여 호출
    • 특정 인스턴스에 값 부여


모든 메서드에서 Animator 컴포넌트에 접근하려면 게임이 시작하자마자 레퍼런스가 설정되어야 하므로, Start 메서드에 GetComponent 함수를 구현한다. 이후 Update 메서드에서 Animator 컴포넌트 레퍼런스를 사용해 SetBool 메서드를 호출한다.

  • GetComponent<TypeParameter>(): Animator 유형의 컴포넌트에 대한 레퍼런스를 구하고 m_Animator 변수에 할당

    • MonoBehaviour클래스의 일부이므로 별도로 클래스명을 명시하지 않음. (접근 권한 부여 O)
  • m_Animator.SetBool(대입할 파라미터, 값): 대입할 파라미터를 분명히 파악해야 하므로, 첫 번째 파라미터의 철자가 정확해야 함



1.3 캐릭터 회전 및 이동



1.4 FixedUpdate



2. Game view 조정



ezgif com-gif-maker (7)

결과 화면

Leave a comment