본문 바로가기
코딩과 알고리즘

유니티3D(Unity3D) 1인칭 시점 조작 #2

이번 시간에는 지난 시간에 이어 1인칭 시점 조작의 이동편에 대해 다루어 보겠습니다.


3D 가상공간에서 1인칭 시점으로 거리를 걷는 것은 현실과 아주 유사합니다.
만일 내가 바라보는 방향이 동쪽이고 앞으로 걷는다면 동쪽으로 이동하는 것이지요.
그러나 내가 바라보는 방향이 서쪽인 상태에서 앞으로 걷는다면 서쪽으로,
북동쪽을 바라보고 앞으로 걷는다면 역시 북동쪽으로 이동하는 것입니다.

그렇기 때문에 1인칭 시점에서의 이동은
바라보는 방향과 아주 밀접한 관련이 있는 것이지요.

유니티는 기본적으로 화살표키와 WASD 키를 전후좌우로 이동하는 키로 인식합니다.

그래서 아래 2개의 함수는 각각 키보드 좌우 이동키(←→ 또는 AD키)의 누름과,
상하 키(↑↓ 또는 WS키)의 눌린 상태값을 나타냅니다.

Input.GetAxis("Vertical")  // 키보드의 좌우 키 누름, 좌=-1, 좌우모두누르지 않음=0, 우 누름=1
Input.GetAxis("Horizontal")  // 키보드의 상하 키 누름, 상=1, 상하모두누르지 않음=0, 하 누름=-1

만일 1인칭 시점에서 앞으로 이동하는 키(↑ 또는 W)를 누를 경우에는 어떤 동작이 이루어지면 될까요?
단, 중력요소가 들어가면 복잡해지니까 중력은 배제하도록 합시다.

다음과 같은 기능이 구현되면 되겠지요.

"앞으로 이동하는 키보드 입력시 카메라를 통해 바라보는 정면 방향으로 이동합니다."

뒤로 이동하는 키가 입력되면 동작은 반대가 되어야 합니다.

"뒤로 이동하는 키보드 입력시 카메라를 통해 바라보는 방향의 후면 방향으로 이동합니다."

좌우로 이동하는 키가 입력될 경우 2가지 방식 중 선택할 수 있는데요.

첫번 째는 "좌 또는 우로 카메라를 회전하는 방법",
두번 째는 "카메라가 바라보는 방향 기준으로 좌 또는 우 방향으로 게걸음처럼 이동하는 방법"

우리는 앞선 챕터에서 이미 마우스로 카메라를 얼마든지 회전할 수 있도록 했기 때문에

두 번째 방법으로 가도록 하겠습니다.

먼저 상하 키에 따라 카메라가 바라보는 방향 기준으로 앞뒤로 이동하는 부분을 살펴봅시다.

이 스크립트는 카메라에 적용되는 스크립트이기 때문에 카메라가 바라보는 앞방향 transform.forward 속성에 바로 접근 가능합니다.
transform.forward 는 거리가 1인 벡터인데요(노말 벡터라고도 합니다).
여기서 벡터란 좌표 또는 방향값을 갖는 3개의 x, y, z 값을 의미합니다.
이경우 좌표보다는 방향의 의미로 사용되지요.

만일 현재 카메라의 위치에 transform.forward 를 더해주면
카메라의 위치가 현재 바라보는 방향 기준으로 1만큼 앞으로 이동하고, 
반대로 현재 카메라의 위치에서 transform.forward 를 빼주면
카메라의 위치가 현재 바라보는 방향 기준으로 1만큼 뒤로 후진합니다

그러니 아래 표현은 상하 화살표 조작에 따라 "앞이나 뒤로 움직일 벡터의 이동량"을 의미합니다.

transform.forward * Input.GetAxis("Vertical")

 

하나 더 보자면 아래 표현은 좌우 화살표 조작에 따라 "좌우로 움직일 벡터의 이동량"을 의미하지요.

transform.right * Input.GetAxis("Horizontal")

 

그렇다면 상하좌우의 화살표 조작에 따라 움직일 벡터의 이동량은 아래와 같습니다.

transform.forward * Input.GetAxis("Vertical") + transform.right * Input.GetAxis("Horizontal")

이제 이 공식을 적용하여 기능을 완성해보겠습니다.
키보드를 누르고 있으면 이동은 지속적으로 이루어져야 하므로,
이 기능은  지속적인 호출이 발생하는 Update() 함수에서 이루어져야 합니다.

우선 이동할 량을 별도의 변수에 담아놓은 다음,

Vector3 move = 
    transform.forward * Input.GetAxis("Vertical") + 
    transform.right * Input.GetAxis("Horizontal");

카메라의 벡터좌표에 더해주면 됩니다.
이 때 아래와 같이 할 수도 있지만,

transform.position += move;

속도를 반영하기 위해 클래스의 앞 부분에 moveSpeed 라는 변수를 선언하고,

public float moveSpeed = 4.0f; // 이동 속도

아래와 같이 작동하도록 하는 것이 좋습니다.
여기서 Time.deltaTime 이란 프레임간 흘러간 시간을 의미하는데요.
속도가 빠른 기기에서든 느린 기기에서든 동일한 속도로 작동하기 위해 적용해주는 공식이라 생각해주시면 됩니다.

transform.position += move * moveSpeed * Time.deltaTime;

만일 속도가 빠른 기기에서는 1초에 Update() 이벤트가 50번 발생하고,
속도가 느린 기기에서는 1초에 Update() 이벤트가 25번 발생한다고 가정할 때.
전자에서 Time.deltaTime 값이 매번 0.02 이고, 후자에서는 Time.deltaTime 값이 매번 0.04입니다.
(물론 이렇게 딱 떨어지지는 않습니다.)

그러니 1초라는 시간 내에서, 0.02를 50번 더한 것과 0.04를 25번 더한 값은 똑같습니다.
그러니 기기속도에 관계없이 초속이 똑같은 것이지요.

지난 스크립트에 이어 완성된 총 스크립트는 아래와 같습니다.

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

public class firstPersonCam : MonoBehaviour
{
    public float turnSpeed = 4.0f; // 마우스 회전 속도    
    private float xRotate = 0.0f; // 내부 사용할 X축 회전량은 별도 정의 ( 카메라 위 아래 방향 )
    public float moveSpeed = 4.0f; // 이동 속도
    
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        // 좌우로 움직인 마우스의 이동량 * 속도에 따라 카메라가 좌우로 회전할 양 계산
        float yRotateSize = Input.GetAxis("Mouse X") * turnSpeed;
        // 현재 y축 회전값에 더한 새로운 회전각도 계산
        float yRotate = transform.eulerAngles.y + yRotateSize;

        // 위아래로 움직인 마우스의 이동량 * 속도에 따라 카메라가 회전할 양 계산(하늘, 바닥을 바라보는 동작)
        float xRotateSize = -Input.GetAxis("Mouse Y") * turnSpeed;
        // 위아래 회전량을 더해주지만 -45도 ~ 80도로 제한 (-45:하늘방향, 80:바닥방향)
        // Clamp 는 값의 범위를 제한하는 함수
        xRotate = Mathf.Clamp(xRotate + xRotateSize, -45, 80);
    
        // 카메라 회전량을 카메라에 반영(X, Y축만 회전)
        transform.eulerAngles = new Vector3(xRotate, yRotate, 0);

        //  키보드에 따른 이동량 측정
        Vector3 move = 
            transform.forward * Input.GetAxis("Vertical") + 
            transform.right * Input.GetAxis("Horizontal");

        // 이동량을 좌표에 반영
        transform.position += move * moveSpeed * Time.deltaTime;
    }
}

스크립트를 수정하시려면 지난번 만들었던 스크립트를 더블클릭하셔서, 비주얼 스튜디오 창에서
위 내용을 붙여넣어 주시면 됩니다.

이 때 주의하실 점은 Project 창의 스크립트 파일명과 클래스명은 반드시 동일해야 합니다.
파일명이 firstPersonCam 이면 스크립트에서도 firstPersonCam 으로 클래스 제목이 지어져야 하니 이 점 주의해주시면 되겠습니다 :)

public class firstPersonCam : MonoBehaviour

이제 유니티에서 플레이틀 시켜보면

아래와 같이 1인칭 시점의 조작이 가능합니다.

필요하신 분에게 도움이 되셨을지 모르겠습니다.
가상세계를 만든다고 할 때 유니티 게임엔진이 상당히 좋은 도구가 될것이라 생각되어 학습중입니다.

오늘도 여기까지 읽어주셔서 감사합니다 :)


다음챕터 중략#1

itadventure.tistory.com/393

 

유니티3D(Unity3D) 중력#1

지난 시간에는 유니티3D 1인칭 시점 조작 #2 에 대해 다루어 보았습니다 itadventure.tistory.com/390 유니티3D(Unity3D) 1인칭 시점 조작 #2 이번 시간에는 지난 시간에 이어 1인칭 시점 조작의 이동편에 대해

itadventure.tistory.com

 

반응형