FPS서바이벌 디펜스

1.기본 캐릭터 움직임

ruripanda 2025. 4. 1. 17:04

본 강좌는 케이디님의 유튜브강좌 영상을 보고 유니티6로 구현한 것 입니다 이렇게 멋진 강좌를 만드신 케이디님을 존경합니다

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    [SerializeField]
    private float walkSpeed;
    [SerializeField]
    private float lookSensitivity;
    [SerializeField]
    private float cameraRotationLimit;
    private float currentCameraRotationX = 0;

    [SerializeField]
    private Camera theCamera;

    private Rigidbody myRigid;

    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {
        myRigid = GetComponent<Rigidbody>();
    }

    // Update is called once per frame
    void Update()
    {
        Move();
        CameraRotation();
        CharacterRotation();
    }
    private void CharacterRotation()//좌우 캐릭터 회전
    {
        float _yRotation = Input.GetAxisRaw("Mouse X");
        Vector3 _characterRotationY = new Vector3(0f, _yRotation, 0f) * lookSensitivity;
        myRigid.MoveRotation(myRigid.rotation * Quaternion.Euler(_characterRotationY));
        Debug.Log(myRigid.rotation);
        Debug.Log(myRigid.rotation.eulerAngles);
    }

    private void CameraRotation()
    {
        float _xRotation = Input.GetAxisRaw("Mouse Y");
        float _cameraRotationX = _xRotation * lookSensitivity;
        currentCameraRotationX -= _cameraRotationX;
        currentCameraRotationX = Mathf.Clamp(currentCameraRotationX, -cameraRotationLimit, cameraRotationLimit);

        theCamera.transform.localEulerAngles = new Vector3(currentCameraRotationX, 0f, 0f);
    }

    private void Move()
    {
        float _moveDirx = Input.GetAxisRaw("Horizontal");//좌우 방향키를 입력시 +1 ~ -1이 반환된다
        float _moveDirZ = Input.GetAxisRaw("Vertical");//상하 움직임 입력시 +1 ~ -1이 반환된다

        Vector3 _moveHorizontal = transform.right * _moveDirx;
        Vector3 _moveVertical = transform.forward * _moveDirZ;//실제 입력과 같이 이동을 처리함

        Vector3 _velocity = (_moveHorizontal + _moveVertical).normalized * walkSpeed;

        myRigid.MovePosition(transform.position + _velocity * Time.deltaTime);
    }
}

 

이번 강좌는 케이디님의 유니티강좌 중 FPS서바이벌 디펜스를 보고 만든 것 입니다

강좌 시작합니다

 

일단 하이러키에서 3D Object > Plane를 선택해서 바닥을 만들어 줍니다

 

그리고 다음은 하이러키에서 3D Object > Capsule 를 만들고 Capsule 오브젝트를 Player이라고 명칭을 바꿉니다

그 뒤 Main Camera를 Player에 넣어줍니다

 

그뒤 Player의 Position 값 중 Y값을 1로 높여줍니다

이제 이 Capsule 오브젝트가 플레이어의 역활을 하게 됩니다

 

그 뒤 Player 오브젝트에 Rigidbody 컴포넌트를 넣어주고

Freeze Rotation부분에서 X와 Z부분을 고정시켜 줍니다

이렇게하면 캡슐 오브젝트가 쓰러지지 않고 값이 고정됩니다

 

이제 Player 오브젝트를 제어하기 위해 C# 스크립트를 만들고 이름은 PlayerController이라고 명명합니다 그뒤 Player 오브젝트에 명명한 스크립트를 넣어줍니다

[SerizlizeField]라는 것이 보이는데 이건 인스펙터에 안보이게 만들어진 변수를 인스펙터에 보이게 만들어 주는 것이다

private로 공개도가 설정된 변수는 원래 인스펙터에 안보인다 우린 그걸 보이게 하기 위해 써넣었다

 

walkSpeed는 움직이는 스피드다

lookSensitivity는 카메라의 민감도라고 생각하면 된다

cameraRotationLimit는 플레이어가 고개(Camera)를 위로 들때 어드정도까지 들거나 내릴 건지 상한선을 정해준 것이다

currentCameraRotationX는 카메라의 X값을 0이라고 지정해주기 위해 만들은 것이다

 

14번 줄 theCemera는 카메라를 인스펙터로 연결해줄 것이다

이렇게 연결해주자

이제 void Update함수에 사용되는 함수들을 작성해주자

Move()함수를 보자

일단 float변수로 선언해서 _moveDirX를 선언해주었다

그뒤 Input.GetAxisRaw("Horizontal"); 이라고 작성해주었는데 Horizontal이 어디 있는지는 잘모른다

이건 Input Manager에 가면 존재한다

Horizontal은 왼쪽 오른쪽으로 축이 움직이는 것을 측정하는 값이다

 

즉 우리는 인풋메니져의 Horizontal 값을 받아오는 함수를 만들은 것이다

Vertical는 그럼 어떤 것일까?

전진과 후진을 관리하는 것이다

이것도 InputManager에 존재한다

 

 

그럼 55번줄과 56번 줄은 어떤 의미일까?

Vector3에 _moveHorizontal 변수는 = transform.right * _moveDirX;라고 되어 있다

이 얘기는 Player 오브젝트의 Vector3 _moveHorizontal

transform.right 에 _moveDirX를 곱한 값과 같다는 뜻이다 즉 이렇게하면 플레이어가 왼쪽, 오른쪽 회전을 한다

56번줄은 Vector3 _moveVertical = transform.forward * _moveDirZ; 라고 작성되 어있는데

쉽게 말하면 transform.forward에 _moveDirZ 를 곱한 값이라고 생각하면 된다

즉 이렇게 작성을 하면 Vector3가 영향을 받아서 움직이게 된다

 

그리고 우리는 Vector3 _velocity 변수 안에 (_moveHorizontal + _moveVertical).normalized * walkSpeed 를 넣어줬는데

이건 대각선 방향으로 움직임을 관리하기 위해 작성해준 변수이다

위의 _moveHorizontal + _moveVertical을 묶어준 뒤 . normalized를 입력해서 대각선이동이 자연스럽게 해준 것이다

뒤의 * walkSpeed는 우리가 이동하는 속도를 곱해준 것이다

 

이해를 쉽게 하기 위해서 필자가 그림을 대충 끄적였다

초록색 선이 normalized가 적용되어서 움직이는 범위라고 생각하면 편하다

그리고 이제 마지막으로 myRigid.MovePosition함수로 리지드바디에 직접 움직임을 입력해주고 플레이어 오브젝트가 움직이게 했다

내부 값은 transform.position과 _velocity를 더한 값을 * Time.deltaTime로 곱해줬는데

Time.deltaTime는 쉽게 말하면 실제 시간을 곱해준 것과 같다고 생각하면 된다

만약 이게 없다면 함수가 컴퓨터의 성능에 따라 프레임이 뒤죽박죽이 되므로 실제 시간을 곱해서 움직임에 제약을 두는 것이다

이렇게 해주면 Move()함수는 끝난 것이다

 

다음은 CameraRotation()함수를 보자

float _xRotation = Input.GetAxisRaw("Mouse Y");라고 작성하여 사용자 마우스가 위로 움직이는 인풋메니져에서 가져왔다

그뒤 43번 줄에 _cameraRotationX = xRotation * lookSensitivity;라고 입력하여

우리가 작성해준 _xRotation변수에 lookSensitivity를 곱해줘서 위로 움직인 값을 받아와 준다

currentCameraRotationX가 있는데

이 변수에 일단 위에 우리가 작성해준 변수 _cameraRotationX를 더해주면 시점 이동이 마우스 움직임과 반대로 적용이되고

이걸 빼주면 시점 이동이 정상적으로 적용된다

우리는 정상적으로 적용을 위해서 -= 를 넣어서 실시간으로 빼줬다

그뒤  Mathf.Clamp()를 적용해서 currentCameraRotationX의 값이 -cameraRotationLimit와 cameraRotationLimit의 값 사이에 갇히게 만들었다

그런데 여기서 문제가 우리는 cameraRotationLimit의 값을 안 넣었다는 점이다

 

인스펙터에 들어가서 45로 값을 맞춰주자

그러면 시점이 -45와 +45도에 갇히게 된다

 

그 뒤 카메라에 theCamera.transform.localEulerAngles 변수에 우리가 지금까지 작성한 currentCameraRotationX함수를

new Vector3로 넣어서 실시간으로 움직이게 한다

 

localEulerAngles은

Transform컴포넌트에서 Rotation을 관리한다고 쉽게 생각하자

 

이제 CharacterRotation()함수를 보자

33번 줄에 flaot _yRotation = Input.GetAxisRaw("Mouse X");라고 변수를 작성해서 플레이어 마우스 X움직임 값을 받아온다

X값은 좌우로 움직이는 값을 말한다

그뒤 34번 줄에 Vector3 _characterRotationY 변수를 선언해주고

new Vector3(0f, _yRotation , 0f)로 우리가 위에 선언한 마우스 X값을 넣어주고 lookSensitivity를 곱해서 민감도를 적용해주었다

그뒤 35번 줄에 myRigid.MoveRotation 안에 myRigid.rotation을 넣어주고 Quaternion.Euler( _characterRotationY )을 곱해줘서 좌우로 시점이 움지이는 것을 구현해주자

3D로 게임을 만들면 중요한게 있는데 Quaternion(쿼터니언)이 정말 중요하다 이건 두고두고 쓸 단어이니 기억해두자

36번과 37번은 잘 작동하는지 확인하는 디버그이다

 

그뒤 유니티엔진으로 돌아와서

인스펙터에 PlayerController스크립트의 값을 조정해줍니다

 

이제 잘 실행되는지 한번 보자

 

시점 이동이 깔끔하게 구현되었다

이동은 생각해보니 녹화를 않했다 ㅎㅎ

 

ps

자 이제 공부 다시 시작합니다

'FPS서바이벌 디펜스' 카테고리의 다른 글

6.재장전, 정조준, 반동  (0) 2025.04.17
5.총 구현과 총구섬광  (0) 2025.04.15
4.팔 구현  (0) 2025.04.14
3.지형 제작  (0) 2025.04.14
2.심화 캐릭터 움직임  (0) 2025.04.02