ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • RPG 듀토리얼 02. 플레이어 이동 구현
    유니티 프로젝트/RPG 듀토리얼

    안녕하세요. 오늘은 player의 이동 구현을 살펴보겠습니다.

     

    player에게 필요한 구현들은 크게 4가지로 볼 수 있는데요

     

    이동 / 공격 / 슬라이드 / 스킬로 볼 수 있습니다.

     

    이동 / 공격 = 매 항시 작용 가능

     

    슬라이드 / 스킬 = 쿨타임을 가진 스킬로 분류를 하겠습니다.


    우선 초기 이동 컨셉부터 보겠습니다.

     

    레이를 이용해 플레이어를 움직이는 모습입니다.

     

    초기 콘셉트를 이렇게 쿼터뷰로 잡고 테스트를 해봤는데

     

    제 역량 부족도 있겠지만, 제 가 만든 게임의 몰입감의 요소가 부족했습니다.

     

    그리 하여 이동 구현을 솔 더뷰로 하게 뜸하여 직접 플레이를 하며 몰입감을 더 해주고

     

    추 후 조이스틱을 추가하기로 했습니다.


    이걸 어디서부터 설명을 해야지 순서대로 잘 갈 수 있을까 고민을 많이 했습니다.

     

    몇 안 되는 코드들이지만, 설명을 함에 있어 뒤죽박죽 된다면 

     

    글을 쓰는 사람도 어렵지만 보는 사람도 곤혹일 것 같다는 생각이 들었습니다.

     

     

    그래서... 빠르진 않지만 천천히 차근차근 나아가겠습니다.

     

    네, 그럼 먼저 플레이어의 이동 구현부터 보겠습니다.

     

    PlayerController 스크립트 입니다.

    이 PlayerController는 플레이어의 컨트롤을 담당해줄 스크립트입니다.

     

    우선 Update문에서 현재 필요한 빨간 줄부터 보겠습니다.

     

    1. playerAni.SetBool("Walk", playerAxisNav.velocity!= Vector3.zero &&!(onCasting))

     

    SetBool ("Walk"가 실행되는 조건을 Nav.velocity가!= Vextor3.zero(0, 0, 0) 이 아닐 때,

     

    그리고 OnCasting 중이!(Not 논리 연산자)로 아닐 때를 걸어주었습니다.

    캐스팅 중인지 체크를 해줄 불 변서 onCasting은 스킬 관련 때 보겠습니다.

     

    즉 player의 naviMeshAgent의 velocity가 제로가 아닐 때 애니메이션 Walk를 실행시켜줍니다

    &&! onCasting

     

    2. PlayerMove() 함수를 실행시킵니다.

     

    3. camAxis_Central의 위치를 플레이어의 포지션 + y축의 0.4f의 위치로 항상 따라오게 해 줍니다.

     

    우선 2. PlayerMove 함수부터 보습니다.


    3. camAxis_Central의 이해를 돕기위한 이미지 입니다.


    PlayerMove함수

    PlayerMove함수입니다.

     

    주석 코드는 현재 테스트용, 제가 알아보기 위함, 사용하다 안 씀 등 종류가 많습니다. 주석 코드는 빼고 설명을 하겠습니다.

     

    우선 if (! onCasting)입니다.

    onCasting : 현재 캐스팅 중인지 체크해줄 불 변수입니다.

    !(Not 논리 연산자)로 캐스팅 중이 아닐 시에만 움직이게 했습니다.

    즉 onCasting == true인 상태에선 움직이지 못합니다.

     

    movement = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"))

    new Vector3에 (Horizontal, 0 Vertical)을 해 주는 모습입니다.

     

    Horizontal / Vertical : 유니티 자체 Input.Manager에 저장되어 있는 Axes입니다.

    Horizontal : a, d 방향키←→ 를 입력 시 -1.0f - 0 - 1.0f를 반환해 줍니다.

    Vertical : w, s 방향키↑↓를 입력 시 -1.0f - 0 - 1.0f 를 반환해 줍니다.

     

    new Vector3(-1.0f - 0 - 1.0f , 0 , -1.0f - 0 - 1.0f )를 받은 것과 같습니다.

     

    이렇게 방향이 정해지면 movement에 반환 값인 new Vector3을 할당해 줍니다


    할당받은 movement는 normalized로 길이를 1로 만들어 줍니다.

     

    유니티에서의 이동하는 오브젝트를 균일한 이동으로 만들어 주기 위해서는

    normalized와 같이 1로 만드는 정규화 방식이 필요합니다.

     

    정규화를 하지 않은 벡터에서 대각선으로 이동시 1.414214...으로 반환되는 것을 생각하면 됩니다.

     

    이렇게 정규화된 벡터를 방향벡터라고 부른다고 하는데요.

    보통 Direction(방향)을 줄인 dir로 변수명을 입력한다고 합니다.

    저는 현재 movement로 변수명을 지어주었습니다.


    이해 돕기용 그림..

    제가 설명엔 영 소질이 없는 것 같아... 사진으로 대체했습니다.

     

    Player의 위치 + y0.4f 값에 cam_CentralAxis가 있습니다.

    그 아래 자식으로 Main Camera를 두어 

    플레이어가 회전하면 Cam_CentralAxis도 같이 회전하며

    MainCamera도 Cam_CentralAxis를 따라 회전하게 되게 구현되어 있습니다.

    이해 돕기용 캡처


    그럼 이제  movement != Vector3.zero 이동 중인 것으로 판단해 아래 조건문을 실행시키는 부분부터 살펴보겠습니다.

    우선 playerAxis를 회전시켜 줍니다.

    PlayerAxis가 회전하게 되면 자식으로 담겨 있는 Player도 같이 회전됩니다.

     

    Quaternion.Euler함수를 사용하였습니다.

    Quaternion.Euler : 오일러 각을 쿼터니언으로 변경시켜 줍니다 인자는 (float x, float y, float z)입니다.

     

    이 값에선 x와 z의 값은 0으로 두고

    y(좌/우) 회전만 camAxis_Central의 rotation.y + camAxis.mouseX 값을 받아왔습니다.

    이에 * camSpeed를 곱해 줘

    cam이 회전되는 스피드와 player(playerAxis)가 회전되는 부분을 맞춰 주었습니다.

     

    camAxis.mouseX : 는 CamController 스크립트의 mouseX += Input.GetAxis("Mouse X") 값입니다.

    Move 함수가 끝난 후 CamController 스크립트로 바로 넘어가겠습니다.

     

    이건 Player(PlayerAxis)를 Translate 함수로 이동시켜 주는 모습입니다.

    인자는 (movement(방향) * moveSpeed(스피드) * Time.deltaTime로 균일한 속도를 맞춰주었습니다)

     

    player의 회전 부분입니다.

    localRotation으로 부모가 있으므로 부모를 중심으로 상대적인 회전을 합니다.

    부모가 존재하지 않다면 localRotation = rotation은 같습니다.

     

    Quaternion.Slerp 함수로 보간하여 좀 더 부드러운 이동이 가능하게 했습니다.

    인자는 A벡터 와 B 벡터의 사이를 float t (6 * Time.deltaTime)으로 0 - 1.0퍼센트 비율로 보관합니다.

     

    여기서 B벡터에 Quaternion.LookRotation 함수를 사용했는데,

    이 벡터를 매개변수로 넣어주면 그 벡터의 방향을 쳐다보게끔 자기 자신의 방향을 회전하는 것을 뜻합니다.

     

     

    이제 마지막으로 movement!= Vector3.zero 가 아니라면 실행되는 

    player.GetComponent <Animator>(). SetBool("Walk", true) 코드와

     

    반대로 movement == Vector3.zero 라면

    실행되는 player.GetComponent<Animator>().SetBool("Walk", false) 코드를 보겠습니다.

     

    player.GetComponent(). SetBool("Walk", true) / player.GetComponent().SetBool("Walk", false)

    코드는 둘 다 SetBool을 이용해 "Walk"에 접근하는 것은 똑같지만

    뒤의 true / false 값이 달라집니다.

     

    이동 중이라면 Walk를 true로 / 이동중이 아니라면 Walk를 false로 와 같습니다.

     

    현재 진행된 동작을 영상으로 보겠습니다.

     

    00 : 12초

     

     

     

    댓글

김효겸 / Tel. 010-7735-0580 / E-mail. dollzzang2@hanmail.net