ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • RPG 듀토리얼 06. Item equip
    유니티 프로젝트/RPG 듀토리얼

    안녕하세요

    오늘은 아이템을 장착하며 

     

    아이템에 따른 능력치가 플레이어 스텟에 동기화되는 동작 구현을 보겠습니다.

     

    우선 지난 시간에 아이템들이 드래그 & 드롭 되는 부분을 봤습니다.

     

    그중 IPointerUpHandler : 버튼 / 클릭 떼는 순간 실행되는 이벤트에서

     

    releaseTime을 검사해

     

    0.2f초 이상 이면은 드래그 중 떼 진 것으로 간주

     

    0.2f초 미만 이면은 클릭 상태로 2가지 동작을 if(조건문)으로 나눴습니다.

     

    releaseTime이 0.2f초 아래 일 시 실행되는 조건문입니다.

    (드래그가 아닌 클릭으로 간주합니다)

     

    우선 코드를 보시기 전에 itemInfoFrame부터 보겠습니다.

    아이템의 정보를 시각화해 줄 UI항목입니다.

     

    Text는 모두 TextMeshProUGUI로 작성했으며

     

    이 아이템 정보창에 동기화될

     

    아이템 스크립트 먼저 봐야 할 것 같군요..ㅎㅎ

     

    자꾸 거슬러 올라가는 느낌..

     


    아이템에 입혀질 Item_Info 스크립트입니다.

    선언된 변수들을 보시자면

    type : 아이템 타입

    Item_Name : 아이템 이름

    Item_Info : 아이템 정보

    resell_Price : 되파는 가격

    count : 수량

    price : 아이템 가격

     

    그리고

     

    아이템의 타입이 Equiment(장비) 이면 생성될 스텟들입니다.

     

    기본 소모품에는 이 스텟이 추가되지 않습니다.

     

    hpBonus : 체력

    atkBonus : 공격력

    defBonus : 방어력

    criBonus : 크리티컬

    (소수점이기에 float로 받았습니다)

     

    isEquip : 장착 중인지 체크할 불 변수

     

    sword_Mesh : 무기 오브젝트

    eqipNum : 장비 번호

    (장비 번호에 맞춰 Info창 그 번호에 맞는 slot에 아이템이 장착될 예정입니다.)

     

    //

    장비 번호에 맞게 Info slot에 장착된 모습

    //

    인스펙터 창에서 보는 아이템에 Items_Info 스크립트가 입혀진 모습입니다.


    그럼 이제 이 아이템의 스텟을 동기화해줄 스크립트를 보겠습니다.


    이렇게 아이템 인포 스크립트 / 텍스트 스크립트를 나누어

    아이템의 정보를 동기화하기 위해 사용했습니다.

     

    items : 클릭으로 간주됐을 시 선택된 아이템의 Items_Info(정보)입니다.

    이 클릭된 아이템은

     

    IPointerUpHandler이벤트에서releaseTime이 0.2f 보다 낮을 경우 클릭으로 간주될 시 

    조건문 안의 코드입니다.

    빨간 네모 친 부분

    //

    터치 한 아이템의 Items_Info(정보)를 받아와 줍니다.

     

    StatBonous : 아이템의 타입이 장비(Equiment) 이면 생성할 스텟 부분입니다.

    (타입이 단순 소모품이면 이 StatBonus 부분이 활성화되지 않습니다. )

     

    item_Name / item_Info / resell_Price

    아이템 이름 / 아이템 정보 / 되팔기 가격

    입니다.

    아이템의 기본 정보 정보들을 동기화해줄 TextMeshProUGUI들이죠


    hpBonus / atkBonus / defBonus / criBonus

    체력 / 공격력 / 방어력 / 크리티컬

    장비 아이템에 붙은 스텟을 동기화해줄 TextMeshProUGUI들입니다.


    그럼 이제 정리를 해 보겠습니다.

     

    현재 아이템의 각 스텟과 / 아이템의 스텟에 맞게 동기화를 해줄 TextMeshProUGUI가 완성됐습니다.

     

    크게 2가지로 나누어 글을 이번 글은 마무리 짓겠습니다.

     

    1. 아이템 정보의 팝업창이 동기화되는 과정

    2. 아이템을 장착 시 Player의 info창 스텟의 변화 과정

    을 보겠습니다.

     

    우선 아이템 정보의 팝업창이 동기화 되는 코드 구현부터 보시죠!

     

     

    팝업창

    매 활성화 시 실행되는 OnEnable 함수입니다.

     

    제가 잊지 않으려고 항상 얘기하는 Start 함수와 Awake 함수는 최초로 1회만 실행되는 함수였죠?

     

    우선 statBonus를 SetActive를 이용해 false(비활성화)를 만들어 줍니다.

    이 statBonus는 아이템이 장비 타입일 시에만 활성화되게 해 주기 위함입니다.

     

    이후 각 아이템의 기본정보인

    item_Name의 text = items.Item_Name

    item_Info의 text = items.Item_Info

    로 지정해 주었습니다.

     

    현재 item_Name / item_Info는 동기화를 해줄 ItemInfoFrame스크립트에서 제작되었고

    대입할 items는 Items_Info에서 받아온 녀석으로

    Item_Action에서 OnPointerDown(터치 시) 실행되는 이벤트에서 받아온

    터치 한 아이템입니다.

     

    나머지 되파는 가격 resell_Price도

    resell_Price.text = string.Format($"resell : {items.resell_Price} G");

    strig.Format으로 문자열을 지정해 둔 뒤 text로 넣을 수 있게 하였습니다.

     

    그럼 이어서 OnEnable 함수를 계속 보겠습니다.

     

    현재 터치 한 그 items의 타입이 "Equipment" (장비) 타입이라면

     

    statBonus를 SetActive == true(활성화) 해 줍니다.

     

    각 hpBonus / atBonus / defBonus / 는 int값 criBonus는 float값 이기 때문에

    문자열로 변환해 주어 각 맞는 TextMeshProUGUI의 text에 넣어 주었습니다.


    이후

    조건문을 보자면 if (! Manager.instance.managerInven.storeFrame.activeSelf) 

    (상점이 활성화(열려) 있지 않았을 시)의 조건문입니다.

     

    현재는 아직 상점 구현 부분을 나가진 않았지만

     

    위와 같은 조건문을 걸어준 이유는

     

    상점이 열려있지 않았을 시 = 장착 / 해제 버튼의 활성화

     

    상점이 열려 있을 시 : 구매 / 판매 버튼의 활성화를 해주기 위함입니다!

     

     

    if (! items.isEquip) 아이템의 장착 중이 아닐 시입니다.

     

    items의 isEquip는 

    장비가 장착된 상태인지 체크하는 불 변수로

    item의 정보인 Items_Info 스크립트에 붙어 있습니다.

     

    즉, if (! items.isEquip) 아이템이 장착 중인지 아닐 시에는

    equipBtn.SetActive(true) : 장착 버튼이 활성화

     

    if (items.isEquip) 아이템이 장착 중 일시에는

    releaseBtn.SetActive(true) : 해제 버튼이 활성화 

     

    되는 코드입니다.

     


    그럼 이제 마지막으로

    equipBtn (장착 버튼) / releaseBtn (해제 버튼) 

    이 눌렸을 시 발생하는 코드를 보겠습니다!!

     


    우선 가기 전에..

    하나씩 코드를 작성하면서 모르는 것은 검색도 해보고 영상들을 찾아보며 구현 방법을 익히고 제 스크립트에 적용하면서 테스트할 때도 상당히 보람찼지만 오래 걸렸었는데,

    뭔가의 흐름? 을 익히고 코드를 하나씩 뜯어 보려니까 은근히 이것도 오래 걸리는 것 같습니다.

     

    다시 되짚어 보기도 하고 구현된 코드를 보면서 까먹었던 부분, 문법의 정확한 상세 내용 등

    저로썬 복습이 이뤄지기에 천천히 나아가고자 하는 마음으로 글을 작성하고 있지만,

    처음 보시는 분들은 이 글만 보고 이해가 될 까..?라는 생각을 잠시 가지게 됐습니다.

    빠르진 않더라도 천천히 그리고 꼼꼼하게 빠트리는 부분 없이 나가가도록 노력할 테니 지켜봐 주세요.


    그럼 다시 돌아와 equipBtn (장착 버튼) / releaseBtn (해제 버튼) 이 눌릴 시 발생할 코드를 보겠습니다.

     

    이 코드는 새로 생성한 Equip 스크립트에서 작성하였고

     

    각 실행 함수는 public으로 선언하여

     

    ui항목인 버튼 오브젝트의 OnClick() 함수에서 실행되게 하였습니다.

     

    equipBtn 버튼을 클릭하면

    EquipBtn의 함수가

     

    releaseBtn버튼을 클릭하면

    ReleaseEquipBtn의 함수가 실행되게 하였습니다.

     

    위에 또 다른 Onclick이벤트는 ManagerSE에 있는 Audiosource의 PlayOneShot 이용해 효과음을 재생하는 모습입니다.

    Audiosource의 Play 함수는 소리가 중첩 x (중첩 시 마지막 효과음만 재생됩니다!)

     

     

    그리고 이 Equip 스크립트를 ManagerInven이 관리하게 해 줍니다.


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

     

    PlayerStats : 플레이어의 현재 스텟입니다.

    플레이어의 스텟에 += 장비 스텟을 더 해 주려고 선언하였습니다.

     

    Slot_Equip : Info창의 슬롯 Transform배열입니다.

     

    cur_Equip : 현재 장착된 장비를 알려줄 아이템의 정보를 담을 수 있는 배열 변수입니다.

     


    EquipBtn(장착) 함수부터 보겠습니다

    우선 장착 버튼을 누르면 선택된 아이템의 정보를 가져옵니다.

     

    아이템의 기본 정보인 Items_Info

     

    그리고 그를 제어하기 위한 Items_Info형 item 변수입니다.

     

     

    if(slot_Equip [item.equipNum]. childCount == 2) 

    아이템 이 장착될 슬롯에 이미 다른 아이템이 있다면? 을 조건문으로 걸어줍니다.

     

    slot_Equip : 캐릭터 인포 창의 장비 슬롯들 이었습니다.

    이 슬롯 배열 중 [item.equipNum]

    즉 아이템의 번호인 배열에 ChildCount == 2 라면?

    의 뜻은 아이템이 다른 아이템이 있다는 것으로 간주합니다.

     

    이해를 돕기 위한 캡처 사진을 보겠습니다.

     

    아이템이 장착될 HEAD 슬롯입니다.

     

    이건 인스펙터 창에 있는 Head_Slot입니다.


    첫 번째 카운트는 Head라는 TextMeshProUGUI가 자리매김을 하고 있습니다.

     

    각 슬롯은 각 이름에 맞게 번호가 부여되어있습니다.

    장비도 마찬가지로 각 번호가 부여되어있습니다.

     

    각 장비는 자기 번호와 똑같은 전용 슬롯에만 아이템을 장착할 수 있기에

     

    가져온 아이템을 장착하려면 가져온 아이템의 equipNum을 인덱스로 활용하여

    캐릭터 인포 창의 장비 슬롯 배열인 slot_Equip [index]를 검사하면 됩니다.


    만일 장착된 장비가 Info Slot에 존재한다면

     

    그 슬롯에 있는 아이템은 파괴해야 합니다.

    (Info Slot에서만 파괴될 뿐이지 Bag에는 여전히 남아있습니다.)

    (현재 EquipBtn(장착)) 버튼을 누른 상태입니다.

     

    cur_Equip [item.equipNum]. isEquip = false로

    cur_Equip : 현재 장착된 아이템입니다.

     

    현재 장착된 아이템의 배열 중 [item.eqipNum]의 isEquip(장착 중인지 체크할 불 변수)

    는 false로 장착 중이 아님을 알려줍니다.

     

    또한 장착되면 Bag에서 표시될 EQUIP 오브젝트도 피 활성화시켜줍니다.

     현재 Info slot에 아이템은 파괴되며 없어지고, 장착 중이던 아이템은 

    장착 중을 알리는 텍스트를 비활성화해준 것입니다.

    각 아이템마다 Eqipped 텍스트가 비활성화되어 있어서 숨어 있고.

    장착을 눌렀을 시 그 해당 아이템의 Equipped만 활성화시켜줍니다.

     

    무기 바로 아래에 존재하기에

    GetChild 함수로 (0) 번째 게임 오브젝트를 SetActive를 활용하여 false로 (비활성화)를 해 주었습니다.

     

    이후 슬롯에 있는 아이템을 파괴시켜주는 코드입니다.

    Destroy(slot_Equip [item.equipNum]. GetChild(1). gameObject)

    slot_Equip는 아이템 인포 창에 있는 슬롯들 이었습니다.

    이 슬롯 중 장착 버튼을 눌렀을 시 선택된 아이템의 정보를 가져온 item 변수에서

    equipNum으로 장비 고유 번호를 가져옵니다.

     

    즉 이 장비 고유 번호에 해당하는 슬롯의 GetChild(1). gameObject를 파괴시켜주는 코드입니다.

     

    인포 창에 있는 슬롯에 GetChild를 1번째로 받은 이유는

    (0번째엔 슬롯엔 각자 해당 장비 타입의 텍스트가 0번째 자식으로 들어있기 때문입니다.)

     

    각 슬롯 0번째 에 자식으로 TextMeshProUGUI가 붙어있는 모습입니다.

     

    이 상태에서 아이템이 만약 장착이 된다면

     

    이와 같은 Hierarchy 창을 볼 수 있습니다.

    즉, slot_Head의 GetChild(0) : Head Text / GetChild(1) : 4 Head_RedCap 이 되는 것입니다.

     

    우선 장비를 파괴했으니, 그 착용되던 아이템의 스텟까지 감소시켜주면 끝입니다.

     

    ReducsStats(cur_Equip [item.equipNum])

     

    마찬가지로 cur_Equip(착용했던 아이템의 정보중) item의 equipNum(해당 고유번호)

    영어처럼 풀어쓰자면, item의 해당 고유번호에 맞는 착용했던 아이템의 정보. 가 되는 것입니다.

     

    이 값을 ReducsStats함수에 넣어 주었습니다.

     

    그럼 바로 ReducsStats함수를 보겠습니다.

    현재 playerStats에 item에 존재하는 bonusStat 값을 -= 연산자로 빼주는 코드입니다.

     

    이후 이 InfoFrame을 SetActive = false로 비활성화해주고

    다시 SetActive = true로 활성화를 해주는 코드를 볼 수 있는데요

     

    이는 동기화를 해주기 위함입니다.

     

    따로 Update를 해주거나 갱신을 해주지 않으면, 인스펙터 창에 값이 변화가 되어도

    보이는 Text에 변화가 없습니다.

     

    그리 하여 비활성화 / 재활성화로 동기화를 구현하는 과정입니다.

     

    ----추가-----

    제가 무기를 장착하면 무기 오브젝트가 활성화 되게 구현을 해놨었는데,

    EquipBtn 함수에서

    item의 장비 번호가 0번이라면?

    해당 장비의 sword_Mesh 오브젝트는 Setactive = false로 비활성화해주는 모습입니다.

    //

     

    EquipBtn의 남은 전체 코드입니다.

    이 전의 코드 설명이 if(slot_Equip [item.equipNum]. childCount == 2) 조건 문으로

    장착하려는 슬롯 안에 아이템이 존재한다면? 이였다면

    현재는 그냥 단순 장착을 구현하는 코드입니다.

     

    GameObject item_slot =
            Instantiate(item.gameObject, slot_Equip [item.equipNum])

    우선 장착 버튼을 눌렀으니, 해당 아이템을, 아이템의 번호로 슬롯에 맞게

    Instantiate로 생성해 줍니다.

     

    이(item.gameObject)를 제어하기 위해 GameObject형으로 item_slot을 선언해 주었습니다.

     

    item_slot.GetComponent <Item_Action>(). enabled = false

    슬롯에 생성된 아이템은 플레이어와 상호 작용을 할 필요가 없으므로

    item_slot(item)에 붙어있는 Item_Action 컴포넌트를 enabled = false로 비활성화해줍니다.

     

    cur_Equip [item.equipNum] = item

    이후 현재 장착된 장비의 슬롯 [아이템의 고유번호] = item으로 지정해 줍니다.

    이 item은 Manager.instance.managerInven.selectedItem.GetComponent <Items_Info>()

    로 아이템의 정보가 선택된 아이템의 정보가 담겨 있었습니다.

     

    아이템을 장착을 했으니

    item.isEquip = true : 장착 중인지 체크할 불 변수는 true

     

    item.transform.GetChild(0). gameObject.SetActive(true)

    아이템의 Equipped는 활성화를 시켜주는 모습입니다.

     

    이후 아이템의 Num에 맞게 게임 상에 보이는 무기 오브젝트를

    SetActive로 이용해 활성화/비활성화해주는 모습입니다.

    이 무기 오브젝트는 캐릭터의 손에 위치를 맞춰서 고정시켜 논 다음

    비활성화를 해 두었습니다.

    즉, 무기 아이템을 장착하면 그에 맞는 오브젝트가 활성화되는 구현입니다.

    해당 장비의 스텟을 중가 시켜주는 IncreaseStats 함수입니다.

     


    자. 그럼 정말 마지막인

    ReleaseEquipBtn 함수 구현을 보겠습니다.

    ReleaseEquipBtn 함수는 해제 버튼의 기능의 함수입니다.

     

    Items_Info item = Manager.instance.managerInven.selectedItem.GetComponent <Items_Info>()

     

    Equip와

     

    이후 item의 번호에 맞게 SetActive를 활용해 비활성화시켜주는 모습입니다.


    해제 버튼을 눌렀으니

    인포 창에 있는 아이템은 파괴가 되어야 합니다.

    Destroy(slot_Equip [item.equipNum]. GetChild(1). gameObject)

    로 해당 슬롯 배열중 아이템의 번호에 맞는 슬롯의 GetChild(1)을 파괴하는 코드입니다.

    (0번은 아이템 장착 부위를 알려주는 Text였습니다.)

     

    item.isEquip = false : 장착 여부를 체크하는 불 변수 isEquip는 false로 바꿔주고

     

    item.transform.GetChild(0). gameObject.SetActive(false) : 장착 중인지 알려주는 Text도 비활성화해줍니다.

    장착 중인지 알려주는 text

    장비를 해제했으니

     

    ReducsStats(cur_Equip [item.equipNum]) : 해당 아이템을 넣어 주어 

    스텟을 감소시키는 구현을 하는 ReducsStats를 실행시켜줍니다.

     

    장비를 해제했으니 장착된 장비는 없어야 하기에

    cur_Equip [item.equipNum] = null로 null로 지정해 주었습니다.

     

    Manager.instance.managerInven.itemInfoFrame.SetActive(false)
    Manager.instance.managerInven.itemInfoFrame.SetActive(true)

     

    인포 창 동기화를 위해 SetActive로 비활성화/활성화해주는 코드입니다!!

     

    00 : 36초

    Item 동작 구현을 설명하다 보니  글이 길어졌습니다.

     

    캡처 사진을 많이 넣어서 그런 것 같기도 하고

     

    가독성을 위해 나눴어야 하나 싶기도 하고..

     

    스크립트를 어떻게 세분화를 잘해야 하는지 랑 비슷한 것 같습니다.

     

    크게 어려울 부분은 없는데 말이죠 ㅎㅎ

     

     

    감은 크게는 안 잡히지만 조금씩 나아지고 있다는 느낌은 받고 있습니다.

     

    다음 글에선 Monster에 관련된 부분을 볼 예정입니다.

     

     

    긴 글 읽으시느라 수고 많으셨습니다..!

     

    오늘도 감사합니다.

     

     

     

     

    댓글

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