6. 들어가기 전에
3부에서는 사방에서 무수히 많이 날아오는 탄알을 가능한 한 오랫동안 피하는 탄막 슈팅 게임을 만든다. 6장에서는 프로젝트를 준비하고, 씬을 구성하며, 플레이어 조작을 완성한다.
레트로의 유니티 게임 프로그래밍 에센스 | 이제민 - 교보문고
레트로의 유니티 게임 프로그래밍 에센스 | 이제민 - 교보문고
레트로의 유니티 게임 프로그래밍 에센스 | 독자분들로부터 수많은 찬사를 받았던 유니티 대표 도서 『소문난 명강의:레트로의 유니티 게임 프로그래밍 에센스』가 개정판으로 돌아왔습니다!
product.kyobobook.co.kr
6.1 씬 구성하기
1. 유니티 허브를 실행하고 New Project 를 클릭한다.
2. 프로젝트 이름을 Dodge 로 변경 후 Create project 버튼을 클릭한다.
6.1.1 레벨 만들기
1. 바닥 만들기
- 바닥 Plane 게임 오브젝트 만들기(하이어라키 창에서 + > 3D Object > Plane 클릭)
- 만약 Transform 컴포넌트의 Position 이 (0, 0, 0) 이 아니라면 (0, 0, 0) 으로 바꿔준다.

2. 가로와 세로 길이를 두 배 늘리기
- 인스펙터 창에서 Plane 게임 오브젝트의 Transform 컴포넌트의 scale 을 (2, 1, 2) 로 변경

6.1.2 머티리얼
유니티에서 게임 오브젝트의 컬러는 머티리얼(Material) 이 결정한다. 머티리얼은 셰이더와 텍스처가 합쳐진 에셋으로, 오브젝트의 픽셀 컬러를 결정한다.
셰이더는 주어진 입력에 따라 픽셀의 최종 컬러를 결정하는 코드이다. 셰이더는 질감과 빛에 의한 반사와 굴절 등의 효과를 만든다. 텍스처는 표면에 입히는 이미지 파일이다.
1. 새로운 머티리얼 만들기
- 프로젝트 창에서 + > Material 클릭
- 생성된 머티리얼의 이름을 Plane Color 로 변경

생성된 Plane Color 머티리얼을 선택하고 인스펙터 창을 보면 머티리얼에 관한 여러 설정값이 보인다.
알베도(Albedo) 는 반사율이라는 뜻으롤, 물체가 어떤 색을 반사할지 결정한다. 즉, 물체 표면의 기본색을 결정한다.

바닥을 검은색으로 칠하고 싶다. 따라서 Plane Color 머티리얼의 알베도를 검은색으로 변경한다.
2. 머티리얼을 검은색으로 만들기
- Albedo 옆의 컬러 필드 클릭
- 컬러 창에서 RGB 값을 (0, 0, 0) 으로 변경 > 컬러 창 닫기


색이 변경된 머티리얼을 Plane 에 적용한다.
3. 머티리얼을 게임 오브젝트에 적용
- Plane Color 머티리얼을 씬 창의 Plane 게임 오브젝트로 드래그&드롭


6.1.3 벽 만들기
게임 도중 플레이어가 바닥을 벗어날 수 없도록 Plane 게임 오브젝트 사방에 벽을 추가한다.
1. 벽 만들기
- 하이어라키 창에서 + > 3D Object > Cube 클릭
- 생성된 Cube 게임 오브젝트의 이름을 Wall 로 변경
- Wall 의 위치는 (0, 0.5, 0), 스케일은 (20, 1, 1) 로 변경

그다음 벽을 바닥의 앞쪽 모서리로 이동시킨다.
2. 벽을 앞쪽에 배치하기
- Wall 게임 오브젝트의 위치를 (0, 0.5, 10) 으로 변경

3. 벽을 뒤쪽에 배치하기
- 하이어라키 창에서 Wall 게임 오브젝트 선택 > [Ctrl + D] 로 복제
- 생성된 Wall(1) 게임 오브젝트를 선택하고 위치를 (0, 0.5, -10) 으로 변경

4. 벽을 좌우에 배치하기
- 하이어라키 창에서 Wall (1) 을 선택 > [Ctrl + D] 를 두 번 눌러 두 번 복제
- 생성된 Wall (2) 의 위치를 (10, 0.5, 0), 스케일을 (1, 1, 20) 으로 변경
- 생성된 Wall (3) 의 위치를 (-10, 0.5, 0), 스케일을 (1, 1, 20) 으로 변경


5. Level 게임 오브젝트 만들기
- 하이어라키 창에서 빈 게임 오브젝트 생성(+ > Create Empty)
- 생성된 GameObject 의 이름을 Level 로 변경
- Level 게임 오브젝트의 위치 리셋(Transform 컴포넌트의 점 세개 버튼 > Reset 클릭)

이제 바닥과 벽 게임 오브젝트들을 Level의 자식으로 만든다.
6. 게임 오브젝트들을 Level 의 자식으로 넣기
- 하이어라키 창에서 [Shift + 클릭] 으로 Plane, Wall, Wall(1), Wall(2), Wall(3) 을 모두 선택
- 선택한 게임 오브젝트를 Level 게임 오브젝트로 드래그&드롭


6.2 카메라 설정하기
레벨을 완성했으니 게임 창에 레벨 전체가 한눈에 보이도록 카메라를 배치한다. 그리고 카메라의 배경색을 짙은 회색으로 바꾼다.
현재는 게임 창에서 레벨이 한눈에 보이지 않는다. 카메라가 바닥 가까이에 있기 때문이다. 따라서 카메라를 한눈에 레벨을 내려다 볼 수 있는 곳으로 옮긴다.
1. 카메라 위치 변경
- 하이어라키 창에서 Main Camera 게임 오브젝트 선택
- Main Camera 의 위치를 (0, 15, -10), 회전을 (60, 0, 0) 으로 변경

카메라 컴포넌트는 기본값으로 배경을 가상의 하늘인 스카이박스로 채우도록 설정되어 있다. 닷지 게임에서는 스카이박스가 어색해 보이기 때문에 배경을 단색으로 변경한다.
2. 카메라의 배경 변경
- Main Camera 게임 오브젝트의 Camera 컴포넌트에서 Clear Flags 의 값을 Solid Color 로 변경
- Background 의 컬러 필드 클릭 > 컬러 창 열림
- RGB 컬러를 (36, 36, 36) 으로 변경 > 컬러 창 닫기

3. 씬 저장하기
- [Ctrl + S] 로 씬 저장
6.3 플레이어 제작
이제 스크립트를 사용해서 조작할 수 있는 플레이어 게임 오브젝트를 만든다. 플레이어 게임 오브젝트는 다음과 같은 기능을 갖는다.
- 파란색 캡슐 모양
- 상하좌우 혹은 WASD 키로 움직일 수 있다.
- 탄알에 맞으면 죽는다.
6.3.1 플레이어 게임 오브젝트 만들기
먼저 플레이어가 될 게임 오브젝트를 만들고 표면을 파란색으로 변경한다.
1. Player 게임 오브젝트 만들기
- 하이어라키 창에서 캡슐(Capsule) 게임 오브젝트 생성(+ > 3D Object > Capsule)
- Capsule 게임 오브젝트의 이름을 Player 로 변경
- Player 게임 오브젝트의 위치를 (0, 1, 0) 으로 변경

2. Player Color 머티리얼 만들기
- 프로젝트 창에서 + > Material 클릭
- 생성된 머티리얼의 이름을 Player Color 로 변경

3. Player 게임 오브젝트를 파란색으로 변경하기
- Player Color 머티리얼의 Albedo 컬러를 (0, 100, 164) 로 변경
- Player Color 머티리얼을 씬 창의 Player 게임 오브젝트로 드래그&드롭

6.3.2 태그 설정하기
나중에 탄알을 만들 때 탄알 입장에서 충돌한 게임 오브젝트가 플레이어인지 확인할 방법이 필요하다. 이때 게임 오브젝트의 태그를 사용한다.
태그는 게임 오브젝트를 분류하고, 코드에서 게임 오브젝트를 구별하는 데 사용한다.
1. Player 태그 할당
- 하이어라키 창에서 Player 게임 오브젝트 선택 > 인스펙터 창의 Tag 드롭다운 버튼 클릭
- Player 태그 선택

이렇게 Player 태그를 설정하면 나중에 탄알이 Player 게임 오브젝트와 충돌했을 때만 게임 오버가 실행되게 할 수 있다. 탄알 입장에서 충돌한 상대방 게임 오브젝트의 태그가 Player 인지 체크하면 되기 때문이다.
6.3.3 리지드바디 컴포넌트 설정
Player 게임 오브젝트를 움직이는 데는 물리적인 힘과 속력이 필요하다. 따라서 Player 게임 오브젝트가 물리적인 상호작용이 가능하도록 리지드바디 컴포넌트를 추가한다.
1. 리지드바디 컴포넌트 추가
- 인스펙터 창에서 Add Component > Physics > Rigidbody 클릭

이제 Player 게임 오브젝트는 물리 상호작용이 가능하다. 그런데 Player 게임 오브젝트는 캡슐 형태이다. 리지드바디 컴포넌트를 그대로 사용하면 플레이어가 오뚝이처럼 이리저리 넘어질 수 있다.
Player 게임 오브젝트가 넘어지는 것을 막기 위해 리지드바디의 제약(Constrains) 옵션을 사용한다. 제약을 사용하면 어떤 축의 위치나 회전이 변경되지 않게 고정할 수 있다.
2. 리지드바디 제약 설정하기
- 인스펙터 창에서 Rigidbody 컴포넌트의 Constraints 필드 펼치기
- Freeze Position 은 Y 체크, Freeze Rotation 은 X, Z 체크

이제 Player 게임 오브젝트의 높이가 변경되지 않으며, 오직 Y 축으로만 회전할 수 있다.
3. 씬 저장하기
- [Ctrl+S] 로 씬 저장
6.4 플레이어 스크립트 생성
Player 게임 오브젝트를 조종하는 PlayerController 스크립트를 준비한다. 이 스크립트는 다음 기능을 가져야 한다.
- 사용자의 키보드 입력 감지
- 리지드바디를 사용하여 Player 게임 오브젝트 움직이기
1. 플레이어 조작 스크립트 생성하기
- 프로젝트 창에서 + > C# Script 클릭
- 생성된 스크립트 이름을 PlayerController 로 변경 > 더블 클릭으로 열기(더블 클릭으로 열 때 아래 사진에 빨간색 박스친 부분이 체크표시 되어 있어야함. 빙글빙글 도는 상태일 땐 열지 말고 기다리기!!!!)

게임 오브젝트의 이동을 구현할 때 물리적인 힘을 가하는 방식을 사용할 것이다. 따라서 Player 게임 오브젝트에 추가된 리지드바디 컴포넌트를 변수로 가져오고 사용해야 한다.
2. 변수 선언하기
- PlayerController 스크립트를 다음과 같이 수정
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public Rigidbody playerRigidbody; // 이동에 사용할 리지드바디 컴포넌트
public float speed = 8f; // 이동 속력
void Start()
{
}
void Update()
{
}
}
Rigidbody 타입의 변수를 선언한다고 해서 Rigidbody 타입의 오브젝트가 생성되는 것은 아니다. 하지만 변수 playerRigidbody 를 통해 Rigidbody 타입의 오브젝트를 가리킬 순 있다.
나중에 playerRigidbody 에 Player 게임 오브젝트의 리지드바디 컴포넌트를 할당할 것이다. 그러면 playerRigidbody 를 통해 Player 게임 오브젝트의 리지드바디 컴포넌트를 조종할 수 있다.
6.5 사용자 입력 감지
변수를 선언했으니 입력을 감지하는 기능을 만들어본다. 입력을 감지하려면 Update() 메서드와 Input 클래스의 입력 감지 메서드가 필요하다.
6.5.1 Update() 메서드
게임 세상 속의 모든 정보는 실시간으로 변한다. 실시간으로 변하는 정보를 주기적으로 체크할 필요가 있다. 예를 들어 인공지능 적이 계속 변하는 플레이어의 위치를 주기적으로 체크해야 정상적으로 플레이어를 추적할 수 있다.
따라서 대부분의 게임은 주기적으로 갱신 처리를 한다. 갱신 처리는 일반적으로 화면이 새로 그려지는 주기에 맞춰 실행된다.
초당 프레임이란?
영화는 1초에 24번, 컴퓨터 화면은 1초에 60번 정도 화면을 새로 그린다. 매번 새로 그리는 각각의 화면을 프레임이라고 부른다.
여기서 1초 동안 화면이 새로 그려지는 횟수를 초당프레임 또는 FPS 라고 부른다. PC 나 콘솔 게임의 화면은 보통 60FPS 로 그려진다. 60FPS 는 화면을 1초에 60번 갱신하므로 이전 프레임과 다음 프레임 사이의 시간 간격이 1/60 초이다.
다만 60FPS 는 평균값일 뿐이고, 실제 FPS 는 컴퓨터 성능에 따라 달라진다. 고성능 컴퓨터는 화면을 더 자주 갱신할 수 있으므로 FPS 가 높다. 성능이 좋지 않은 컴퓨터는 FPS 가 낮아서 게임이 뚝뚝 끊기는 것처럼 보일 수 있다.
따라서 PC 게임을 개발할 때는 60FPS 를 평균으로 생각하되, 실제 FPS 는 가변적임을 명심해야 한다.
Update() 메서드는 Start() 메서드처럼 특정 시점에 자동으로 실행되는 유니티 이벤트 메서드이다. Update() 메서드는 한 프레임에 한 번, 매 프레임마다 반복 실행된다.
만약 60FPS 로 화면이 갱신되면 Update() 메서드는 1/60초마다 실행된다. 1초에 60번.. 이렇게 짧은 간격으로 반복 실행되는 Update() 메서드를 사용하면 어던 값이나 입력을 자주 체크하고 갱신하는 처리를 구현할 수 있다.
6.5.2 Input 을 사용한 입력 감지
유니티의 Input 클래스는 사용자 입력을 감지하는 메서드를 모아둔 집합이다. Input 의 입력 감지 메서드는 실행 시점에 어떤 키를 눌렀는지 알려준다.
1. Update() 메서드 작성하기
- PlayerController 스크립트의 Update() 메서드를 다음과 같이 수정.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public Rigidbody playerRigidbody; // 이동에 사용할 리지드바디 컴포넌트
public float speed = 8f; // 이동 속력
void Start()
{
}
void Update()
{
if (Input.GetKey(KeyCode.UpArrow) == true)
{
// 위쪽 방향키 입력이 감지된 경우 z 방향 힘 주기
playerRigidbody.AddForce(0f, 0f, speed);
}
if (Input.GetKey(KeyCode.DownArrow) == true)
{
// 아래쪽 방향키 입력이 감지된 경우 -z 방향 힘 주기
playerRigidbody.AddForce(0f, 0f, -speed);
}
if (Input.GetKey(KeyCode.RightArrow) == true)
{
// 오른쪽 방향키 입력이 감지된 경우 -z 방향 힘 주기
playerRigidbody.AddForce(speed, 0f, 0f);
}
if (Input.GetKey(KeyCode.LeftArrow) == true)
{
// 왼쪽 방향키 입력이 감지된 경우 -z 방향 힘 주기
playerRigidbody.AddForce(-speed, 0f, 0f);
}
}
}
6.5.3 Input.GetKey()
Input.GetKey() 메서드는 키보드의 식별자를 KeyCode 타입으로 입력받는다. Input.GetKey() 메서드는 실행될 때 해당 키를 누르고 있으면 true, 그렇지 않으면 false 를 반환한다.
Update() 메서드는 1초에 수십 번씩 실행되고, 따라서 Update() 내부의 코드도 1초에 수십 번씩 호출된다. 즉, GeyKey() 메서드가 수십 번씩 실행된다.
변경된 스크립트를 저장한다.
6.6 플레이어 사망 처리
이번에는 사망 처리를 실행하는 Die() 메서드를 만들어 플레이어 사망을 구현한다.
6.6.1 Die() 메서드 추가
Die() 메서드는 자신의 게임 오브젝트를 비활성화하여 죽음을 구현하는 메서드이다.
Die() 메서드는 탄알과 플레이어가 충돌했을 때 실행된다. 탄알과 플레이어 사이의 충돌 감지는 7장에서 탄알과 함께 구현한다.
Die() 메서드는 PlayerController 스크립트가 스스로 실행하지 않는다. 대신 플레이어에 부딪힌 탄알이 Player 게임 오브젝트의 PlayerController 컴포넌트에 접근하여 실행한다. 따라서 Die() 메서드는 public 으로 지정되어 PlayerController 클래스 외부에서 접근할 수 있어야 한다.
1. PlayerController 스크립트에 Die() 메서드 추가
- Update() 메서드 아래에 다음과 같이 Die() 메서드 추가
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public Rigidbody playerRigidbody; // 이동에 사용할 리지드바디 컴포넌트
public float speed = 8f; // 이동 속력
void Start()
{
}
void Update()
{
if (Input.GetKey(KeyCode.UpArrow) == true)
{
// 위쪽 방향키 입력이 감지된 경우 z 방향 힘 주기
playerRigidbody.AddForce(0f, 0f, speed);
}
if (Input.GetKey(KeyCode.DownArrow) == true)
{
// 아래쪽 방향키 입력이 감지된 경우 -z 방향 힘 주기
playerRigidbody.AddForce(0f, 0f, -speed);
}
if (Input.GetKey(KeyCode.RightArrow) == true)
{
// 오른쪽 방향키 입력이 감지된 경우 -z 방향 힘 주기
playerRigidbody.AddForce(speed, 0f, 0f);
}
if (Input.GetKey(KeyCode.LeftArrow) == true)
{
// 왼쪽 방향키 입력이 감지된 경우 -z 방향 힘 주기
playerRigidbody.AddForce(-speed, 0f, 0f);
}
}
public void Die()
{
// 자신의 게임 오브젝트를 비활성화
gameObject.SetActive(false);
}
}
6.6.2 gameObject
gameObject 는 컴포넌트 입장에서 자신이 추가된 게임 오브젝트를 가리키는 변수이다. gameObject 는 GameObject 타입의 변수이며 컴포넌트들의 기반 클래스인 MonoBehaviour 에서 제공한다.
모든 컴포넌트는 gameObject 변수를 이용해 자신을 사용 중인 게임 오브젝트(자신의 게임 오브젝트) 에 접근할 수 있다.
playerController 스크립트는 Player 게임 오브젝트에 컴포넌트로서 추가될 것이다. 따라서 이 스크립트에서 gameObject 는 Player 게임 오브젝트를 가리키게 된다.
gameObject 와 GameObject 를 혼동하면 안 된다. 전자는 변수, 후자는 타입이다.
6.6.3 SetActive() 메서드
모든 게임 오브젝트는 스스로를 끄고 켜는 기능을 가지고 있다. 인스펙터 창에서 게임 오브젝트 이름 왼쪽에 보이는 체크 박스가 게임 오브젝트를 활성화/비활성화 하는 버튼이다.
체크를 해제하여 게임 오브젝트를 비활성화하면 해당 게임 오브젝트에 추가된 컴포넌트들도 함께 비활성화되어 동작을 멈춘다. 그렇게 비활성화 된 게임 오브젝트는 씬에서 보이지 않게 된다.
반대로 체크박스를 체크하면 해당 게임 오브젝트와 해당 게임 오브젝트에 추가된 컴포넌트들이 다시 활성화되고 동작한다.
이와 같은 게임 오브젝트 활성화/비활성화를 코드 상에서는 SetActive() 메서드로 실행할 수 있다.
void SetActive(bool value)
SetActive() 는 게임 오브젝트를 나타내는 GameObject 타입에 내장되어 있는 메서드이다. 입력으로 bool 값을 받으며 SetActive(true) 가 실행되면 게임 오브젝트를 활성화한다. false 였다면 비활성화한다.
즉, gameObject.SetActive(false); 는 gameObject 를 사용해 자신의 게임 오브젝트에 접근하고, 접근한 게임 오브젝트의 SetActive(false); 를 실행한다.
6.6.4 PlayerController 컴포넌트 설정하기
완성한 PlayerController 스크립트를 Player 게임 오브젝트에 컴포넌트로 추가하고 실행한다.
1. PlayerController 스크립트를 Player 게임 오브젝트에 추가
- PlayerController 스크립트를 하이어라키 창의 Player 게임 오브젝트로 드래그&드롭

2. 리지드바디 컴포넌트를 playerRigidbody 변수에 할당하기
- 하이어라키 창에서 Player 게임 오브젝트 선택
- 인스펙터 창에서 Rigidbody 컴포넌트를 PlayerController 컴포넌트의 Player Rigidbody 필드로 드래그&드롭

3. 테스트하기
- 플레이 버튼 클릭 > 씬이 시작됨
- 키보드 방향키로 플레이어 조작하기

4. 씬 저장하기
- 플레이 버튼 클릭 -> 플레이 모드 해제
- [Ctrl+S] 로 씬 저장
6.7 PlayerController 스크립트 개선하기
PlayerController 스크립트를 완성했지만 몇 가지 문제점이 있다.
- 조작이 게임에 즉시 반영되지 않는다.
- 리지드바디 컴포넌트의 AddForce() 메서드는 힘을 추가한다. 누적된 힘으로 속도를 점진적으로 증가시키기 때문에 속도가 충분히 빨라지 때까지 시간이걸린다. 또한 이동 중에 반대 방향으로 이동하려는 경우 관성에 의해 힘이 상쇄되어 방향 전환이 금방 이루어지지 않는다.
- 입력 감지 코드가 복잡하다.
- 방향키를 감지하는데 if 문을 네 개 사용했다. 이를 개선하고 싶다.
- playerRigidbody 에 컴포넌트를 드래그&드롭으로 할당하는 것이 불편하다.
- 변수에 컴포넌트의 참조를 할당하는 과정을 코드로 실행하고 싶다.
6.7.1 Start() 메서드 수정
먼저 Start() 메서드를 이용하여 게임이 시작될 때 변수 playerRigidbody 에 리지드바디 컴포넌트의 참조를 할당하도록 수정한다.
1. 리지드바디 컴포넌트를 코드에서 할당하기
- 변수 playerRigidbody 의 Start() 메서드 부분을 다음과 같이 수정
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
private Rigidbody playerRigidbody; // 이동에 사용할 리지드바디 컴포넌트
public float speed = 8f; // 이동 속력
void Start()
{
// 게임 오브젝트에서 Rigidbody 컴포넌트를 찾아 playerRigidbody 에 할당
playerRigidbody = GetComponent<Rigidbody>();
}
void Update()
{
if (Input.GetKey(KeyCode.UpArrow) == true)
{
// 위쪽 방향키 입력이 감지된 경우 z 방향 힘 주기
playerRigidbody.AddForce(0f, 0f, speed);
}
if (Input.GetKey(KeyCode.DownArrow) == true)
{
// 아래쪽 방향키 입력이 감지된 경우 -z 방향 힘 주기
playerRigidbody.AddForce(0f, 0f, -speed);
}
if (Input.GetKey(KeyCode.RightArrow) == true)
{
// 오른쪽 방향키 입력이 감지된 경우 -z 방향 힘 주기
playerRigidbody.AddForce(speed, 0f, 0f);
}
if (Input.GetKey(KeyCode.LeftArrow) == true)
{
// 왼쪽 방향키 입력이 감지된 경우 -z 방향 힘 주기
playerRigidbody.AddForce(-speed, 0f, 0f);
}
}
public void Die()
{
// 자신의 게임 오브젝트를 비활성화
gameObject.SetActive(false);
}
}
변수 playerRigidbody 의 접근 한정자를 public 에서 private 로 변경했다. 따라서 나중에 인스펙터 창에서 PlayerController 컴포넌트를 봤을 때 이전의 Player Rigidbody 필드가 더이상 표시되지 않는 것을 알 수 있다.
6.7.2 GetComponent() 메서드
GetComponent() 메서드는 원하는 타입의 컴포넌트를 자신의 게임 오브젝트에서 찾아오는 메서드이다. GetComponent() 메서드는 꺾쇠 <> 로 가져올 타입을 받는다.
Start() 메서드에서 실행된 GetComponent<Rigidbody>(); 는 자신의 게임 오브젝트에서 Rigidbody 타입의 컴포넌트를 찾아서 가져온다.
GetComponent() 메서드가 컴포넌트를 찾지 못했을 때
게임 오브젝트에 찾으려는 타입의 컴포넌트가 추가되어 있지 않으면 GetComponent() 메서드는 null 을 반환한다.
6.7.3 조작감 개선하기
1. PlayerController 의 기존 Update() 메서드 개선
- PlayerController 스크립트의 Update() 메서드를 다음과 같이 수정
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
private Rigidbody playerRigidbody; // 이동에 사용할 리지드바디 컴포넌트
public float speed = 8f; // 이동 속력
void Start()
{
// 게임 오브젝트에서 Rigidbody 컴포넌트를 찾아 playerRigidbody 에 할당
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);
}
}
수정된 코드는 다음과 같은 동작을 수행한다.
- 수평축과 수직축의 입력을 감지
- 속도를 나타낼 새로운 Vector3 를 생성
- 리지드바디 컴포넌트의 속도를 변경
6.7.4 GetAxis() 메서드
Input.GetAxis() 메서드는 어떤 축에 대한 입력값을 숫자로 반환하는 메서드이다.
이 메서드는 축의 이름을 받는다. 그다음 경우에 따라 감지된 입력 값을 반환한다.
- 축의 음의 방향에 대응되는 버튼을 누름 : -1.0
- 아무것도 누르지 않음 : 0
- 축의 양에 방향에 대응되는 버튼을 누름 : 1.0
입력축은 6.8절 입력 매니저에서 설명할 입력 매니저를 이용해 설정한다. 기본 설정으로 추가되어 있는 Horizontal 축과 Vertical 축의 대응 입력키와 출력되는 입력값은 다음과 같다.
Horizontal 축의 경우
- 음의 방향: 왼쪽 방향키, A 키
- 양의 방향: 오른쪽 방향키, D 키
- Input.GetAxis("Horizontal") 의 출력값
- 음의 방향: -1.0
- 아무것도 누르지 않음: 0
- 양의 방향: 1.0
Vertical 축의 경우
- 음의 방향: 아래 방향키, S키
- 양의 방향: 위 방향키, W키
- Input.GetAxis("Vertical") 의 출력값
- 음의 방향: -1.0
- 아무것도 누르지 않음: 0
- 양의 방향: 1.0
6.7.5 속도 계산하기
Update() 메서드를 살펴보면 xInput 값과, zInput 값을 기반으로 X 와 Z 방향의 속도를 각각 계산하고 새로운 Vector3 데이터를 생성한다.
// 수평축과 수직축의 입력값을 감지하여 저장
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;
6.7.6 Vector3
Vector3 는 원소 x, y, z 를 가지는 타입이다. 위치, 크기, 속도, 방향 등을 나타낼 때 주로 사용한다. 자세한 기능과 수학적 내용은 9, 10장에서 다시 보게된단. 지금은 Vector3 가 x, y, z 를 하나의 변수로 다루는 타입이라는 점만 알면 된다.
6.8 마치며
이 장에서는 씬을 구성하고 Player 게임 오브젝트와 플레이어 조작용 PlayerController 스크립트를 완성했다. 그리고 코드에서 변수에 컴포넌트를 할당하는 방법, 사용자 입력을 감지하는 방법, Vector3 를 사용하는 방법을 배웠다.
다음 장에서는 플레이어를 공격하는 탄알과 탄알 생성기를 만든다.