✅ 기능
지금까지 아이템을 데이터화하고, 씬 내에 배치하고, 런타임 도중 아이템을 바라보고 획득하는 기능을 구현하였습니다. 대부분의 기능을 구현하였으니 이번 글에서는 획득한 아이템들을 사용하고, 사용 시 해당 아이템의 효과를 적용하여 물약을 사용하면 플레이어의 체력과 마나를 회복하는 기능을 구현하고 정리해 보았습니다. 이번 글이 기본적인 인벤토리 시스템의 마지막입니다.
🔨 로드맵
2. 유니티 인벤토리 시스템(2) - 아이템(ScriptableObject)
3. 유니티 인벤토리 시스템(3) - 아이템 슬롯(인벤토리 슬롯)
5. 유니티 인벤토리 시스템(5) - 아이템 슬롯 관리
[📌현재 글] 6. 유니티 인벤토리 시스템(6) - 아이템 사용
✅ 구현
1. InventorySlot
...
public class InventorySlot : MonoBehaviour, IPointerClickHandler, IBeginDragHandler, IDragHandler, IEndDragHandler, IDropHandler, IPointerEnterHandler, IPointerExitHandler
{
...
/// <summary>
/// 마우스 클릭 오버라이드나 외부에서 해당 슬롯을 대상으로 직접 사용하도록 호출
/// </summary>
public void UseItem()
{
if (mItem != null) //해당 슬롯의 아이템이 null이라면 return
{
//상호작용이 불가능한 (사용이 불가능한) 아이템이라면 리턴
if (!mItem.IsInteractivity) { return; }
//쿨타임이 0보다 큰경우 (현재 쿨타임이 돌고있는경우)라면 리턴한다.
if (ItemCooltimeManager.Instance.GetCurrentCooltime(mItem.ItemID) > 0) { return; }
//아이템 사용 함수 호출
//만약 아이템 함수 호출인 상태에서 false가 리턴되면, 현재 사용 불가능 상태이기에 리턴한다.
if (!mItemActionManager.UseItem(mItem)) { return; }
//아이템의 쿨타임이 설정되어있으면 쿨타임 적용
if(mItem.Cooltime > 0f) { ItemCooltimeManager.Instance.AddCooltimeQueue(mItem.ItemID, mItem.Cooltime);}
//상호작용이 가능한(착용 가능한) 장비 아이템을 사용한경우?
if (mItem.Type >= ItemType.Equipment_HELMET && mItem.Type <= ItemType.Equipment_SHOES) { ChangeEquipmentSlot(); }
//아이템이 소모성이면 한개씩 개수를 줄임
if(mItem != null && mItem.IsConsumable) { UpdateSlotCount(-1); }
//아이템을 다쓴경우, UpdateSlotCount로 인해 mItem이 null이 되는 경우에 UI를 끈다.
if(mItem == null) { mItemDescription.CloseUI(); }
}
}
...
//마우스 클릭 오버라이드
public void OnPointerClick(PointerEventData eventData)
{
if (eventData.button == PointerEventData.InputButton.Right) //버튼 우클릭시
{
if(mSlotMask == ItemType.SKILL) { return; }
UseItem();
}
}
...
}
- InventorySlot에 마우스 이벤트 오버라이드를 추가합니다 (OnPointerClick)
- UseItem() 함수를 추가하여 마우스 이벤트가 발생한 경우 호출하여 아이템을 사용할 수 있도록 합니다.
public void OnPointerClick(PointerEventData eventData)
- UseItem() 보다 선행되는 함수로 InventorySlot이 붙어있는 컴포넌트 UI에서 마우스 클릭이 발생하였다면 호출되는 함수입니다.
- 우클릭 시 UseItem()을 호출하여 아이템을 사용하도록 하였습니다.
public void UseItem()
- 아이템을 사용하고, 사용하기 전 여러 경우의 수를 확인하여 사용할 수 있는지 확인합니다.
- 여러 기능이 많이 담겨있어 조건이 많지만, 여기서 중요한 것은 IsInteractivity(상호작용이 가능한가?)입니다.
- 다른 조건에 대한 내용은 이 글에서 다루지 않겠습니다. (쿨타임 기능은 [여기]에서 확인하세요!)
public void UseItem()
{
...
if(mItem != null && mItem.IsConsumable) { UpdateSlotCount(-1); }
...
}
- 아이템을 정상적으로 사용했을 때 IsConsumable이 True로 설정되어 있다면, 슬롯의 카운트(개수)를 1개 줄입니다.
2. ItemActionManager
using UnityEngine;
/// <summary>
/// 씬 내의 매니저 오브젝트에 할당
/// 아이템(또는 정적 물체)과 상호작용하거나, 인벤토리에서 아이템을 사용하면 특수 이벤트를 발생시킴
/// </summary>
public class ItemActionManager : MonoBehaviour
{
/// <summary>
/// 메시지를 주고받는경우 스킬에 대한 메시지 약속
/// </summary>
public static string _SkillMessage = "ActiveSkill";
[SerializeField] private PlayerController mPlayerController;
[Header("Preloaded objects into the scene")]
[SerializeField] private GameObject[] mObjects;
/// <summary>
/// 아이템 사용 이벤트 호출
/// 각 아이템마다 실행되는 기능을 수행
/// </summary>
/// <param name="item"></param>
/// <returns>실행이 정상적으로 이루어 졌는가?</returns>
public bool UseItem(Item item)
{
Debug.Log("UseItemEvent");
switch (item.Type)
{
//스킬을 사용한경우라면?
case ItemType.SKILL:
{
...
}
case ItemType.Consumable:
{
switch(item.ItemID)
{
case (int)ItemCode.SMALL_HEALTH_POTION:
{
GameManager.Instance.Player.ModifyHP(50);
SoundManager.Instance.PlaySound2D("Food Drink " + SoundManager.Range(1, 4, true));
break;
}
case (int)ItemCode.SMALL_MANA_POTION:
{
GameManager.Instance.Player.ModifyMana(50);
SoundManager.Instance.PlaySound2D("Food Drink " + SoundManager.Range(1, 4, true));
break;
}
}
break;
}
}
return true;
}
/// <summary>
/// 씬 내에서 아이템을 줍거나, NONE타입(줍지 않고, 상호작용 전용) 아이템과 상호작용한경우 실행되는 함수
/// </summary>
/// <param name="itemID">해당 아이템의 코드</param>
/// <param name="interactTarget"></param>
public void InteractionItem(Item item, GameObject interactTarget)
{
Debug.Log("InteractionItemEvent");
if(interactTarget.tag == "NPC")
{
//NPC FSM 가져오기
NPCBase targetNPC = interactTarget.GetComponent<NPCBase>();
//현재 상호작용이 불가능한 대상이라면 리턴
if(!targetNPC.CanInteraction || targetNPC.IsQuotePlaying) { return; }
//상호작용 메시지 보냄
MessageDispatcher.Instance.DispatchMessage(0, "", targetNPC.EntityName, "Interaction");
return;
}
}
/// <summary>
/// 아이템을 슬롯에 드롭하는경우 발생하는 이벤트이다.
/// </summary>
/// <param name="slot">드롭된 슬롯</param>
public void SlotOnDropEvent(InventorySlot slot)
{
Debug.Log("SlotOnDropEvent");
}
}
public enum ItemCode
{
SMALL_HEALTH_POTION,
SMALL_MANA_POTION,
}
- 아이템에 대한 상호작용이 이루어진 경우, 호출되는 함수로 현재 세 가지 이벤트(사용, 드롭, 줍기)를 구현하였습니다.
[SerializeField] private GameObject[] mObjects;
- 아이템을 사용하거나, 상호작용 하는 등 여러 이벤트에 대해 특정한 오브젝트에 대해 접근을 해야 하는 경우 인스펙터에서 해당 오브젝트를 지정하여 접근할 수 있도록 하였습니다.
- 예를 들어 아이템을 사용하여 문을 열어야 하는 경우 mObjects에 문 오브젝트를 미리 등록시켜 해당 오브젝트에 접근할 수 있습니다.
public bool UseItem(Item item)
- 인벤토리에 있는 아이템을 사용하여 해당 아이템의 효과를 받는 함수입니다.
- case ItemType.Consumable:에서 현재 아이템이 Consumable이라면, 사용을 위한 아이템이기에 Switch로 묶어 ItemCode를 비교합니다.
- ItemCode가 0, 1(Enum)을 확인하여 아이템코드가 맞다면 해당 아이템의 효과를 적용시킵니다.
public void InteractionItem(Item item, GameObject interactTarget)
- InteractionItem은 씬 내에 배치되어있는 아이템(또는 NPC, 건물 등) 속성을 가지는 모든 오브젝트에 대해 줍기 활동을 하면 발생하는 이벤트입니다.
- NPC와 같이 일부 오브젝트는 주울 수 없이 InteractionItem 함수만 호출될 수 있습니다.
- 지금까지 다루지 않았지만 MessageDispatcher.Instance.DispatchMessage(0, "", targetNPC.EntityName, "Interaction");을 통해 메시지를 보내 대상 클래스에서 이벤트를 처리하는 기능을 FSM으로 구현하였습니다.
public void SlotOnDropEvent(InventorySlot slot)
- 인벤토리 슬롯에서 아이템이 드롭(위치를 이동)하면 호출되는 함수입니다.
✅ 사용(적용) 예시
- 씬 내에 매니저 역할을 하기 위해 ItemActionManager을 사용합니다.
- 위치는 상관없지만, 런타임 도중 비활성화되거나 파괴되지 않아야 합니다.
- 런타임 도중 인벤토리에서 아이템을 우클릭하여 사용합니다.
'unity game modules' 카테고리의 다른 글
[유니티] VideoPlayer URL 재생 및 관리 (0) | 2023.01.02 |
---|---|
[유니티] 인벤토리 시스템(번외) - 쿨타임 기능 (0) | 2022.12.28 |
[유니티] 인벤토리 시스템(5) - 아이템 슬롯 관리 (0) | 2022.12.26 |
[유니티] 인벤토리 시스템(4) - 아이템 획득 (0) | 2022.12.26 |
[유니티] 인벤토리 시스템(3) - 아이템 슬롯(인벤토리 슬롯) (0) | 2022.12.26 |