상세 컨텐츠

본문 제목

유니티 인벤토리 드래그 앤 드롭

유니티/기능

by MJ_119 2024. 11. 29. 03:14

본문

 

참고 영상 : https://www.youtube.com/watch?v=kWRyZ3hb1Vc

 

https://www.youtube.com/watch?v=BGr-7GZJNXg

 

 

드래그 앤 드롭 순서

  1. 드래그 시작 (OnBeginDrag)
    - 아이템 이미지 클릭
    - 인벤토리 슬롯의 하위오브젝트인 이미지(UI)의 부모를 상위오브젝트로 올림(슬롯의 부모오브젝트)
    - 하이어라키에서 제일 밑으로 내림(화면 제일 앞으로 끌어내기, 안그러면 다른 슬롯들 뒤로 아이템 이미지가 가려짐)
    - 레이캐스트 타겟을 비활성화하여 드래그 중 다른 UI 요소와 상호작용하지 않게 함.
  2. 드래그 중 (OnDrag)
    - 아이템 이미지 드래그 중
    - 아이템의 위치를 마우스 커서 위치로 업데이트
  3. 드롭 (Slot의 OnDrop)
    - 여기서 parentAfterDrag가 새 슬롯으로 변경됨
    - parentAfterDrag : 드래그가 끝난 후 아이템이 위치할 부모 객체를 저장
  4. 드래그 종료 (OnEndDrag) - 변경된 parentAfterDrag (새 슬롯)으로 이동
    - 아이템 이미지의 부모 오브젝트를 정해서 그 자식으로 들어감.
    - 레이캐스트 타겟을 다시 활성화 ( 상호작용 가능하게 만듦 )

 

 

 

 

 

 

 

 

 

 

 

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

[CreateAssetMenu(fileName = "NewInventory", menuName = "Inventory/Inventory")]
public class Inventory : ScriptableObject
{
    public List<Item> items = new List<Item>(); // 아이템 목록


    public void AddItem(Item item)
    {
        items.Add(item);
    }


    public void RemoveItem(Item itemToRemove)
    {
        items.Remove(itemToRemove);
    }

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

// 아이템 타입
public enum ItemType
{
    Equipment,    // 장비형
    Consumable,   // 소비형
    Material,     // 재료
    Quest,        // 퀘스트
    Misc          // 기타
}

// 장비 슬롯 타입
public enum EquipmentSlotType
{
    None,
    Head,
    Chest,
    Legs,
    Feet,
    Weapon,
    Shield,
    Accessory
}

// 아이템 희귀도
public enum Rarity
{
    Common,
    Uncommon,
    Rare,
    Epic,
    Unique,
    Legendary
}


[CreateAssetMenu(fileName = "NewItem", menuName = "Inventory/Item")]
public class Item : ScriptableObject
{
    [Header("기본 정보")]
    public string itemName; // 아이템 이름
    public Sprite itemIcon;// 아이템 아이콘
    public string itemDescription;// 아이템 설명
    public ItemType itemType;// 아이템 타입
    public string itemID;// 고유 ID

    public bool isStackable;           // 중첩 가능 여부
    public int maxStackSize = 1;       // 최대 중첩 개수

    [Header("아이템 효과")]
    public float useTime = 1f;         // 사용 시간
    public bool canUseInBattle = true; // 전투중 사용 가능 여부

    [Header("장비 속성")]
    public bool isEquipment;           // 장비 여부
    public EquipmentSlotType equipSlot; // 장착 슬롯 종류
    public int durability = 100;       // 내구도
    public int defense;                // 방어력
    public int attack;                 // 공격력
    // 추가 : 무기 속성(빛,어둠,물,불)

    [Header("소비 아이템 속성")]
    public bool isConsumable;          // 소비 아이템 여부
    public float healthRestore;        // HP 회복량
    public float manaRestore;          // MP 회복량
    public float duration;             // 효과 지속시간


    [Header("기타")]
    public int buyPrice;               // 구매 가격
    public int sellPrice;              // 판매 가격
    public string requiredLevel;       // 필요 레벨
    public Rarity rarity;             // 희귀도

    // 아이템 사용 메서드
    public virtual void Use(Player player)
    {
        if (isConsumable)
        {
            // 소비 아이템 사용 로직
            //player.RestoreHealth(healthRestore);
            //player.RestoreMana(manaRestore);
        }
    }

    // 장비 장착 메서드
    public virtual void Equip(Player player)
    {
        if (isEquipment)
        {
            // 장비 장착 로직
            //player.AddDefense(defense);
            //player.AddAttack(attack);
        }
    }

    // 장비 해제 메서드
    public virtual void Unequip(Player player)
    {
        if (isEquipment)
        {
            // 장비 해제 로직
            //player.RemoveDefense(defense);
            //player.RemoveAttack(attack);
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// 아이템 데이터베이스 ScriptableObject
[CreateAssetMenu(fileName = "ItemDatabase", menuName = "Inventory/ItemDatabase")]
public class ItemDatabase : ScriptableObject
{
    // 만들어둔 아이템 SO들을 리스트에 미리 전부다 할당해놓기.
    public List<Item> items = new List<Item>();

    // ID로 아이템 찾기
    public Item FindItemById(string id)
    {
        return items.Find(item => item.itemID == id);
    }

    // Name으로 아이템 찾기
    public Item FindItemByName(string name)
    {
        return items.Find(item => item.itemName == name);
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ItemPickUp : MonoBehaviour
{
    public string itemId;  // 고유 아이템 ID를 Inspector에서 입력
    //public Item itemData;  // 인스펙터에서 아까 만든 아이템 에셋을 여기에 연결

    private void OnTriggerEnter(Collider other)
    {
        transform.SetAsLastSibling();
        //if (other.CompareTag("Player"))
        //{
        //    InventoryManager.Instance.AddItemToInventory(itemData);
        //    // 아이템 획득 처리
        //    //bool wasPickedUp = InventoryManager.instance.AddItemToInventory(itemData);
        //    //if (wasPickedUp)
        //    //{
        //    //    Debug.Log($"{itemData.itemName} 획득!");
        //    //    Destroy(gameObject);
        //    //}
        //}
        if (other.CompareTag("Player"))
        {
            // 아이템 데이터베이스에서 ID로 아이템 찾기
            Item itemToPickUp = InventoryManager.Instance.itemDatabase.FindItemById(itemId);

            if (itemToPickUp != null)
            {
                bool wasPickedUp = InventoryManager.Instance.AddItemToInventory(itemToPickUp);

                if (wasPickedUp)
                {
                    Debug.Log($"{itemToPickUp.itemName} 획득!");
                    Destroy(gameObject);
                }
            }
            else
            {
                Debug.LogError($"ID {itemId}에 해당하는 아이템을 찾을 수 없습니다.");
            }
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class InventoryManager : MonoBehaviour
{
    public static InventoryManager Instance { get; private set; }
    public Inventory playerInventory;  // 인벤토리 ScriptableObject
    public GameObject inventoryUI;
    public ItemDatabase itemDatabase;  // 아이템 데이터 베이스 SO
    public bool activeInventory;

    public List<Slot> slots = new List<Slot>();
    public Transform slotHolder;

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

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



    private void Start()
    {
        gameObject.SetActive(true);
        slots.AddRange(slotHolder.GetComponentsInChildren<Slot>());
        inventoryUI.SetActive(activeInventory);
        //slotCount = 4;
    }



    private void Update()
    {
        if(Input.GetKeyDown(KeyCode.I))
        {
            activeInventory = !activeInventory;
            inventoryUI.SetActive(activeInventory);
        }
    }
    public bool AddItemToInventory(Item item)
    {
        if (playerInventory != null)
        {
            playerInventory.AddItem(item);
            Debug.Log($"{item.itemName}이(가) 인벤토리에 추가되었습니다.");
        }
        else
        {
            Debug.LogError("playerInventory가 할당되지 않았습니다!");
        }

        // 빈 슬롯 찾기
        foreach (Slot slot in slots)
        {
            // 슬롯의 이미지가 비어있다면
            if (slot.itemImage.sprite == null)
            {
                // 슬롯에 아이템 설정
                slot.SetItem(item);

                Debug.Log($"{item.itemName} 아이템 획득!");

                return true;
            }
        }
        return false;
    }

    public void RemoveItemFromInventory(Item item)
    {
        if (playerInventory != null)
        {
            playerInventory.RemoveItem(item);
            Debug.Log($"{item.itemName}이(가) 인벤토리에서 제거되었습니다.");
        }
        else
        {
            Debug.LogError("playerInventory가 할당되지 않았습니다!");
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class DraggableItem : MonoBehaviour, IBeginDragHandler, IDragHandler ,IEndDragHandler
{
    public Transform parentAfterDrag; // 드래그가 끝난 후 아이템이 위치할 부모 객체를 저장
    public Image image; // 아이템 이미지


    // 드래그 시작 시 호출
    public void OnBeginDrag(PointerEventData eventData)
    {
        parentAfterDrag = transform.parent; // 현재 부모를 parentAfterDrag에 저장
        transform.SetParent(transform.root); // 아이템을 최상위 레벨로 이동시켜 다른 UI 요소 위에 표시되게 합니다.
        transform.SetAsLastSibling(); // 부모의 자식 목록에서 가장 마지막으로 이동
        image.raycastTarget = false; // 레이캐스트 타겟을 비활성화하여 드래그 중 다른 UI 요소와 상호작용하지 않게 합니다.
    }


    // 드래그 중 지속적으로 호출
    public void OnDrag(PointerEventData eventData)
    {
        transform.position = Input.mousePosition; // 아이템의 위치를 마우스 커서 위치로 업데이트
    }


    // 드래그가 끝날 때 호출
    public void OnEndDrag(PointerEventData eventData)
    {
        transform.SetParent(parentAfterDrag);
        image.raycastTarget = true; // 레이캐스트 타겟을 다시 활성화 ( 상호작용 가능하게 만듦 )
    }
}

 

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class Slot : MonoBehaviour, IDropHandler
{
    public Image itemImage; // 현재 슬롯의 아이템 이미지
    public Item currentItem; // 현재 슬롯의 아이템 정보

    // 슬롯에 아이템 설정 메서드
    public void SetItem(Item item)
    {
        // 아이템 이미지 활성화
        //itemImage.gameObject.SetActive(true);

        currentItem = item; // 현재 아이템 저장

        // 아이템 아이콘 설정
        itemImage.sprite = item.itemIcon;

    }

    // 슬롯 초기화 메서드
    public void ClearSlot()
    {
        //itemImage.gameObject.SetActive(false);
        currentItem = null; // 아이템 참조 제거
        itemImage.sprite = null;
    }

    // 아이템이 이 슬롯에 드롭될 때 호출
    public void OnDrop(PointerEventData eventData)
    {
        // 아래 코드는 이전의 코드
        //if(transform.childCount == 1)
        //{
        //    GameObject dropped = eventData.pointerDrag;
        //    DraggableItem draggableItem = dropped.GetComponent<DraggableItem>();
        //    draggableItem.parentAfterDrag = transform;
        //} 


        GameObject dropped = eventData.pointerDrag;
        // dropped가 null인지 먼저 체크
        if (dropped == null)
        {
            Debug.LogWarning("드래그된 오브젝트가 없습니다.");
            return;
        }


        DraggableItem draggableItem = dropped.GetComponent<DraggableItem>();

        // draggableItem이 null인지 체크
        if (draggableItem == null)
        {
            Debug.LogWarning("DraggableItem 컴포넌트를 찾을 수 없습니다.");
            return;
        }

        // 드래그된 아이템의 원래 슬롯 찾기
        //Slot originalSlot = draggableItem.GetComponentInParent<Slot>();

        // 원래 슬롯 찾기 (GetComponentInParent 대신 다른 방법 사용)
        //Slot originalSlot = dropped.GetComponentInParent<Slot>();

        Slot originalSlot = draggableItem.parentAfterDrag.GetComponent<Slot>();

        if (originalSlot == null)
        {
            Debug.LogWarning("원래 슬롯을 찾을 수 없습니다.");
            return;
        }

        // 현재 슬롯에 아이템이 있는 경우
        if (itemImage.sprite != null)
        {
            // 원래 슬롯 초기화
            originalSlot.ClearSlot();
        }
        else
        {
            // 원래 슬롯에서 아이템 제거
            originalSlot.ClearSlot();
        }

        // 드래그된 아이템을 현재 슬롯의 자식으로 설정
        draggableItem.parentAfterDrag = transform;

        // 현재 슬롯에 아이템 설정
        SetItem(originalSlot.currentItem);
    }
}

 

 

 

 

'유니티 > 기능' 카테고리의 다른 글

유니티 3D 발소리,footstep,Sound 적용하기  (0) 2024.12.24
유니티 OnValidate()  (0) 2024.12.21
유니티 인벤토리 데이터 베이스  (0) 2024.11.26
유니티 인벤토리 아이템 설정  (1) 2024.11.08
유니티 딕셔너리  (0) 2024.11.01

관련글 더보기