유니티에서 키보드 입력으로 플레이어 이동 및 회전 구현하기 (올드 인풋 시스템 활용)

GoGoComputer·2024년 10월 27일

unity2d game

목록 보기
7/17
post-thumbnail

part 1/2 인풋 시스템

안녕하세요! 오늘은 유니티에서 키보드의 방향키를 사용하여 플레이어가 앞으로 움직이면 앞으로, 뒤로 움직이면 뒤로, 그리고 좌우로 회전하도록 만드는 방법을 쉽게 자세히 설명해 드리겠습니다. 마지막에는 작동 가능한 전체 코드를 제공해 드릴게요.

인풋 시스템 이해하기

인풋 시스템은 플레이어의 물리적 동작(키보드 입력, 마우스 움직임 등)을 게임 내에서 이해할 수 있는 정보로 변환하는 방법입니다. 즉, 플레이어가 누르는 버튼이나 키보드 입력을 게임이 인식하여 캐릭터나 오브젝트가 어떻게 반응해야 하는지를 결정합니다.

유니티에는 두 가지 인풋 시스템이 있습니다:

  1. 올드 인풋 시스템: 기존에 사용되던 시스템으로, 이해하고 시작하기에 쉽습니다.
  2. 뉴 인풋 시스템: 최신 시스템으로, 더 많은 기능과 유연성을 제공합니다.

이번에는 올드 인풋 시스템을 사용하여 기본적인 움직임을 구현해 보겠습니다.

인풋 매니저 설정 확인하기

  1. Edit > Project Settings로 이동합니다.
  2. 왼쪽 메뉴에서 Input Manager를 선택합니다.
  3. Axes를 확장하면 여러 축(axis)이 나열되어 있습니다.

축(axis)은 -1에서 +1까지의 값을 가지며, 중간의 모든 값을 포함합니다. 유니티에는 기본적으로 다음과 같은 축이 설정되어 있습니다:

  • Horizontal: 좌우 움직임(왼쪽/오른쪽 방향키 또는 A/D 키)
  • Vertical: 상하 움직임(위쪽/아래쪽 방향키 또는 W/S 키)

이 축들을 사용하여 플레이어의 입력을 감지하고, 이에 따라 움직임을 구현할 수 있습니다.

코딩 시작하기

1. 변수 선언하기

우선, 플레이어의 회전 속도와 이동 속도를 조절할 수 있는 변수를 선언합니다.

public float steerSpeed = 1.0f; // 회전 속도
public float moveSpeed = 1.0f;  // 이동 속도

2. Update() 메서드 내에서 입력 감지하기

Update() 메서드는 매 프레임마다 호출되므로, 플레이어의 입력을 지속적으로 감지하고 반영하기에 적합합니다.

a. 좌우 회전 구현

void Update()
{
    // 좌우 입력 감지
    float steerAmount = Input.GetAxis("Horizontal") * steerSpeed;
    transform.Rotate(0, 0, -steerAmount);
}
  • Input.GetAxis("Horizontal")은 플레이어의 좌우 입력을 -1에서 +1 사이의 값으로 반환합니다.
  • 이 값에 steerSpeed를 곱하여 회전 속도를 조절합니다.
  • transform.Rotate(0, 0, -steerAmount);를 통해 오브젝트를 회전시킵니다. 마이너스를 붙이는 이유는 회전 방향을 조정하기 위함입니다.

b. 전진 및 후진 구현

void Update()
{
    // 기존 코드...

    // 전진 및 후진 입력 감지
    float moveAmount = Input.GetAxis("Vertical") * moveSpeed;
    transform.Translate(0, moveAmount, 0);
}
  • Input.GetAxis("Vertical")은 플레이어의 앞뒤 입력을 -1에서 +1 사이의 값으로 반환합니다.
  • 이 값에 moveSpeed를 곱하여 이동 속도를 조절합니다.
  • transform.Translate(0, moveAmount, 0);를 통해 오브젝트를 이동시킵니다.

3. 전체 코드 정리

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public float steerSpeed = 1.0f; // 회전 속도
    public float moveSpeed = 1.0f;  // 이동 속도

    void Update()
    {
        // 좌우 회전
        float steerAmount = Input.GetAxis("Horizontal") * steerSpeed;
        transform.Rotate(0, 0, -steerAmount);

        // 전진 및 후진
        float moveAmount = Input.GetAxis("Vertical") * moveSpeed;
        transform.Translate(0, moveAmount, 0);
    }
}

코드 설명

  • public 변수: steerSpeedmoveSpeed는 인스펙터에서 쉽게 조절할 수 있도록 public으로 선언했습니다.
  • Input.GetAxis(): 키보드 입력을 감지하여 -1에서 +1 사이의 값을 반환합니다.
    • "Horizontal": 좌우 방향키 또는 A/D 키
    • "Vertical": 상하 방향키 또는 W/S 키
  • transform.Rotate(): 오브젝트를 회전시킵니다.
  • transform.Translate(): 오브젝트를 이동시킵니다.

주의사항 및 팁

  • 축 이름 정확히 입력하기: "Horizontal""Vertical"의 철자를 정확히 입력해야 합니다. 그렇지 않으면 입력이 제대로 감지되지 않습니다.
  • 플레이 모드에서의 변수 변경: 플레이 모드에서 변수 값을 변경하면, 플레이 모드를 종료할 때 변경된 값이 초기화됩니다. 원하는 값을 유지하려면 플레이 모드가 아닐 때 값을 변경하세요.
  • 회전 및 이동 속도 조절: steerSpeedmoveSpeed의 값을 조절하여 원하는 움직임 속도를 설정할 수 있습니다. 너무 큰 값은 과도한 움직임을 유발할 수 있으니 주의하세요.
  • 컴퓨터 성능 차이: 컴퓨터의 성능이나 프레임 속도에 따라 움직임이 다르게 보일 수 있습니다. 이후 강의에서 이를 보완하는 방법을 다룰 예정입니다.

실행 방법

  1. 유니티에서 새로운 C# 스크립트를 생성하고 위의 코드를 복사하여 붙여넣습니다. 스크립트 이름은 PlayerController로 설정합니다.
  2. 해당 스크립트를 플레이어 오브젝트(예: 차량)에 추가합니다.
  3. 인스펙터에서 steerSpeedmoveSpeed 값을 적절하게 설정합니다. 예를 들어, 둘 다 1.0으로 시작해 볼 수 있습니다.
  4. 플레이 모드로 실행하고 키보드 방향키나 W, A, S, D 키를 사용하여 플레이어를 조작해 봅니다.

마무리

이렇게 해서 키보드의 방향키를 사용하여 플레이어를 앞뒤로 움직이고 좌우로 회전시키는 방법을 배웠습니다. 인풋 시스템을 이해하고 이를 코드에 적용하여 플레이어의 움직임을 제어하는 기본적인 과정을 이해하셨을 거라 생각합니다.

다음 단계에서는 움직임을 더 부드럽게 만들거나, 컴퓨터 성능에 따라 움직임이 달라지는 문제를 해결하기 위해 프레임 독립적인 움직임을 구현할 수 있습니다. 이를 위해 Time.deltaTime을 사용하는 방법 등을 배우게 될 것입니다.

전체 코드 제공

마지막으로, 작동 가능한 전체 코드를 다시 한 번 제공합니다:

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

public class Driver : MonoBehaviour
{
    [SerializeField] float steerSpeed = 1f;
    [SerializeField] float moveSpeed = 0.01f;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        float steerSpeed = Input.GetAxis("Horizontal");
        float moveSpeed = Input.GetAxis("Vertical");
        transform.Rotate(0, 0, -steerSpeed);
        transform.Translate(0, moveSpeed, 0);
    }
}

이 코드를 통해 게임 내에서 키보드 입력에 따라 플레이어를 움직일 수 있습니다. 꼭 직접 따라 해 보시고, 이해되지 않는 부분이 있으면 다시 한 번 읽어보세요.


part 2/2 Time.deltaTime

안녕하세요!

오늘은 현재 사용하고 있는 코드에서 발생할 수 있는 문제점과 이를 해결하기 위해 Time.deltaTime을 사용하는 방법에 대해 자세히 설명해 드리겠습니다. 마지막에는 작동 가능한 전체 코드를 제공해 드릴게요.

현재 코드의 문제점

먼저, 현재 사용하고 있는 코드를 살펴보겠습니다:

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

public class Driver : MonoBehaviour
{
    [SerializeField] float steerSpeed = 1f;
    [SerializeField] float moveSpeed = 0.01f;

    void Update()
    {
        float steerSpeed = Input.GetAxis("Horizontal");
        float moveSpeed = Input.GetAxis("Vertical");
        transform.Rotate(0, 0, -steerSpeed);
        transform.Translate(0, moveSpeed, 0);
    }
}

이 코드는 플레이어의 입력에 따라 오브젝트를 회전하고 이동시키는 간단한 코드입니다. 하지만 이 코드에는 중요한 문제가 있습니다.

프레임률에 따른 움직임의 차이

현재 코드에서는 Update() 메서드가 매 프레임마다 호출되며, 각 프레임에서 일정한 양의 회전과 이동이 발생합니다. 그러나 컴퓨터마다 프레임률(초당 프레임 수)이 다르기 때문에, 빠른 컴퓨터에서는 더 많은 프레임이 처리되고, 느린 컴퓨터에서는 더 적은 프레임이 처리됩니다.

예를 들어:

  • 빠른 컴퓨터: 초당 100프레임 처리
  • 느린 컴퓨터: 초당 30프레임 처리

현재 코드에서는 프레임마다 같은 양의 움직임이 발생하므로, 빠른 컴퓨터에서는 초당 움직임이 100번 적용되고, 느린 컴퓨터에서는 초당 움직임이 30번 적용됩니다. 결과적으로 빠른 컴퓨터에서 게임이 훨씬 더 빠르게 진행되고, 느린 컴퓨터에서는 느리게 진행됩니다.

Time.deltaTime의 필요성

이러한 문제를 해결하기 위해서는 프레임률에 독립적인 움직임을 구현해야 합니다. 여기서 Time.deltaTime이 필요합니다.

Time.deltaTime이란?

  • Time.deltaTime이전 프레임과 현재 프레임 사이에 소요된 시간(초 단위)을 나타냅니다.
  • 프레임률이 높으면 각 프레임 사이의 시간이 짧고, 프레임률이 낮으면 시간이 깁니다.
  • 이를 이용하면 움직임을 시간에 기반하여 계산할 수 있어, 프레임률에 관계없이 일정한 속도로 움직이게 할 수 있습니다.

어떻게 사용하는가?

움직임이나 회전 값을 계산할 때, 해당 값에 Time.deltaTime을 곱해줍니다. 이렇게 하면 움직임이 초당 속도로 계산됩니다.

예를 들어:

  • moveAmount = speed * Time.deltaTime;

코드 수정하기

이제 현재 코드를 수정하여 Time.deltaTime을 적용해 보겠습니다.

1. 변수 이름 수정

현재 Update() 메서드 내에서 steerSpeedmoveSpeed를 다시 선언하고 있습니다. 이는 클래스 멤버 변수와 혼동을 일으킬 수 있으므로 변수 이름을 수정하겠습니다.

void Update()
{
    float steerAmount = Input.GetAxis("Horizontal");
    float moveAmount = Input.GetAxis("Vertical");
    // ...
}

2. Time.deltaTime 적용

steerAmountmoveAmountTime.deltaTime과 속도 변수를 곱해줍니다.

void Update()
{
    float steerAmount = Input.GetAxis("Horizontal") * steerSpeed * Time.deltaTime;
    float moveAmount = Input.GetAxis("Vertical") * moveSpeed * Time.deltaTime;
    // ...
}

3. 수정된 코드 적용

전체적인 수정된 코드는 다음과 같습니다:

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

public class Driver : MonoBehaviour
{
    [SerializeField] float steerSpeed = 300f; // 회전 속도
    [SerializeField] float moveSpeed = 20f;   // 이동 속도

    void Update()
    {
        // 입력 값 받기
        float steerAmount = Input.GetAxis("Horizontal") * steerSpeed * Time.deltaTime;
        float moveAmount = Input.GetAxis("Vertical") * moveSpeed * Time.deltaTime;

        // 회전 및 이동
        transform.Rotate(0, 0, -steerAmount);
        transform.Translate(0, moveAmount, 0);
    }
}

4. 속도 값 조정

Time.deltaTime을 곱해주면 움직임이 시간에 기반하여 계산되기 때문에, 기존의 속도 값으로는 움직임이 매우 느려질 수 있습니다. 따라서 steerSpeedmoveSpeed의 값을 적절히 조절해야 합니다.

  • 회전 속도(steerSpeed): 300 정도
  • 이동 속도(moveSpeed): 20 정도

이 값은 필요에 따라 조절하시면 됩니다.

전체 코드 정리

최종적으로 수정된 전체 코드는 다음과 같습니다:

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

public class Driver : MonoBehaviour
{
    [SerializeField] float steerSpeed = 1f;
    [SerializeField] float moveSpeed = 0.01f;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        // 입력 값 받기
        float steerAmount = Input.GetAxis("Horizontal") * steerSpeed * Time.deltaTime;
        float moveAmount = Input.GetAxis("Vertical") * moveSpeed * Time.deltaTime;

        // 회전 및 이동
        transform.Rotate(0, 0, -steerAmount);
        transform.Translate(0, moveAmount, 0);
    }
}

코드 설명

  • [SerializeField]: 이 속성은 private 변수를 인스펙터에서 수정할 수 있도록 해줍니다.
  • steerSpeedmoveSpeed: 움직임의 속도를 조절하는 변수입니다.
  • Input.GetAxis("Horizontal"): 수평 입력 값을 받아옵니다. (-1부터 1까지의 값)
  • Input.GetAxis("Vertical"): 수직 입력 값을 받아옵니다. (-1부터 1까지의 값)
  • Time.deltaTime: 이전 프레임에서 현재 프레임까지의 시간 차이를 초 단위로 반환합니다.
  • transform.Rotate(): 오브젝트를 회전시킵니다.
  • transform.Translate(): 오브젝트를 이동시킵니다.

왜 Time.deltaTime을 사용하는가?

  • 일관된 움직임: 프레임률이 다르더라도 움직임이 일정하게 유지됩니다.
  • 플랫폼 독립성: 다양한 기기(PC, 모바일 등)에서 동일한 게임 플레이 경험을 제공합니다.
  • 부드러운 애니메이션: 시간에 기반한 움직임은 애니메이션을 더 부드럽게 만들어 줍니다.

테스트 및 튜닝하기

  1. 유니티 에디터에서 스크립트를 저장하고 실행합니다.
  2. 인스펙터에서 steerSpeedmoveSpeed 값을 조정하여 원하는 움직임을 얻을 때까지 튜닝합니다.
    • 값이 너무 크면 움직임이 과도하게 빠를 수 있습니다.
    • 값이 너무 작으면 움직임이 느려집니다.
  3. 플레이 모드에서 값을 변경하면 플레이 모드를 종료할 때 값이 초기화됩니다. 원하는 값을 유지하려면 플레이 모드가 아닐 때 값을 변경하세요.
  4. 다른 컴퓨터나 기기에서 테스트하여 움직임이 일관적인지 확인합니다.

마무리

이렇게 해서 Time.deltaTime을 사용하여 프레임률에 독립적인 움직임을 구현하는 방법을 배웠습니다. 이를 통해 다양한 환경에서 일관된 게임 플레이 경험을 제공할 수 있습니다.

프레임률 독립적인 움직임은 게임 개발에서 매우 중요한 개념이며, 앞으로의 개발에서도 자주 사용될 것입니다.

다음 강의에서 더 흥미로운 내용을 다루도록 하겠습니다. 감사합니다!

profile
IT를 좋아합니다.

0개의 댓글