-
안녕하세요
오늘은 아이템을 장착하며
아이템에 따른 능력치가 플레이어 스텟에 동기화되는 동작 구현을 보겠습니다.
우선 지난 시간에 아이템들이 드래그 & 드롭 되는 부분을 봤습니다.
그중 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에 관련된 부분을 볼 예정입니다.
긴 글 읽으시느라 수고 많으셨습니다..!
오늘도 감사합니다.
'유니티 프로젝트 > RPG 듀토리얼' 카테고리의 다른 글
RPG 듀토리얼 08. Monster(Enemy) AI & Attack (0) 2022.04.21 RPG 듀토리얼 07. Monster(Enemy) Target_Box (0) 2022.04.20 RPG 듀토리얼 05. ITEM_in the Bag (0) 2022.04.19 RPG 듀토리얼 04. RenderTexture & stat (0) 2022.04.17 RPG 듀토리얼 03. Ray & CamController (0) 2022.04.16