ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • RPG 듀토리얼 03. Ray & CamController
    유니티 프로젝트/RPG 듀토리얼

    오늘은 Ray를 생성하여 발사하는 로직을 구현할 예정입니다.

     

    이 Ray의 사용처는 매우 다양하지만

     

    이번 글에서는 player를 클릭해 Inventory / info 창이 열리게 설정할 것입니다.

    Ray 생성에 앞 서

     

    먼저 카메라 회전을 담당할 스크립트 CamController부터

     

    짧게 보고 가겠습니다.


    CamController

    구현 목록은 간단합니다.

     

    GetMouseButton(1)로 마우스 왼쪽 버튼이 눌린 상태에서

     

    마우스 움직임 방향대로 좌/우/상/하 회전을 하게 됩니다.

     

    스크립트부터 바로 보시겠습니다.

     

    선언 변수들부터 보겠습니다.

    camAxis_Central : MainCamera를 담고 있는 부모 오브젝트입니다

    (플레이어의 위치 + y축 0.4f의 높이)에 붙어 있습니다.

     

    cam : player를 비춰 줄 메인 카메라입니다.

     

    camSpeed : 캠이 회전할 스피드입니다.

     

    mouse X/Y : Input.Manager 에 Mouse X / Mouse Y의 반환된 -1.0f - 0 - 1.0f를 담고 있습니다.

     

    wheel : Input.GetAxis("Mouse ScrollWheel")의 -1.0f - 0 - 1.0f 값입니다.

    (사용 필요성이 크게 느껴지지 않아 아직 추가를 안 한 상태입니다.)

     

    int up / down : 회전 값을 인스펙터 창에서 조절하며 테스트하기 위해 선언한 변수입니다.

     

    player : 플레이어입니다.

     

    업데이트 함수에서는 if (Input.GetMouseButton(1)) 의 조건으로

     

    MouseButton(1)로 마우스 오른쪽 버튼이 눌려 있을 때

    CamMove()를 실행하라고 조건을 걸어주었습니다.

     

    눌려 있을 때를 받는 MouseButton과

    MouseDown(첫 눌렸을 시) / MouseUp(떼어졌을 시)가 존재하며

    뒤에 인자 값은 0(마우스 왼쪽) / 1(마우스 오른쪽) / 2(가운데 휠)을 받습니다.

     

    CamMove 함수를 보겠습니다.

     

    MouseX에 +=연산자로 Input.GetAxis(Mouse X)의 반환 값을 누적시켜줍니다.

    Mouse X : InputManager에 있는 Axes로 마우스 좌/우 방향을 -1.0f - 0 - 1.0f를 반환시켜 줍니다.

     

    MouseY에 +=연산자로 Input.GetAxis(Mouse Y)의 반환 값을 누적시켜줍니다.

    Mouse Y : InputManager에 있는 Axes로 마우스 상/하 방향을 -1.0f - 0 - 1.0f를 반환시켜 줍니다.

     

    하지만 서향 문화? 의 차이라고 하는데

    마우스를 상으로 올리면 -값을 주어 아래로

    마우스를 하로 내리면 + 값을 주어 위로

    되는 반대가 되는 현상이 있습니다.

    이를 뒤집어 주기 위해 마지막에 -1을 곱해 주는 코드입니다.

     

    이후 MouseY의 값에 제한을 걸어주는 코드입니다.

    if(mouseY의 값이 지정한 up보다 크다면?)

    mouseY의 값은 up이 됩니다.

    if(mouseY의 값이 지정한 down보다 작다면?)

    mouseY의 값은 down이 됩니다.

     

    즉 상/하 의 제한값을 걸어준 것입니다.


    마지막 

    코드를 보겠습니다.

    camAxis_Central의 회전은 Quaternion.Euler로 오일러 값을 쿼터니언으로 바꿔 주었습니다.

    (camAxis_Central 이 회전하면 자식으로 붙은 MainCamera도 함께 회전을 합니다)

     

    이후 new Vecto3의 인자 값인 (float x, float y, float z)로 받아 왔습니다.

    x 값 : camAxis_Central.ratation.x + mouseY

    y 값 : camAxis_Central.rotation.y + mouseX

    z 값 : 0

     

    오브젝트의 회전 방향과 마우스의 움직임 방향을 잘 봐야 합니다.

    오브젝트의 x축 회전은 마우스로 볼 땐 상/하 mouse Y입니다.

    오브젝트의 y축 회전은 마우스로 볼 땐 좌/우 mouse X입니다.

     

    camAxis_Central과 마우스 방향을 맞춰 주어 회전을 시키는 모습입니다.

     

    - 추가 -

    캠 Zoom 기능.

    Update문에서 실행하였습니다.

    특이 사항으로 캠의 위치를 조절하지 않고 카메라에 붙어있는 fieldOfView를 이용해 Zoom 기능을 연출했습니다.

    Camera에 붙은 Field of View

    짧게 동작 구현 동영상을 보시고, Ray를 생성하는 코드로 가겠습니다.

     

    00 : 11초

    Ray를 생성하는 코드는 PlayerController에서 실행하겠습니다.

     

    지난번에 빨간 줄로 했는데, 얼핏 보면 스크립트 오류 뜬것 같아서... 녹색 줄로 바꿨습니다..

     

    우선 EventSustem을 사용하기 위해서 네임스페이스를 선언해 주는 모습입니다.

     

    수많은 함수들이 내장되어 있지만, 그중 IPointerDownHandler를 사용했습니다.

     

    유니티에서 지원하고 있는 (Eventsystems)은 많은 이벤트를 지원하고 있습니다.

     

    그 중에서도 현재 사용한 

     

    IPointerDownHandler / IPointerUpHandler를 보겠습니다.

     

    IPointerDownHandler : 버튼을 클릭 / 터치하는 순간 실행되며

    IPointerUpHandler : 버튼을 클릭 / 터치를 떼는 순간 실행됩니다.

     

    버튼 뿐만이 아닌 게임 오브젝트에는 모두 가능한 인터페이스이기에, 다양한 구현을 가능하게 만들어 줍니다.

     

    진짜 생각보다 Eventsystem 안에 다양한 인터페이스가 존재하기에..

    지금은 아니더라도 앞으로도 프로젝트에 모두 한번씩 다 해볼 수 있을까??라는 생각이 듭니다.

    프로젝트에 쓰이진 않더라도 한번씩은 연습을 해봐야겠습니다.


    현재 PlayerController를 담고 있는 오브젝트는 

    UI항목인 Canvas 안에 Panel에 붙어 있습니다.

     

    즉 현재 보는 Maincamera 에서 Ray를 생성하게 되어 제어를 하게끔 구현했습니다.


    IpointerDown / IPointerUp 인터페이스 구현


    그럼 이제 레이를 생성 후 발사하는 코드를 보시겠습니다.

    이 생성하여 발사한 레이는

    player, Npc를 클릭할때나, 몬스터/보스를 클릭하는 데에 이용이 될 것입니다.

    우선 가장 중요한 게, 발사한 레이에 맞은 녀석의 충돌처리를 하려면 Collider가 있어야 합니다. (기본이지만 중요함)

    이 Collider가 없이 코드상 오류는 없는데.. 안 되는 이유를 찾으려고 했던 뼈아픈 기억이 있습니다..

     

    Ray를 ray변수를 cam.ScreenPointToRay 즉 메인 카메라로 보는 시점의 스크린의 점 중에서

    eventDtat.position(터치/클릭 한 지점)에 생성되게 만들어 주었습니다.

     

    Physics.Raycast(ray, out hit)

    Physics은 물리학이라는 뜻으로 보아

    물리를 담당하는 클래스인 것을 알 수 있고

     

    Raycast를 활용하여 레이를 발사하는 코드입니다.

    Raycast : 직선을 투영하여 대성에 적중되면 true를 리턴하는 물리 함수입니다.

     

    뒤에 인자로는 ray(제가 생성한 ray)

    RaycastHit로 만든 out hit (ray에 충돌된 충돌체를 담을 변수)입니다.

     

    여기서 out키워드는 매개변수 한정자라고 부르는데,

    return을 통해 직접 갑을 매겨주지 않아도 hit에 레이 캐스트 결과 정보를 바로 저장한다고 보시면 됩니다.

     

    IPointerDownHandler에서

    if (hit.transform!= null) 

    hit(레이 캐스트로 발사하여 맞은 충돌체의 transform이!= null이 아니라면?

     

    touchEffect : 클릭한 지점을 시각화해줄 오브젝트입니다.

     

    touchEffect

    Animation으로 시각화를 더 해 주었습니다.

     

    단순히 SetActive를 이용해 켜 있을 수 있으니, (false) 비활성화를 먼저 해주고 ture(활성화)를 해주는 코드입니다.

     

    이 touchEffect의 위치는 = cam(Main.Camera의 WorldToScreenPoint(hit.point)입니다.

    WorldToScreenPoint : 월드 스페이스에서 스크린 스페이스로 좌표 공간을 변경해 주는 유니티 함수입니다.

    스크린 스페이스의 좌표에서 지점은 hit.point(레이를 쏴 맞은 충돌체의 위치)입니다.


    그럼 이제 플레이어를 클릭/터치했을 시 info / inventory 창이 팝업 되는 동작을 구현해보겠습니다.

    if (hit.transform.tag == "Player") : hit의 트랜스폼의 태그가 "Player"라면? 의 조건문입니다.

     

    첫 번째 코드는 Manager에 접근하여 playerOneShot 함수를 활용해 managerSE에 있는 btnA의 클립을

    실행시켜주는 코드입니다.

    Manager 스크립트
    ManagerSE 스크립트
    Hiararchy 창

    PlayOnShot 함수는 Play와 같지만, Play는 소리 중첩 시 마지막 클립만 재생이 되며

    PlayOnShot 은 소리 중첩이 가능합니다.

    Manager에 접근해 managerInven에 있는 charInfoFrame의 SetActive를 통한 활성화와

    OpenBag() 함수를 실행해 주는 모습입니다.

     

    ManagerInven 스크립트까지 보려고 했는데, 연관되어 있는 코드들이 많아서

    다음 글에 바로 올리겠습니다.

     

    Player를 클릭하면 뜨는 TouchEffect와

    아직 설명드리진 않았지만, charInfoFrame의 활성화와 OpenBag함수가 실행되는 모습을 영상으로 보겠습니다.

     

    00 : 13초

     

    댓글

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