상세 컨텐츠

본문 제목

유니티 인벤토리 만들기 - 3D게임

유니티/기능

by MJ_119 2025. 1. 6. 18:18

본문

1. 아이템 데이터 ( 스크립터블 오브젝트 )를 만들고 SO(스크립터블 오브젝트)를 만든다.

 - 아이템 데이터를 만들고 이름, 아이콘, 설명을 넣어준다.

using UnityEngine;

[CreateAssetMenu(fileName = "NewItem", menuName = "Item/ItemData")]
public class ItemData : ScriptableObject
{
    [Header("기본 정보")]
    public string itemName; // 아이템 이름
    public Sprite itemIcon;// 아이템 아이콘
    public string itemDescription;// 아이템 설명
}

 

 

 

2. 아이템오브젝트 

 - 아이템 오브젝트 스크립트를 만들고, 아이템 오브젝트에 이 스크립트를 넣고, 위에서 만든 아이템 데이터 스크립터블 오브젝트를 넣어주고, 콜라이더를 추가해준뒤 콜라이더 크기를 조절하고, 캐릭터의 태그를 Player로 바꾸고 실행시켜서 로그를 확인해본다.

 

 - OnValidate()는 없어도 전혀 지장 없다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ItemObject : MonoBehaviour
{
    [SerializeField] ItemData itemData;

    private void OnValidate()
    {
        if(itemData != null)
            name = "Item Object : " + itemData.itemName;
    }

    private void OnTriggerEnter(Collider other)
    {
        if(other.CompareTag("Player"))
        {
            Inventory.instance.AddItemToInventory(itemData);
        }
    }
}

 

 

3. UI 인벤토리 만들고 데이터 연결하기

 

 

using Cinemachine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Inventory : MonoBehaviour
{
    public static Inventory instance { get; private set; }
    public GameObject inventoryUI; // 인벤토리 UI
    public CinemachineVirtualCamera virtualCamera; // 플레이어 바라보고있는 카메라
    //public ItemDatabase itemDatabase;  // 아이템 데이터 베이스 SO
    public bool activeInventory;

    public List<InventoryItem> inventoryItems = new List<InventoryItem>();
    public Dictionary<ItemData, InventoryItem> inventoryDictionary = new Dictionary<ItemData, InventoryItem>();

    [Header("Inventory UI")]
    public UI_ItemSlot[] itemSlot;
    public Transform inventorySlotParent;

    int slotCount { get { return slotCount; } set { } }

    private void Awake()
    {
        // 싱글톤 패턴 구현
        if (instance == null)
        {
            instance = this;
            DontDestroyOnLoad(gameObject);  // 씬 전환시에도 유지되도록 설정
        }
        else
        {
            Destroy(gameObject);
        }
    }

    void UpdateSlotUI()
    {
        for(int i = 0; i < inventoryItems.Count; i++)
        {
            itemSlot[i].UpdateSlot(inventoryItems[i]);
        }
    }

    private void Start()
    {
        inventoryUI.SetActive(activeInventory);
        itemSlot = inventorySlotParent.GetComponentsInChildren<UI_ItemSlot>();
    }



    private void Update()
    {
        if(Input.GetKeyDown(KeyCode.I))
        {
            activeInventory = !activeInventory;
            inventoryUI.SetActive(activeInventory);
            virtualCamera.enabled = !activeInventory;
        }
    }


    public void AddItemToInventory(ItemData item)
    {
        if( inventoryDictionary.TryGetValue(item, out InventoryItem value))
        {
            value.AddStack();
        }
        else
        {
            InventoryItem newItem = new InventoryItem(item);
            inventoryItems.Add(newItem);
            inventoryDictionary.Add(item, newItem);
        }

        UpdateSlotUI();
    }

    public void RemoveItemFromInventory(ItemData item)
    {
        if(inventoryDictionary.TryGetValue(item, out InventoryItem value))
        {
            if(value.stackSize <= 1)
            {
                inventoryItems.Remove(value);
                inventoryDictionary.Remove(item);
            }
            else
            {
                value.RemoveStack();
            }
        }

        UpdateSlotUI();
    }
}

 

딕셔너리를 쓰는 이유 :

 

 

  • List 검색: O(n) - n개의 아이템을 모두 확인해야 함
  • Dictionary 검색: O(1) - 바로 찾을 수 있음

 

- List를 사용한 코드 ( 딕셔너리 X )

public void AddItemToInventory(ItemData item)
{
    // List에서 아이템 검색
    InventoryItem existingItem = inventoryItems.Find(invItem => invItem.data == item);
    
    if (existingItem != null)
    {
        // 기존 아이템이 있으면 수량 증가
        existingItem.AddStack();
    }
    else
    {
        // 새 아이템 추가
        inventoryItems.Add(new InventoryItem(item));
    }
    UpdateSlotUI();
}

 

 

 

 

 

 

 

 

 

 

 

 

 

using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class UI_ItemSlot : MonoBehaviour
{
    [SerializeField] Image itemImage;
    [SerializeField] TextMeshProUGUI itemText;

    public InventoryItem item;


    public void UpdateSlot(InventoryItem _newItem)
    {
        item = _newItem;
        itemImage.color = Color.white;

        if (item != null)
        {
            itemImage.sprite = item.data.itemIcon;

            if (item.stackSize > 1)
            {
                itemText.text = item.stackSize.ToString();
            }
            else
            {
                itemText.text = "";
            }
        }
    }
}

 

 

using System;

[Serializable]
public class InventoryItem
{
    public ItemData data;
    public int stackSize;

    public InventoryItem(ItemData newItemData)
    {
        data = newItemData;
        AddStack();
    }

    public void AddStack()
    {
        stackSize++;
    }
    public void RemoveStack()
    {
        stackSize--;
    }

}

 

 

 

  • ItemData (SO)
    • 아이템의 기본 정보 저장
    • 이름, 아이콘, 설명
  • InventoryItem
    • ItemData + 수량(stackSize) 관리
    • 실제 인벤토리에서 관리되는 단위
  • Inventory
    • 전체 시스템 관리
    • List와 Dictionary로 아이템 관리
    • UI 업데이트 처리
  • ItemObject
    • 실제 게임 월드의 아이템
    • 플레이어와 충돌 시 인벤토리에 추가
  • UI_ItemSlot
    • 인벤토리 UI의 각 슬롯
    • 아이템 아이콘과 수량 표시

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

관련글 더보기