레트로의 유니티 게임 프로그래밍 에센스 - 6.7

Cosmos·2023년 4월 5일
0

학습 매체 : 책

책이름 : 레트로의 유니티 게임 프로그래밍 에센스

저자 : 이제민


본 내용은 해당 강의 내용을 공부하면서 정리한 글입니다.


6.7 PlayerController 스크립트 개선하기


  • PlayerController 스크립트를 완성했지만 몇 가지 문제가 있다.

1. 조작이 게임에 즉시 반영되지 않는다.

  • AddForce( ) 메서드는 힘을 추가한다. 누적된 힘으로 속도를 점진적으로 증가시키기 때문에 속도가 충분히 빨라질 때까지 시간이 걸린다. 또한 이동 중에 반대 방향으로 이동하려는 경우 관성에 의해 힘이 상쇄되어 방향 전환이 금방 이루어지지 않는다.

2. 입력 감지 코드가 복잡하다.

  • 방향키를 감지하는 데 if 문 네 개를 사용했다. 이것을 좀 더 쉽고 간결한 코드로 개선하고 싶다.

3. palyerRigidbody에 컴포넌트를 드래그&드롭으로 할당하는 것이 불편하다.

  • 인스펙터 창에서 PlayerController 컴포넌트의 Player Rigidbody 필드로 리지드바디 컴포넌트를 직접 드래그&드롭했다. 이렇게 직접 드래그&드롭하는 방식은 불편하며, 잘못된 값을 할당할 위험이 있다. 변수에 컴포넌트의 참조를 할당하는 과정을 코드로 실행하고 싶다.

6.7.1 Start( ) 메서드 수정

  • Start( ) 메서드를 이용하여 게임이 시작될 때 변수 palyerRigidbody에 리지드바디 컴포넌트의 참조를 할당하도록 수정하겠다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private Rigidbody playerRigidbody;
    public float speed = 8f;

    void Start()
    {
        playerRigidbody = GetComponent<Rigidbody>();
    }

    void Update()
    {
		// 생략
    }

    public void Die()
    {
        gameObject.SetActive(false);
    }
}
  • 변수 palyerRigidbody의 접근 한정자를 public에서 private로 변경했다. 따라서 나중에 인스펙터 창에서 PlayerController 컴포넌트를 봤을 때 이전의 Player Rigidbody 필드가 더이상 표시되지 않는 것을 알 수 있다.

  • public이 아닌 변수는 유니티 인스펙터 창에서 관측되지 않기 때문에 표시되지 않는다. 따라서 이제는 드래그&드롭으로는 리지드바디 컴포넌트를 변수 palyerRigidbody에 할당할 수 없다.

6.7.2 GetComponent( ) 메서드

  • GetComponent( ) 메서드는 원하는 타입의 컴포넌트를 자신의 게임 오브젝트에서 찾아오는 메서드이다. GetComponent( ) 메서드는 꺾쇠 <>로 가져올 타입을 받는다.
GetComponent<Rigidbody>();
  • 자신의 게임 오브젝트에서 Rigidbody 타입의 컴포넌트를 찾아서 가져온다. 즉, 아래 코드는 Player 게임 오브젝트에서 리지드바디 컴포넌트를 찾아서 palyerRigidbody 변수에 할당한다.
    void Start()
    {
        playerRigidbody = GetComponent<Rigidbody>();
    }

GetComponent( ) 메서드가 컴포넌트를 찾지 못했을 때

  • 게임 오브젝트에 찾으려는 타입의 컴포넌트가 추가되어 있지 않으면 GetComponent( ) 메서드는 null을 반환한다.

제네릭

  • GetComponent( ) 메서드에서 사용한 꺾쇠 <>는 제네릭(Generic) 기법이다. 제네릭은 메서드나 클래스가 여러 타입에 호환되게 한다. 꺾쇠 안에 원하는 타입을 명시하면 클래스나 메서드가 해당 타입에 맞춰 동작한다.
  • 제네릭을 사용하지 않으면 같은 처리를 위한 여러 타입의 메서드나 클래스를 일일이 만들어야 한다.
  • 이런 문제를 해결하기 위해 GetComponent( )는 제네릭을 사용할 수 있도록 구현되어 있으며, 제네릭 덕분에 하나의 GetComponent( ) 메서드로 모든 타입의 컴포넌트에 대응할 수 있다.

6.7.3 조작감 개선하기

  • 기존 Update( ) 메서드를 수정하여 코드를 더 간결하게 만들고 조작이 이동 속도에 즉시 반영되도록 개선하자.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private Rigidbody playerRigidbody;
    public float speed = 8f;

    void Start()
    {
        playerRigidbody = GetComponent<Rigidbody>();
    }

    void Update()
    {
        // 수평축과 수직축의 입력값을 감지하여 저장
        float xInput = Input.GetAxis("Horizontal");
        float zInput = Input.GetAxis("Vertical");

        // 실제 이동 속도를 입력값과 이동 속력을 사용해 결정
        float xSpeed = xInput * speed;
        float zSpeed = zInput * speed;

        // Vector3 속도를 (xSpeed, 0, zSpeed)로 생성
        Vector3 newVelocity = new Vector3(xSpeed, 0f, zSpeed);

        // 리지드바디의 속도에 newVelocity 할당
        playerRigidbody.velocity = newVelocity; 
    }

    public void Die()
    {
        gameObject.SetActive(false);
    }
}
  • 수정된 코드는 다음과 같은 동작을 수행한다.

1. 수평축과 수직축의 입력 감지

2. 속도를 나타낼 새로운 Vector3를 생성

3. 리지드바디 컴포넌트의 속도를 변경


6.7.4 GetAxis( ) 메서드

  • 앞의 개선된 Update( ) 메서드를 보면 Input.GetKey( ) 대신 Input.GetAxis( ) 메서드가 등장했다.

  • Input.GetAxis( ) 메서드는 어떤 축에 대한 입력값을 숫자로 반환하는 메서드이다.

float Input.GetAxis(string axisName);
  • Input.GetAxis( ) 메서드는 축(Axis)의 이름을 받는다. 그리고 다음 경우에 따라 감지된 입력값을 반환한다.
  • 축의 음의 방향에 대응되는 버튼을 누름 : -1.0

  • 아무것도 누르지 않음 : 0

  • 축의 양의 방향에 대응되는 버튼을 누름 : +1.0

  • 입력축은 6.8절 '입력 매니저'에서 설명할 입력 매니저를 이용해 설정한다. 기본 설정으로 추가되어 있는 Horizontal 축과 Vertical 축의 대응 입력키와 출력되는 입력값은 다음과 같다.

Horizontal 축의 경우

  • Horizontal(수평) 축에 대응되는 키

    - 음의 방향 : ←(왼쪽 방향키), A 키
    - 양의 방향 : →(오른쪽 방향키), D 키
  • Input.GetAxis("Horizontal")의 출력값

    - ← 또는 A 키를 누름 : -1.0
    - 아무것도 누르지 않음 : 0
    - → 또는 D 키를 누름 : +1.0

Vertical 축의 경우

  • Vertical(수직) 축에 대응되는 키

    - 음의 방향 : ↓(아래쪽 방향키), S 키
    - 양의 방향 : ↑(위쪽 방향키), W 키
  • Input.GetAxis("Vertical")의 출력값

    - ↓ 또는 S 키를 누름 : -1.0
    - 아무것도 누르지 않음 : 0
    - ↑ 또는 W 키를 누름 : +1.0

		float xInput = Input.GetAxis("Horizontal");
        float zInput = Input.GetAxis("Vertical");
  • 개선된 Update( ) 메서드를 다시 보자. 새로 선언한 변수 xInput은 수평 방향 입력, 변수 zInput은 수직 방향 입력을 저장한다.

  • 그리고 매 프레임마다 Input.GetAxis( )를 이용해 Horizontal 축 입력과 Vertical 축 입력을 각각 xInput과 zInput에 저장한다.

  • 결과적으로 키보드 입력에 따라 xInput과 zInput에 할당되는 값은 다음과 같다.

  • ← 또는 A 키 : xInput = -1.0

  • 아무것도 누르지 않음 : xInput = 0

  • → 또는 D 키 : xInput = +1.0

  • ↓ 또는 S 키 : zInput = -1.0

  • 아무것도 누르지 않음 : zInput = 0

  • ↑ 또는 W 키 : zInput = +1.0


6.7.2 속도 계산하기

  • 계속해서 Update( ) 메서드를 살펴보면 xInput 값과 zInput 값을 기반으로 X와 Z 방향의 속도를 각각 계산하고 새로운 Vector3 데이터를 생성한다.
        float xInput = Input.GetAxis("Horizontal");
        float zInput = Input.GetAxis("Vertical");
        
        float xSpeed = xInput * speed;
        float zSpeed = zInput * speed;
  • 여기서 xSpeed는 X 방향 이동 속도, zSpeed는 Z 방향 이동 속도를 표현한다.
float xSpeed = xInput * speed;
  • xInput * speed가 왼쪽, 정지, 오른쪽 이동을 모두 표현할 수 있다는 점에 주목하자.
  • ← 또는 A 키를 누른 경우
    - xInput = -1.0
    - xSpeed = (-1.0) x speed = -speed (왼쪽 이동)
  • 아무것도 누르지 않은 경우
    - xInput = 0
    - xSpeed = 0 x speed = 0 (정지)
  • → 또는 D 키를 누른 경우
    - xInput = +1.0
    - xSpeed = (+1.0) x speed = speed (오른쪽 이동)
  • 수직 방향도 같은 원리이다.
float zSpeed = zInput * speed;
  • ↓ 또는 S 키를 누른 경우
    - zInput = -1.0
    - zSpeed = (-1.0) x speed = -speed (뒤쪽 이동)
  • 아무것도 누르지 않은 경우
    - zInput = 0
    - zSpeed = 0 x speed = 0 (정지)
  • ↑ 또는 W 키를 누른 경우
    - zInput = +1.0
    - zSpeed = (+1.0) x speed = speed (앞쪽 이동)
  • xSpeed, zSpeed에 할당된 값들을 기반으로 새로운 Vector3 변수 newVelocity를 선언했다. newVelocity는 X, Y, Z 방향으로의 속도를 나타내기 위한 변수이다.
        float xSpeed = xInput * speed;
        float zSpeed = zInput * speed;

        Vector3 newVelocity = new Vector3(xSpeed, 0f, zSpeed);
        playerRigidbody.velocity = newVelocity;
  • newVelocity에 (xSpeed, 0f, zSpeed)를 가지는 Vector3 데이터를 생성하여 할당했다.

  • 리지드바디 컴포넌트는 현재 속도를 표현하는 Vector3 타입의 velocity 변수를 제공한다. 리지드바디의 velocity 변수로 현재 속도를 알 수 있으며, 반대로 해당 변수에 새로운 값을 할당하여 현재 속도를 변경할 수 있다.

  • playerRigidbody.velocity에 newVelocity를 할당했다. 그러면 playerRigidbody에 할당된 리지드바디 컴포넌트의 현재 속도가 newVelocity로 변경된다.


6.7.6 Vector3

  • Vector3는 원소 x, y, z를 가지는 타입이다. 위치, 크기, 속도, 방향 등을 나타낼 때 주로 사용한다. 새로운 Vector3 값은 아래와 같은 형태로 생성한다. x, y, z에 대응하는 값을 넣으면 된다.
Vector3 vector = new Vector3(x, y, z);
  • 예를 들어 (x = 100, y = 100, z = 100)을 표현하는 새로운 Vector3 값을 생성하고 싶으면 다음과 같은 방법으로 생성한다.
Vector3 vector = new Vector3(100f, 100f, 100f);
  • Vector3 newVelocity = new Vector3(xSpeed, 0f, zSpeed);는 X 방향으로 xSpeed, Y 방향으로 0, Z 방향으로 zSpeed만큼 가는 속도를 표현하는 Vector3 값을 생성하여 newVelocity라는 변수로 저장한 것이다.

  • Vector3와 관련한 자세한 기능과 수학적 내용은 9장과 10장에서 다시 보게 된다. 지금은 Vector3가 x, y, z를 하나의 변수로 다루는 타입이라는 점만 알면 된다.

Rigidbody의 AddForce( )와 velocity의 차이

  • 이전에 조작이 무겁게 느껴졌던 이유는 관성 때문이다. 기존 Update( ) 메서드에서는 AddForce( ) 메서드를 사용해 힘을 누적하고 속력을 점진적으로 증가시켰다.
  • Rigidbody의 velocity를 수정하는 것은 이전 속도를 지우고 새로운 속도를 사용하는 것이다. 따라서 관성을 무시하고 속도가 즉시 변경된다.

6.7.7 완성된 스크립트 확인(2차)

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

public class PlayerController : MonoBehaviour
{
    private Rigidbody playerRigidbody;
    public float speed = 8f;

    void Start()
    {
        playerRigidbody = GetComponent<Rigidbody>();
    }

    void Update()
    {
        // 수평축과 수직축의 입력값을 감지하여 저장
        float xInput = Input.GetAxis("Horizontal");
        float zInput = Input.GetAxis("Vertical");

        // 실제 이동 속도를 입력값과 이동 속력을 사용해 결정
        float xSpeed = xInput * speed;
        float zSpeed = zInput * speed;

        // Vector3 속도를 (xSpeed, 0, zSpeed)로 생성
        Vector3 newVelocity = new Vector3(xSpeed, 0f, zSpeed);

        // 리지드바디의 속도에 newVelocity 할당
        playerRigidbody.velocity = newVelocity; 
    }

    public void Die()
    {
        gameObject.SetActive(false);
    }
}
  • 이제 유니티 에디터로 돌아가서 테스트를 해보자.

  • 충분히 테스트해봤다면 플레이 모드를 해제하고 진행 사항을 저장하자.

  • 이것으로 이 장의 모든 구현을 끝났다. 다음에는 우리가 사용한 GetAxix( ) 메서드와 입력 매니저를 자세히 알아보겠다.


다음 강의에서 계속~

profile
게임 개발을 목적으로 공부하고 있는 대학생입니다.

0개의 댓글