학습 매체 : 책
책이름 : 레트로의 유니티 게임 프로그래밍 에센스
저자 : 이제민
본 내용은 해당 강의 내용을 공부하면서 정리한 글입니다.
1. 조작이 게임에 즉시 반영되지 않는다.
- AddForce( ) 메서드는 힘을 추가한다. 누적된 힘으로 속도를 점진적으로 증가시키기 때문에 속도가 충분히 빨라질 때까지 시간이 걸린다. 또한 이동 중에 반대 방향으로 이동하려는 경우 관성에 의해 힘이 상쇄되어 방향 전환이 금방 이루어지지 않는다.
2. 입력 감지 코드가 복잡하다.
- 방향키를 감지하는 데 if 문 네 개를 사용했다. 이것을 좀 더 쉽고 간결한 코드로 개선하고 싶다.
3. palyerRigidbody에 컴포넌트를 드래그&드롭으로 할당하는 것이 불편하다.
- 인스펙터 창에서 PlayerController 컴포넌트의 Player Rigidbody 필드로 리지드바디 컴포넌트를 직접 드래그&드롭했다. 이렇게 직접 드래그&드롭하는 방식은 불편하며, 잘못된 값을 할당할 위험이 있다. 변수에 컴포넌트의 참조를 할당하는 과정을 코드로 실행하고 싶다.
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);
}
}
GetComponent<Rigidbody>();
void Start()
{
playerRigidbody = GetComponent<Rigidbody>();
}
GetComponent( ) 메서드가 컴포넌트를 찾지 못했을 때
- 게임 오브젝트에 찾으려는 타입의 컴포넌트가 추가되어 있지 않으면 GetComponent( ) 메서드는 null을 반환한다.
제네릭
- GetComponent( ) 메서드에서 사용한 꺾쇠 <>는 제네릭(Generic) 기법이다. 제네릭은 메서드나 클래스가 여러 타입에 호환되게 한다. 꺾쇠 안에 원하는 타입을 명시하면 클래스나 메서드가 해당 타입에 맞춰 동작한다.
- 제네릭을 사용하지 않으면 같은 처리를 위한 여러 타입의 메서드나 클래스를 일일이 만들어야 한다.
- 이런 문제를 해결하기 위해 GetComponent( )는 제네릭을 사용할 수 있도록 구현되어 있으며, 제네릭 덕분에 하나의 GetComponent( ) 메서드로 모든 타입의 컴포넌트에 대응할 수 있다.
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. 리지드바디 컴포넌트의 속도를 변경
앞의 개선된 Update( ) 메서드를 보면 Input.GetKey( ) 대신 Input.GetAxis( ) 메서드가 등장했다.
Input.GetAxis( ) 메서드는 어떤 축에 대한 입력값을 숫자로 반환하는 메서드이다.
float Input.GetAxis(string axisName);
축의 음의 방향에 대응되는 버튼을 누름 : -1.0
아무것도 누르지 않음 : 0
축의 양의 방향에 대응되는 버튼을 누름 : +1.0
Horizontal 축의 경우
Horizontal(수평) 축에 대응되는 키
- 음의 방향 : ←(왼쪽 방향키), A 키
- 양의 방향 : →(오른쪽 방향키), D 키Input.GetAxis("Horizontal")의 출력값
- ← 또는 A 키를 누름 : -1.0
- 아무것도 누르지 않음 : 0
- → 또는 D 키를 누름 : +1.0Vertical 축의 경우
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
float xInput = Input.GetAxis("Horizontal");
float zInput = Input.GetAxis("Vertical");
float xSpeed = xInput * speed;
float zSpeed = zInput * speed;
float xSpeed = 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 (앞쪽 이동)
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로 변경된다.
Vector3 vector = new Vector3(x, y, z);
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를 수정하는 것은 이전 속도를 지우고 새로운 속도를 사용하는 것이다. 따라서 관성을 무시하고 속도가 즉시 변경된다.
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( ) 메서드와 입력 매니저를 자세히 알아보겠다.
다음 강의에서 계속~