ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 유니티 인벤토리 - 인벤토리 시스템
    Unity 2024. 1. 23. 19:55
    반응형

    안녕하세요

    오늘은 유니티 인벤토리 시스템을 만들어 봤습니다.

     

    ※ 현재는 클린코드를 지향하고 있지만 인벤토리 시스템을 제작할 당시에는

    클린코드 존재를 잘 몰랐던 시기라 보시는데 불편함이 있을 수 있습니다.


    [인벤토리 프리팹]

     

    • 인벤토리 프리팹을 만들어 줍니다.
    • Inventory 객체에 Inventory.cs를 넣어줍니다.
    • ToolTip 객체에 InventorySlotToolTip.cs를 넣어줍니다.
    • DragSlot 객체에 DragSlot.cs를 넣어줍니다.

    [Inventory.cs]

    #region 변수
    [Header("=====> 인벤토리 설정 <=====")]
    [SerializeField] private GameObject InventoryObject;
    [SerializeField] private GameObject InventoryContent;
    [SerializeField] private InventorySlotToolTip ToolTip;
    [SerializeField] private GameObject SlotPrefab;
    [SerializeField] private Transform ContentArea;
    [SerializeField] private int SlotCount = 25;
    
    public List<ItemData> InventoryItemList = new List<ItemData>();
    public InventorySlot[] SlotArray;
    #endregion // 변수
    
    #region 함수
    /** 초기화 */
    private void Awake()
    {
        InventorySlotCreate();
        SlotArray = GetComponentsInChildren<InventorySlot>();
    
        for(int i = 0; i < SlotArray.Length; i++)
        {
            SlotArray[i].ToolTip = ToolTip;
            SlotArray[i].Inven = this;
        }
    }
    
    /** 인벤토리 활성화 */
    public void OpenInventory() => InventoryObject.SetActive(true);
    
    /** 인벤토리 비활성화 */
    public void CloseInventory() => InventoryObject.SetActive(false);
    
    /** 슬롯 생성 */
    public void InventorySlotCreate()
    {
        for(int i = 0; i < SlotCount; i++)
        {
        	// 슬롯 생성
            var Slot = Instantiate(SlotPrefab, ContentArea);
        }
    }
    
    /** 아이템을 습득한다 */
    public void AcquireItem(ItemData Item, int Count = 1)
    {
        for (int i = 0; i < SlotArray.Length; i++)
        {
            // 해당 슬롯에 아이템이 있을 경우
            if (SlotArray[i].PlusItem != null)
            {
                // 해당 슬롯의 아이템 이름을 가져와 습득한 아이템이름과 같은지 확인
                if (SlotArray[i].PlusItem.ItemName == Item.ItemName)
                {
                    // 개수 증가
                    SlotArray[i].SetSlotCount(Count);
                    return;
                }
            }
        }
    
        for (int i = 0; i < SlotArray.Length; i++)
        {
            // 해당 슬롯에 아이템이 없을 경우
            if (SlotArray[i].PlusItem == null)
            {
                // 아이템 추가
                SlotArray[i].AddItem(Item, Count);
                return;
            }
        }
    }
    #endregion // 함수
    •  AcquireItem() 호출은 플레이어가 아이템을 주웠을 경우에 호출 해주면 된다.
    • 주석으로 코드의 역할을 표시해 이해하기 편하게 했습니다.

    [인벤토리 슬롯 프리팹]

    • InventorySlot 객체에 InventorySlot.cs를 넣어줍니다.
    • ItemSlotCount_Img 객체는 아이템이 존재 할 경우에만 활성화 합니다.

    [InventorySlot.cs]

    #region 변수
    [SerializeField] private Image ItemImg; // 아이템 이미지
    [SerializeField] private GameObject ItemCountImg;
    [SerializeField] private TMP_Text ItemCountText;
    
    public ItemData PlusItem; // 획득한 아이템
    public int ItemCount;  // 획득한 아이템 수
    #endregion // 변수
    
    #region 프로퍼티
    public InventorySlotToolTip ToolTip { get; set; }
    public Inventory Inven { get; set; }
    #endregion // 프로퍼티
    
    #region 함수
    /** 아이템 이미지 투명도 조절 */
    private void SetColor(float Alpha)
    {
        Color color = ItemImg.color;
        color.a = Alpha;
        ItemImg.color = color;
    }
    
    /** 아이템 추가 */
    public void AddItem(ItemData Item, int Count = 1)
    {
        this.PlusItem = Item;
    
        Inven.InventoryItemList.Add(PlusItem);
    
        ItemCount = Count;
        ItemImg.sprite = Item.ItemImg;
    
        // 아이템 타입에 따라 관리 if
        ItemCountImg.SetActive(true);
        ItemCountText.text = ItemCount.ToString();
    
        // 투명도
        SetColor(1);
    }
    
    /** 아이템 개수 조정 */
    public void SetSlotCount(int Count)
    {
        // 개수 조정, 표시
        ItemCount += Count;
        ItemCountText.text = ItemCount.ToString();
    
        // 아이템이 없을경우
        if(ItemCount <= 0)
        {
            // 슬롯 초기화
            ClearSlot();
        }
    }
    
    /** 슬롯을 교환한다 */
    private void ChangeSlot()
    {
        // 데이터 덮어쓰기전 저장
        ItemData ItemTemp = PlusItem;
        int ItemCountTemp = ItemCount;
    
        // 아이템 추가
        AddItem(DragSlot.Instance.InventoryDragSlot.PlusItem, DragSlot.Instance.InventoryDragSlot.ItemCount);
    
        // 슬롯 교환
        if (ItemTemp != null)
        {
            DragSlot.Instance.InventoryDragSlot.AddItem(ItemTemp, ItemCountTemp);
        }
        else
        {
            DragSlot.Instance.InventoryDragSlot.ClearSlot();
        }
    }
    
    /** 슬롯 초기화 */
    private void ClearSlot()
    {
        // 초기화
        PlusItem = null;
        ItemCount = 0;
        ItemImg.sprite = null;
    
        // 투명도
        SetColor(0);
    
        // 개수 표시 X
        ItemCountText.text = string.Empty;
        ItemCountImg.SetActive(false);
    }
    
    /** 클릭했을때 */
    public void OnPointerClick(PointerEventData eventData)
    {
        // 오른쪽 클릭했을경우
        if(eventData.button == PointerEventData.InputButton.Right)
        {
            // 아이템이 있을경우
            if(PlusItem != null)
            {
                // 아이템 타입에 따라 장착 , 사용 여부 if
                PlusItem.Use();
                Inven.InventoryItemList.Remove(PlusItem);
                ToolTip.HideToolTip();
    
                // 무기 이미지, 탄약 상태창 갱신
                UIManager.Instance.PlayerStatusTextUpdate();
                UIManager.Instance.PlayerWeaponImgUpdate();
                UIManager.Instance.PlayerAmmoTextUpdate();
                Debug.Log(PlusItem.ItemName + "를 사용했습니다");
    
                // 개수 조정
                SetSlotCount(-1);
            }
        }
    }
    
    /** 드래그를 시작했을때 */
    public void OnBeginDrag(PointerEventData eventData)
    {
        // 아이템이 있을경우
        if (PlusItem != null)
        {
            // 드래그중인 아이템 세팅
            DragSlot.Instance.InventoryDragSlot = this;
            DragSlot.Instance.DragSetImg(ItemImg);
    
            DragSlot.Instance.transform.position = eventData.position;
        }
    }
    
    /** 드래그 중일때 */
    public void OnDrag(PointerEventData eventData)
    {
        // 아이템이 있을경우
        if (PlusItem != null)
        {
            DragSlot.Instance.transform.position = eventData.position;
        }
    }
    
    /** 드래그가 끝났을때 */
    public void OnEndDrag(PointerEventData eventData)
    {
        Debug.Log("EndDrag");
    
        // 투명도, 비우기
        DragSlot.Instance.SetColor(0);
        DragSlot.Instance.InventoryDragSlot = null;
    }
    
    /** 드랍했을때 */
    public void OnDrop(PointerEventData eventData)
    {
        Debug.Log("Drop");
    
        // 드래그중인 아이템이 있을경우
        if (DragSlot.Instance.InventoryDragSlot != null)
        {
            // 아이템 교환
            ChangeSlot();
        }
    }
    
    /** 슬롯에 마우스를 올렸을 경우 */
    public void OnPointerEnter(PointerEventData eventData)
    {
        if(PlusItem != null)
        {
            // 툴팁 보여주기
            ToolTip.ShowToolTip(PlusItem);
        }
    }
    
    /** 슬롯에있는 마우스가 나갔을 경우 */
    public void OnPointerExit(PointerEventData eventData)
    {
        if (PlusItem != null)
        {
            ToolTip.HideToolTip();
        }
    }
    #endregion // 함수
    • IPointerClickHandler, IBeginDragHandler, IDragHandler, IEndDragHandler, IDropHandler, IPointerEnterHandler, IPointerExitHandler 인터페이스를 사용했습니다.

    [DragSlot.cs]

     #region 변수
     [SerializeField] private Image ItemImg;
    
     public InventorySlot InventoryDragSlot;
    
     public static DragSlot Instance;
     #endregion // 변수
    
     #region 함수
     /** 초기화 */
     private void Awake()
     {
         Instance = this;
     }
    
     /** 드래그중인 아이템 이미지 세팅 */
     public void DragSetImg(Image ItemImg)
     {
         this.ItemImg.sprite = ItemImg.sprite;
         SetColor(1);
     }
    
     /** 아이템 이미지 투명도 조절 */
     public void SetColor(float Alpha)
     {
         Color color = ItemImg.color;
         color.a = Alpha;
    
         ItemImg.color = color;
     }
     #endregion // 함수

     

    [InventorySlotToolTip.cs]

    #region 변수
    [SerializeField] private GameObject ToolTip;
    [SerializeField] private TMP_Text ItemNameText;
    [SerializeField] private TMP_Text ItemDescText;
    [SerializeField] private TMP_Text ItemDescUseText;
    #endregion // 변수
    
    #region 함수
    /** 툴팁을 보여준다 */
    public void ShowToolTip(ItemData Item)
    {
        ToolTip.SetActive(true);
    
        ItemNameText.text = Item.ItemName;
        ItemDescText.text = Item.ItemDesc;
        ItemDescUseText.text = Item.ItemDescUse;
    }
    
    /** 툴팁을 숨긴다 */
    public void HideToolTip()
    {
        ToolTip.SetActive(false);
    }
    #endregion // 함수

     

    [구현 완료]

     

    • 인벤토리 시스템 구현하는 방법은 다양하게 존재합니다.
    • 유니티에서 제공하는 인터페이스를 사용해 쉽게 구현했습니다.
    • 유튜브에 구현하는 방법이 많이 존재하니 자신만의 코드로 응용하여 구현해 보는것을 추천합니다!
    반응형
Designed by Tistory.