게임에서 캐릭터를 조종하는 것은 가장 기본적인 즐거움 중 하나입니다. 키보드로 움직임을 제어하고, 마우스로 시점을 자유롭게 전환하는 조작 방식은 FPS(1인칭 슈팅)나 TPS(3인칭 슈팅) 게임의 핵심이 됩니다. 이번 글에서는 유니티에서 WASD 키보드 입력과 마우스 움직임을 조합하여 캐릭터를 이동하고 회전시키는, 완성도 높은 코드를 단계별로 살펴보겠습니다. 이 코드는 단순 이동을 넘어, 점프 기능까지 포함하여 게임 플레이의 기초를 다져줄 것입니다.
1. 캐릭터 조종 스크립트 작성
PlayerController.cs
라는 이름의 C# 스크립트를 새로 만들고, 아래 코드를 입력해 주세요. 이 스크립트는 플레이어 캐릭터 오브젝트에 부착됩니다.
C#
using UnityEngine;
[RequireComponent(typeof(Rigidbody))] // Rigidbody 컴포넌트가 필수임을 명시
public class PlayerController : MonoBehaviour
{
[Header("이동 및 점프 설정")]
public float moveSpeed = 5f;
public float jumpForce = 5f;
private bool isGrounded = false;
private Rigidbody rb;
[Header("시점 제어 설정")]
public Transform playerCamera;
public float lookSensitivity = 2f;
public float verticalLookLimit = 90f; // 시야각 상하 제한
private float horizontalRotation = 0f;
private float verticalRotation = 0f;
void Awake()
{
rb = GetComponent<Rigidbody>();
// 마우스 커서를 게임 화면 중앙에 고정하고 숨깁니다.
Cursor.lockState = CursorLockMode.Locked;
}
void Update()
{
// === 키보드 입력으로 이동 방향 계산 ===
float moveX = Input.GetAxis("Horizontal"); // A, D 키
float moveZ = Input.GetAxis("Vertical"); // W, S 키
// 이동 방향 벡터를 월드 좌표계 기준으로 변환
Vector3 moveDirection = transform.forward * moveZ + transform.right * moveX;
// 이동 방향에 속도를 곱하여 리지드바디에 속도 적용
// 단, y축 속도는 유지
rb.velocity = new Vector3(moveDirection.x * moveSpeed, rb.velocity.y, moveDirection.z * moveSpeed);
// === 점프 입력 처리 ===
if (Input.GetButtonDown("Jump") && isGrounded) // 스페이스바
{
rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
isGrounded = false; // 점프 후 착지 상태를 false로 변경
}
// === 마우스 입력으로 시점 회전 ===
float mouseX = Input.GetAxis("Mouse X") * lookSensitivity;
float mouseY = Input.GetAxis("Mouse Y") * lookSensitivity;
// 수평 회전: 캐릭터 전체를 Y축 기준으로 회전
horizontalRotation += mouseX;
transform.localRotation = Quaternion.Euler(0f, horizontalRotation, 0f);
// 수직 회전: 카메라만 X축 기준으로 회전, 상하 시야각 제한
verticalRotation -= mouseY;
verticalRotation = Mathf.Clamp(verticalRotation, -verticalLookLimit, verticalLookLimit);
if (playerCamera != null)
{
playerCamera.localRotation = Quaternion.Euler(verticalRotation, 0f, 0f);
}
}
// 바닥과 충돌했을 때 isGrounded 상태를 true로 변경
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag("Ground"))
{
isGrounded = true;
}
}
}
2. 유니티 에디터에서 설정하기
- 컴포넌트 추가: 플레이어 캐릭터 오브젝트에
Rigidbody
컴포넌트를 추가합니다.Constraints
항목에서Freeze Rotation
의 X, Y, Z축을 모두 체크하여 캐릭터가 의도치 않게 넘어지는 것을 방지하세요. - 카메라 배치:
Main Camera
를 플레이어 캐릭터 오브젝트의 **자식(Child)**으로 배치합니다. 카메라의 위치를 캐릭터의 눈높이에 맞게 조정합니다. - 스크립트 부착: 작성한
PlayerController.cs
스크립트를 플레이어 캐릭터 오브젝트에 부착합니다. - 변수 연결: 인스펙터(Inspector) 창에서
PlayerController
컴포넌트의Player Camera
필드에 씬에 있는Main Camera
오브젝트를 드래그하여 연결합니다. - 태그 설정: 바닥(Ground) 오브젝트의 태그(Tag)를 “Ground”로 설정하여
OnCollisionEnter
함수가 바닥과의 충돌을 감지할 수 있도록 합니다.
3. 코드 해설 및 심화 포인트
Rigidbody
와FixedUpdate()
대신Update()
: 이 코드는 물리 기반이 아닌Transform
조작을 주로 사용하기 때문에Update()
에서 이동을 처리합니다.Rigidbody.velocity
를 직접 수정하면 물리엔진의 영향을 받으면서도 정밀한 제어가 가능합니다.Awake()
함수에서Rigidbody
컴포넌트를 미리 캐시하여 성능을 최적화했습니다.- 키보드 이동:
Input.GetAxis("Horizontal")
과Input.GetAxis("Vertical")
로 방향을 계산한 후,transform.forward
와transform.right
를 곱해 캐릭터의 현재 회전 상태에 맞는 로컬 방향으로 움직입니다. - 마우스 회전:
transform.localRotation
은 캐릭터의 수평 회전을 담당하고,playerCamera.localRotation
은 카메라의 수직 회전을 담당합니다. 이렇게 수평과 수직 회전을 분리해야 마우스로 위아래를 바라볼 때 캐릭터의 몸통은 좌우로만 회전하는 자연스러운 시점 제어가 가능합니다. Mathf.Clamp()
: 이 함수는 카메라의 상하 시야각이 특정 범위를 넘지 않도록 값을 제한합니다.verticalRotation = Mathf.Clamp(verticalRotation, -90f, 90f);
덕분에 플레이어가 하늘을 본 상태에서 계속 마우스를 움직여도 고개가 뒤로 꺾이지 않습니다.OnCollisionEnter()
: 물리엔진을 이용해 바닥과의 충돌을 감지합니다. 바닥에 닿았을 때isGrounded
상태를true
로 바꿔 점프가 가능하도록 합니다.Cursor.lockState
: 게임 시작 시 마우스 커서를 화면 중앙에 고정하고 보이지 않게 하여, 게임 플레이에 방해가 되지 않도록 합니다.
이 코드는 FPS나 3인칭 게임의 가장 기본적인 플레이어 컨트롤러를 완성합니다. 이 구조를 기반으로 달리거나 웅크리는 동작, 벽 타기 등 다양한 기능을 추가하여 더욱 풍부한 게임을 만들어보세요.