[C# Unity] 케릭터(오브젝트) 움직이기

Arthur·2023년 8월 14일
0
post-thumbnail

작성한 계기


인프런이라는 강의 플랫폼에서 Rookiss님의 유니티 강의를 보고 케릭터가 움직이는 기능을 배웠습니다.

해당 내용을 봐도 한번에 이해가 되지 않았습니다.
그리고 강의 코드를 참고하지 않아도 혼자서 코드를 작성해 볼 수 있어야 한다고 생각했습니다.

그러기 위해선 강의에 나오는 내용을 정리하고 코드를 직접 하나씩 뜯어보고,
모르는 내용은 정리해서 하나씩 해결해 나가야 한다고 생각해서 이렇게 글로 작성하게 되었습니다.



첫 번째 작성한 코드



public class PlayerController : MonoBehaviour
{
	// ...
    void Update()
    {
        if (Input.GetKey(KeyCode.W))
            transform.position += new Vector3(0.0f, 0.0f, 1.0f);
        if (Input.GetKey(KeyCode.S))
            transform.position -= new Vector3(0.0f, 0.0f, 1.0f);
        if (Input.GetKey(KeyCode.A))
            transform.position -= new Vector3(1.0f, 0.0f, 0.0f);
        if (Input.GetKey(KeyCode.D))
            transform.position += new Vector3(1.0f, 0.0f, 0.0f);
    }
}



무료로 제공해주는 Asset 케릭터 모델을 다운로드 받고 스크립트로 PlayerController을 추가했습니다.
추가한 스크립트에 위와 같은 코드를 작성했습니다.

유니티 실행해 실행하면 위와 같이 작동합니다.
이동은 해도 움직임이 부자연스럽고 방향키를 한 번만 입력해도 생각보다 많이 범위를 이동합니다.

첫 번째 작성한 코드의 문제점

  • 이동이 상당히 부자연스럽습니다.
  • 방향키를 한 번만 입력해도 많은 범위를 한 번에 이동합니다.
  • 케릭터가 바라보는 기준의 좌표 기준이 아닌, 월드 좌표 기준의 방향으로 움직입니다.

우선 코드를 개선하기 전에 각 키워드를 정리하고 공부해봤습니다.


Transform(트랜스폼)

게임 오브젝트의 포지션, 회전, 스케일, 부모-자식 상태를 저장하기 위해 사용하며 따라서 매우 중요합니다. 게임 오브젝트에는 항상 하나의 트랜스폼 컴포넌트가 있습니다. 이 트랜스폼을 제거하거나, 트랜스폼이 없는 게임 오브젝트를 생성하는 것은 불가능합니다.
<Unity Docs - 트랜스폼>

  • 트랜스폼의 프로퍼티에는 Position, Rotation, Scale이 있습니다.
    - Position : X, Y, Z 좌표에서의 트랜스폼 포지션
    • Rotation : X, Y, Z 축 주변의 트랜스폼 회전으로, 도 단위로 측정
    • Scale : X, Y, Z 축을 따르며, 크기를 조절할 수 있습니다.
  • 트랜스폼은 X, Y, Z 축으로 이루어진 3D 공간 또는 X, Y축만 있는 2D 공간에서 조작합니다.

유니티 Docs에는 위와 같이 나와있습니다.

추가적으로 게임 오브젝트의 부모-자식 관계 설정, 스케일에 관한 내용은 Unity Docs를 참고 바랍니다
=> Unity Docs - 트랜스폼 => 링크


Vector3

3D 벡터 및 점을 표현합니다. 이 구조는 Unity 전체에서 3D 위치와 방향을 전달하는데 사용됩니다. 또한 일반적인 벡터 연산을 수행하기 위한 함수도 포함되어 있습니다.
<Unity Docs - Vector3>

  • Vector3는 구조체로 new 연산자를 사용해도 힙(Heap)이 아닌 스택(Stack) 생성된다. => 참고 링크
  • 기본 데이터 타입이 float입니다.
  • 크기와 방향을 나타내는 데이터 타입입니다.

Vector(벡터)란?

벡터에 대한 수학, 물리학, 기하학 등 여러 복잡한 글들이 있습니다.
다 알면 좋겠지만 해당 내용들은 그래픽스를 배우거나 좀 더 심화로 배울 때 공부하기로 했습니다.

유니티에서 사용되는 벡터의 개념으로 봤을 때 간단하게 요약하면,
특정한 공간에서 방향과 크기를 표현하는 도구로서 주로 화살표로 표시되는 개념을 말합니다.


유니티에서는 공간 내의 점이나 방향 등을 표현하는데 사용됩니다.

벡터는 주로 2가지 유형으로 나뉩니다.

  • 2D 벡터 : 2D 공간에서 좌표나 방향을 나타내는 벡터입니다. 보통 (x, y)형태로 표현되며, 위치, 속도, 가속도 등을 나타내는데 사용됩니다.
  • 3D 벡터 : 3D 공간에서의 좌표나 방향을 나타내는 벡터로 (x, y, z) 형태로 표현되며, 3D 그래픽스, 물리 시뮬레이션, 카메라 이동 등 다양한 분야에서 사용됩니다.

(그래픽스 관점에서 벡터를 이해하고 싶으시면 블로그 링크 를 참고하시길 바랍니다.)

키워드를 아주 간단하게 정리해보고 알아봤으니 이제 다시 문제점을 수정해보기로 했습니다.



두 번째 작성한 코드


void Update()
{
    if (Input.GetKey(KeyCode.W))
        transform.Translate(Vector3.forward * Time.deltaTime * _speed);
    if (Input.GetKey(KeyCode.S))
        transform.Translate(Vector3.back * Time.deltaTime * _speed);
    if (Input.GetKey(KeyCode.A))
        transform.Translate(Vector3.left * Time.deltaTime * _speed);
    if (Input.GetKey(KeyCode.D))
        transform.Translate(Vector3.right * Time.deltaTime * _speed);
}

위에 작성한 코드를 실행해 작동하면 아래와 같이 작동합니다.

개선한 점

  • Translate를 사용해서 월드 좌표 기준이 아닌 로컬(local) 좌표 기준으로 움직입니다.
    - 케릭터가 회전을 해도 케릭터 기준으로 좌표가 결정됩니다.
    • 나중에 방향전환 기능 추가 시 필요
  • 케릭터의 speed를 설정할 수 있습니다.
  • 방향에 대한 값을 직접 계산해서 넣어주는게 아니라, Vector3에 내장 함수를 사용합니다.
    - Vector3.forward, Vector3.back 과 같은 함수 사용
  • deltaTime을 사용해 한 프레임 당 실행하는 시간의 값을 곱해줍니다.
    - Update()가 실행될 때마다 1프레임 당 이동거리를 계산하여 실행합니다.
    - 1프레임 당 이동거리 = Vector3값 * 1프레임 당 실행 시간 X 케릭터 이동 속도

코드의 양은 적지만 각 키워드에 담겨있는 내용이 상당히 많았습니다.
아직 전부 다 깊게 이해하지는 못했지만, 발견했던 문제들과 개선할 점은 다 해결되었습니다.



참고자료


  • 공부하는 식빵맘 - Chapter 2. Transform (+ Input Manager) => 링크
  • 인프런 - [C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part3: 유니티 엔진 => 링크
  • Unity Docs - 트랜스폼 => 링크
  • 수포자를 위한 게임 수학 #03 - 선형대수학?(Linear Algebra?) => 링크
  • 수포자를 위한 게임 수학 #04 - 벡터(vector) #1 벡터맨은 핵아재! => 링크
  • 벡터(vector)란? => 링크
  • [Unity3D] Vector - 좌표와 속도를 다루기 위한 도구 => 링크
profile
기술에 대한 고민과 배운 것을 회고하는 게임 서버 개발자의 블로그입니다.

0개의 댓글