Chapter 5-5. 인벤토리 : 아이템 회복
카테고리: Unity Lesson 3
태그: Unity Game Engine
인프런에 있는 케이디님의 [유니티 3D] 실전! 생존게임 만들기 - Advanced 강의를 듣고 정리한 필기입니다. 😀
🌜 강의 들으러 가기 Click
Chapter 5. 인벤토리
🚖 포션 아이템 만들기
이름은
Potion Yellow Item
- “Item” 태그, 레이어
- Box Collider
- Rigidbody
- 📜ItemPickUp
Potion Yellow
item 만들어서 할당- 아이템 타입은 Used
🚖 포션 먹으면 회복하게 하기
인벤토리에서 해당 포션에 우클릭하면 소모되도록 한다.
📜ItemEffectDatabase.cs
빈 오브젝트
Database
를 만들고 📜ItemEffectDatabase.cs 을 붙여 주었다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class ItemEffect
{
public string itemName; // 아이템의 이름(Key값으로 사용할 것)
[Tooltip("HP, SP, DP, HUNGRY, THIRSTY, SATISFY 만 가능합니다.")]
public string[] part; // 효과. 어느 부분을 회복하거나 혹은 깎을 포션인지. 포션 하나당 미치는 효과가 여러개일 수 있어 배열.
public int[] num; // 수치. 포션 하나당 미치는 효과가 여러개일 수 있어 배열. 그에 따른 수치.
}
public class ItemEffectDatabase : MonoBehaviour
{
[SerializeField]
private ItemEffect[] itemEffects;
private const string HP = "HP", SP = "SP", DP = "DP", HUNGRY = "HUNGRY", THIRSTY = "THIRSTY", SATISFY = "SATISFY";
[SerializeField]
private StatusController thePlayerStatus;
[SerializeField]
private WeaponManager theWeaponManager;
public void UseItem(Item _item)
{
if (_item.itemType == Item.ItemType.Equipment)
{
// 장착
StartCoroutine(theWeaponManager.ChangeWeaponCoroutine(_item.weaponType, _item.itemName));
}
if (_item.itemType == Item.ItemType.Used)
{
for (int i = 0; i < itemEffects.Length; i++)
{
if (itemEffects[i].itemName == _item.itemName)
{
for (int j = 0; j < itemEffects[i].part.Length; j++)
{
switch(itemEffects[i].part[j])
{
case HP:
thePlayerStatus.IncreaseHP(itemEffects[i].num[j]);
break;
case SP:
thePlayerStatus.IncreaseStamina(itemEffects[i].num[j]);
break;
case DP:
thePlayerStatus.IncreaseDP(itemEffects[i].num[j]);
break;
case THIRSTY:
thePlayerStatus.IncreaseThirsty(itemEffects[i].num[j]);
break;
case HUNGRY:
thePlayerStatus.IncreaseHungry(itemEffects[i].num[j]);
break;
case SATISFY:
break;
default:
Debug.Log("잘못된 Status 부위. HP, SP, DP, HUNGRY, THIRSTY, SATISFY 만 가능합니다.");
break;
}
Debug.Log(_item.itemName + " 을 사용했습니다.");
}
return;
}
}
Debug.Log("itemEffectDatabase에 일치하는 itemName이 없습니다.");
}
}
}
- ItemEffect 클래스 👉 한 아이템의 효과.
[System.Serializable]
로 선언되어서 이 클래스의 멤버들은 MonoBehaviour 을 상속 받는 클래스가 아닌 일반 C# 클래스임에도 불구하고 유니티 인스펙터에 띄워 여기서 값을 할당할 수 있게 되었다.part
와num
의 인덱스는 대응되게 할 것이다. part[2]가 HUNGRY 라면 num[2] 의 원소 값은 HUNGRY 에 대한 수치itemName
에 해당하는 하나의 아이템은part
배열에 속한 부분들에 대한 효과를 가진다. 그에 대응하는 효과 수치는num
배열에 해당.
itemEffects
- private 으로 선언되었기 때문에 ItemEffect 클래스가
[System.Serializable]
긴 하더라도SerializeField
해주어야 비로소 유니티 인스펙터에 뜨게 된다. - 배열이다. 📜ItemEffectDatabase.cs 에서 여러 포션 아이템들을 이 `itemEffects` 배열 멤버에서 한번에 관리 하게 됨.
- private 으로 선언되었기 때문에 ItemEffect 클래스가
- UseItem(Item _item) 아이템 소모시 👉 📜Slot.cs의 우클릭 이벤트에서 처리 했었는데 성능을 위해 이 스크립트로 옮겼다.
- 아이템이 장비면 장착하고
- 때문에 📜WeaponManager.cs 가 필요 하다.
- 다만
Slot
과 다르게Database
는 프리팹은 아니기 때문에 FindObejctOfType을 사용하지 않고 직접 할당해주기로 하였다.[SerializeField]
.
- 다만
- 때문에 📜WeaponManager.cs 가 필요 하다.
- 아이템이 소모품이면 👈 포션이 해당 됨
- 해당 수치에 맞게 효과 적용
- 인수로 들어온 아이템의 이름이
itemEffects
배열에 있는지를 찾고 - 찾았다면 해당 아이템의 효과들을 📜StatusController.cs 의 함수들을 호출하여 적용한다.
- IncreaseHP 등등
- 모든 효과를 적용했다면 바로 종료.
itemEffects
배열에 있는지를 더 찾을 필요가 없으므로.
- 인수로 들어온 아이템의 이름이
- 해당 수치에 맞게 효과 적용
- 아이템이 장비면 장착하고
- Potion Yellow 아이템을 소비 하면
- SP 가 500 으로 증가하고
- HUNGRY 가 100 으로 증가하고
- THIRSTY 가 100 으로 증가하게끔 하였다.
📜Slot.cs
private ItemEffectDatabase theItemEffectDatabase;
void Start()
{
baseRect = transform.parent.parent.GetComponent<RectTransform>().rect;
theInputNumber = FindObjectOfType<InputNumber>();
theItemEffectDatabase = FindObjectOfType<ItemEffectDatabase>();
}
// 마우스 클릭 이벤트
public void OnPointerClick(PointerEventData eventData)
{
if(eventData.button == PointerEventData.InputButton.Right)
{
if (item != null)
{
theItemEffectDatabase.UseItem(item);
if(item.itemType == Item.ItemType.Used)
SetSlotCount(-1);
}
}
}
Slot
은 프리팹이기 때문에 다른 오브젝트를 FindObjectOfType 로 불러올 수 밖에 없다. 또한 20개나 되기 때문에 인벤토리가 활성화 되어 슬롯도 활성화 될 때, Start() 에서 너무 많은 컴포넌트를 로딩한다면 성능에 문제가 생길 것이다.- 따라서 📜Slot.cs 의 📜WeaponManager.cs 를 불러오는 부분을 지웠다. 아래 코드를 지우고 위와 같이 고침. 대신 이와 같은 과정은 📜ItemEffectDatabase 에서 하도록 옮겼다.
- 수정 전 📜Slot.cs
public void OnPointerClick(PointerEventData eventData) { if(eventData.button == PointerEventData.InputButton.Right) { if (item != null) { if(item.itemType == Item.ItemType.Equipment) // 👈👈👈👈👈👈👈 { // 장착 StartCoroutine(theWeaponManager.ChangeWeaponCoroutine(item.weaponType, item.itemName)); } else // 👈👈👈👈👈👈👈 { // 소비 Debug.Log(item.itemName + " 을 사용했습니다."); SetSlotCount(-1); } } } }
- 📜ItemEffectDatabase.cs
public void UseItem(Item _item) { if (_item.itemType == Item.ItemType.Equipment) // 👈👈👈👈👈👈👈 { // 장착 StartCoroutine(theWeaponManager.ChangeWeaponCoroutine(_item.weaponType, _item.itemName)); } if (_item.itemType == Item.ItemType.Used) // 👈👈👈👈👈👈👈 { // 소비 for (int i = 0; i < itemEffects.Length; i++) { if (itemEffects[i].itemName == _item.itemName) { for (int j = 0; j < itemEffects[i].part.Length; j++) { switch(itemEffects[i].part[j]) { case HP: thePlayerStatus.IncreaseHP(itemEffects[i].num[j]); break; case SP: thePlayerStatus.IncreaseStamina(itemEffects[i].num[j]); break; case DP: thePlayerStatus.IncreaseDP(itemEffects[i].num[j]); break; case THIRSTY: thePlayerStatus.IncreaseThirsty(itemEffects[i].num[j]); break; case HUNGRY: thePlayerStatus.IncreaseHungry(itemEffects[i].num[j]); break; case SATISFY: break; default: Debug.Log("잘못된 Status 부위. HP, SP, DP, HUNGRY, THIRSTY, SATISFY 만 가능합니다."); break; } Debug.Log(_item.itemName + " 을 사용했습니다."); } return; } } Debug.Log("itemEffectDatabase에 일치하는 itemName이 없습니다."); } }
- 수정 후 📜Slot.cs
- 무기든 소모품이든, 아이템 사용에 대한 처리를 📜ItemEffectDatabase.cs 의 UseItem 함수에게 전적으로 맡기게 되었다.
- 대신 해당 아이템이 소모품일 땐 아이템 갯수를 1 감소시키는 처리를 해주었다.
if(eventData.button == PointerEventData.InputButton.Right) { if (item != null) { theItemEffectDatabase.UseItem(item); if(item.itemType == Item.ItemType.Used) SetSlotCount(-1); } }
- 대신 해당 아이템이 소모품일 땐 아이템 갯수를 1 감소시키는 처리를 해주었다.
- 무기든 소모품이든, 아이템 사용에 대한 처리를 📜ItemEffectDatabase.cs 의 UseItem 함수에게 전적으로 맡기게 되었다.
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글 남기기