ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • RPG 듀토리얼 05. ITEM_in the Bag
    유니티 프로젝트/RPG 듀토리얼

    안녕하세요.

     

    오늘은 Bag 오브젝트 안에 Item 부분을 설명드릴 예정입니다.

     

    다른 글들도 정리가 잘 되어있지 않은 편이지만..

     

    특히나 이 Item 부분은 더욱더 어디서부터 시작을 해야 할지 모르겠습니다.

     

    우선 구현 목차를 간단하게 정리해 보겠습니다.


    (아이템이 가방 안에 있다는 가정 하입니다.)

    1. Item 드래그 & 드롭 기능.

     

    2. Item 장착 기능

     

    3. Item 능력치 부여

     

    4. Item 장착 시 (Player Stat += Item 능력치)

     

    우선 아이템에 기능 구현은 이 정도가 끝인 것 같습니다.

     

    이후 상점을 열어 아이템 구매 및 판매할 시

     

    Bag 함수를 열어 Bag에 있는 아이템 부분과 상점의 상호작용 하는 부분에서 추가적으로 올리겠습니다.

     

     

    우선 첫 번째로 Item의 드래그 기능부터 보겠습니다.

     

     

    Bag Item

     

    이 아이템 들은 UI항복의 Image로 만들어 주었습니다.

    Source Image를 변경 되게 해 주어 각 다른 아이템들을 구성했는데요

     

    현재 이렇게 만든 아이템들은 프리팹화를 해 두어

     

    재사용이 용이하게 만들었습니다.

    프리팹


    우선 처음으로 inven을 담당하는 ManagerInven에게 변수들을 선언해 주었습니다.

    selectedItem : 터치 / 클릭될 시 선택 아이템

     

    curParent : 아이템의 부모(Slot)입니다.

    curParent 이해 돕기용

    즉 아이템들이 각 번호에 맞는 Slot의 자식으로 들어와 있는 상태입니다.

     

    parentOnDrag : 드래그 중 일 시 부모 역할을 해 줄 오브젝트입니다.

     

    부모 역할을 해주지 않고 드래그를 하게 된다면, 이미지가 뒤로 가려져 버리게 됩니다.

     

    이렇게 slot(int)의 자식이 아닌

     

    SlotBox의 자식으로 붙어 줘야 이미지가 가려지는 현상이 사라지는 것을 볼 수 있으십니다.

    그렇기에 parentOnDrag : SlotBox오브젝트입니다.


    아이템에 넣어줄 스크립트부터 만들겠습니다.

    유니티의 UI 항목을 사용하기 위해 using UnityEngine.UI 네임 스페이스를 선언해 주었고

    또한 EventSystem을 사용할 것이기에 using UnityEngine.EventSystems 네임스페이스를 선언해 주었습니다.

     

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

     

    img : 아이템이 시각적으로 보일 이미지입니다.

     

    inBag : 아이템이 가방에 있는지 체크할 불 변수입니다.

     

    inStore : 아직은 사용되지 않지만 추 후 상점에 있는지 체크할 불 변수입니다.

     

    releaseTime : OnPointerUp(터치 / 클릭 해제 시)에서 실행이 될 것인데

    OnPointerDown(터치 / 클릭했을 시) releaseTime += Time.deltaTime으로 시간을 누적시켜 주며

     

    OnPointerUp 됐을 시 releaseTime에 누적되던 시간은 멈춥니다.

     

    이 releaseTime의 시간이 0.2f보다 크면 드래그 중이었다고 간주하고

    0.2f보다 작으면 단순 클릭이라고 간주합니다.

     

    drag : 드래그 중인지 체크해줄 불 변수입니다.


    이어서 이벤트 시스템인

     IPointerUpHandler / IPointerDownHandler / IDragHandler

    부터 보겠습니다.

     

    유니티에서 제공하고 있는 이벤트 매뉴얼은 다양합니다.

     

    그중 

    IPointerUpHandler : 버튼 / 클릭 떼는 순간 실행

    IPointerDownHandler : 버튼 / 클릭하는 순간 실행

     

    으로 구현을 하였고

    IDragHandler : 스크립트가 붙은 오브젝트를 드래그 중일 때 계속 호출되는 이벤트까지

     

    총 3개를 사용하였습니다.

     

    알면 알수록 다양한 구현을 할 수 있다는 게 신기하기도 하고

    유니티는 정말 대단한 것 같습니다..

     


    IPointerUpHandler인 버튼 / 클릭 떼는 순간 실행되는 소스코드부터 보겠습니다.

    터치 / 클릭을 줄여서 터치로 통일 짓겠습니다.

     

    터치를 하게 되면 img에 터치한 아이템의 Img컴포넌트를 받아옵니다.

    이 받아온 img는 현재 레이 캐스트를 활성/비활성화를 해줄 예정입니다.

     

    이후 Manager.instance.managerInven.selectedItem = transform로 통해

    현재 선택한 아이템이 무엇인지 알려줄 것입니다.

     

    하나의 싱글톤 패턴만으로 다양하게 손쉬운 접근이 가능하니,

    Manager를 이용한 기법은 음.. 아무리 생각해도 정말 잘 배워두었던 것 같습니다ㅎㅎ

     

    부 Manager들 이외에도 PlayerController를 받아와 player에게 손쉽게 접근도 가능합니다!!

     


    큼큼.. 다시 돌아와 OnPointerDown (터치 시 실행되는 이벤트)에서 실행될 첫 번째 조건문을 보겠습니다.

    if(inbag) == if(inbag == true)로 가방 안에 있을 시 / inbag이 true일 시 실행될 조건문입니다.

     

    StartCoruine로 코 루틴 함수 ReleaseTime을 실행시켜 주는 코드입니다.

     

    코 루틴 함수 ReleaseTime를 보겠습니다.

    ReleaseTime 전체 코드

    드래그 / 터치 인지를 기준을 잡아줄 releaseTime 변수는 0으로 초기화를 해줍니다.

    또한 불 변수 drag의 초기 상태는 false로 해줍니다.

     

    터치 가 시작되면 실행될 IPointerDownHandler 이벤트에서 실행되는 

    코 루틴 함수 ReleaseTime을 잊으시면 안 됩니다.

    네. 사실 저만 안 잊으면 됩니다.. T.T

    (요즘 제가 T.T란 게임을 제작 중인데 Touch Touch에서 따온 T.T입니다)


    Time.deltaTime : 1초를 현재 프레임의 값으로 나눈 값입니다.

     

    releaseTime의 값에 += 연산자로 이 값을 누적해 줍니다.

     

    이 relaseTime은 0.2f초를 기준으로

     

    드래그 / 클릭을 나눌 것입니다.

     

     

    if(releaseTime >= 0.2f) : releaseTime의 값이 0.2f초 이상일 시

     

    드래그 중인 것으로 간주하고 실행될 조건문입니다.

     

    맨 처음으로 스케일 값을 조정하여 시각화를 더해주었습니다.

     

    transform.localScale = new Vector3(1.3f, 1.3f, 1)로 

     

    현재 아이템의 scale 값을 x = 1.3f / y = 1.3f / z = 1로 변경해 커지게 만들었습니다.

     

     

    if!(drag) == if(drag == false)

    로 중복 방지를 해준 뒤

     

     Manager.instance.managerSE.seAudio.PlayOneShot(Manager.instance.managerSE.drag)의 

    Manager접근 -> ManagerSE접근 방식으로

    drg효과음을 재생을 해주었습니다.

     

    releaseTime이 0.2초 이상으로  드래그 중이라고 간주된 상태이니

    drag = true로 드래그 중이라고 체크를 했습니다.

     

    Manager.instance.managerInven.curParent = transform.parent

    ManagerInven의 curParent(현재 부모)는 현재 아이템의 부모라고 알려줍니다.

    (드래그 중일 시 부모가 SlotBox로 변경돼서 이미지가 가려지는 현상을 바꿔줬다가

    드래그가 해제되면 원래 부모인 curParent(Slot)으로 돌아가기 위함입니다.)

     

    transform.SetParent(Manager.instance.managerInven.parentOnDrag)

    현재 부모를 저장해 두었으니, 이제 드래그 중일 시

    SetParent함수를 이용해 부모를 변경해 주는 코드입니다.

     

    //

    이로서 managerInven에 있는 

    selectedItem : 터치(선택) 한 아이템

    curParent : 아이템의 현재 부모

    parentOnDrag : 드래그 시 변경될 부모

    가 모두 사용됐습니다.

    //

     

    이 코 루틴 함수는, OnPointerDown(터치 시)에서 inBag(가방 안에 있는지)의 조건을 성립하면

    StartCorutine를 이용해 실행됩니다.

     


     

    이번엔 OnPointerUp(터치가 떼어졌을 시 실행) 이벤트 에서의 코드를 보겠습니다.

     

    StopCorutine 함수로 코 루틴 함수 "ReleaseTime"을 스톱시킵니다.

     

    코 루틴 함수 ReleaseTime에서 releaseTime이 0.2f 이상일 시 드래그로 간주하여

     

    시각화를 더해주기 위해 transform.localScale = new Vector3(1.3f, 1.3f, 1)로 스케일 값을 키웠었습니다.

     

    이를 원상태로 복귀하기 위하여 transform.localScale = vector3.zero로 만들어 줬습니다.

     

     

    이후 if(releaseTime >= 0.2f) 조건문을 실행하여 한번 더 검사를 합니다.

     

     

    releaseTime이 0.2f초 이상이면 드래그하다가 터치가 떼어진 것

     

    relaseTime이 0.2초 미만 이면 터치를 한 것으로 간주합니다.

     

     

    if(releaseTime >= 0.2f)의 조건문부터 보겠습니다.

     

    드래그 중일 시 이미지가 가려지는 현상을 막기 위해

     

    ManagerInven에 있는 parentOnDrag(SlotBox)로 부모를 지정해 주었었습니다.

     

    SetParent 함수를 이용해 지정해 줬던 curParent(터치되기 전 부모)로 지정을 해줍니다.

     

     

    이후 아이템의 위치를 초기화하기 위해

     

    transform.localPosition = Vector3.zero를 받아왔습니다.

     

    position과 localPosition은 부모가 없다면 같은 기능을 하지만

     

    localPosition은 부모가 있다면 부모를 기준으로 상대 좌표를 반환합니다.

     

    즉 부모가 있는 위치의 현재 위치한 지점이 되는 것입니다.

     

     

    img.raycastTarget = true로 꺼놨단 레이 케스트 타깃은 다시 활성화를 시켜줬습니다.

     

    이로서 다시 이 img를 터치할 수 있게 됩니다.

     


     

    if(releaseTime < 0.2f) 이 코드는 단순 클릭을 한 것으로 간주하는 조건문입니다.

     

    클릭을 하게 되면 아이템 팝업창이 뜨게 되는데, 이 부분은 아이템을 장착하는 부분에서 다시 보겠습니다.

     


    IDragHandler : 오브젝트를 드래그 중일 때 계속 호출되는 이벤트는 현재 단순합니다.

     

    드래그 중으로 간주 시 아이템이  드래그 중인 위치(eventData.position)를 따라가게 해 줍니다.

     

    inbag && dragin으로 아이템이 가방 안에 있고 && 드래그 중일 시에만 실행이 됩니다.

     


     

    마지막!으로 아이템이 드롭됐을 시 실행하는 코드를 보겠습니다.

    이번에는 새로운 이벤트입니다.

     

    이벤트를 사용하기 위해 UnityEngine.EventSystems 네임스페이스를 선언해 주었습니다.

     

    IDropHandler : 오브젝트에 마우스 드롭 이벤트가 발생됐을 때 실행됩니다.

     

     

    이 스크립트들은 각각 Slot에 넣어주었습니다.

    OnPointerUp (터치 종료 시) 발생되는 이벤트에서 releaseTime을 검사하여

     

    0.2f초 이상이면 드래그하던 중 드롭 이 발생되게 했습니다.

     

    각 Bag 안에 있는 Slot에 드롭이 되면 이벤트가 실행됩니다.

     

    Item_Drp 에 있는 IdropHandler

     ManagerInven managerInven = Manager.instance.managerInven 

    우선 처음으로 ManagerInven을 사용할 것이기 때문에

     

    그때그때 호출해서 부르는 것보다, 미세하지만 조금 더 빠른 미리 호출해서 받아놓은 상태로

     

    ManagerInven을 managerInven에 담았습니다.

    현재 hierarchy 창을 보시면, 각 1 Slot 안에 1개의 아이템이 존재합니다.

    그에 해당하는 이미지에 맞게 씬뷰에서 시각화로 나타내어지는데요

     

    if (transform.childCount!= 0) 코드를 보자면

     

    transfrom(slot)의 자식의 카운터가 0이 아니라면? 의 조건문입니다.

     

    즉, 아이템이 Slot 안에 존재하고 있는 상태로 간주되며

     

    그 아이템을 제어하기 위해

     

     Transform item = transform.GetChild(0)로 item에 받아왔습니다.

     

    이후 SetParent함수를 이용해

     

    현재 드래그 중이다 Drop 되는 아이템의 부모가 저장된

     

    curParent로 부모를 저장해 줍니다.

     

    원래 안에 있던 객체의 부모가 바뀌었으니

     

    부모를 상대적으로 포지션 값이 변환되는 localPosition을 사용해 

     

    item.localPosition = Vector3.zero를 만들어 줍니다.

    (위치 초기화)

     

     

    반대로 (transform.childCount!= 0) 이 아니라면

     

    위의 조건문은 실행될 일이 없습니다.

     

    드래그 중 Drop 된 아이템(선택한 아이템) selectedItem의 부모를 SetParent를 이용해 transfrom(Slot)으로 지정해 준 뒤

     

    position 이 아닌 localPosition으로 부모를 상대적으로.

    Vector3.zero(new vector3(0, 0, 0) 위치를 초기화해줍니다.

     

     

     

    00 : 19초

     

    동작 구현되는 영상과 코드들은 짧지만..

     

    생각 이상으로 정말 오래 걸렸습니다.

     

    더군다나 현재 제작된 drag과정 중

     

    첫 drag를 할 시 SlotBox로 정해 주어 이미지가 가려지는 현상을 막고 터치 해제 시 그전에 지정된 부모로 돌아가게끔 만드는 로직이 어느 정도 정리가 되어있지만

     

    이해하는 과정이 왜 이렇게 오래 걸렸나 모르겠지만.. 음..

     

    뭐든 제가 볼 땐 반복학습이 중요한 것 같습니다.

    뭐든 제가 볼 땐 반복학습이 중요한 것 같습니다.

     

    (오타 아닙니다. 중요하니 두번 적었습니다.)

     

     

    댓글

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