[Unity / C#] 아이템 버리기

주예성·2025년 6월 17일

📋 목차

  1. DragHandler
  2. 중간 결과
  3. 맵으로 아이템 버리기
  4. 최종 결과
  5. 오늘의 배운 점
  6. 다음 계획

🖱️ DragHandler

보통 생존게임에서 아이템을 버릴때는, 인벤토리의 아이템을 클릭하고 인벤토리 UI 밖으로 드래그해서 없앱니다. 이것을 DragHandler를 이용하여 처리합니다.

// InventorySlot.cs

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;


public class InventorySlot : MonoBehaviour, IPointerClickHandler, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    [Header("UI Elements")]
    [SerializeField] private GameObject UIManager;
    [SerializeField] private Image itemIcon;
    [SerializeField] private RectTransform backgroundRect;

    [Header("etc")]
    [SerializeField] private GameObject player;
    [SerializeField] private int slotIndex;

    private UIManager uiManager;
    private Inventory inventory;
    private GameObject dragObject; // 드래그할 복제 오브젝트
    private Canvas canvas; // 복제 오브젝트의 부모

    private void Start()
    {
        if (UIManager)
        {
            uiManager = UIManager.GetComponent<UIManager>();
            inventory = player.GetComponent<Inventory>();
        }
        canvas = GetComponentInParent<Canvas>();
    }

    public void OnPointerClick(PointerEventData eventData)
    {
        if (!inventory.items[slotIndex]) return;

        if (eventData.clickCount == 2)
        {
            uiManager.OnSlotDoubleClick(slotIndex);
        }
    }

    public void OnBeginDrag(PointerEventData eventData) 
    {
        if (!inventory.items[slotIndex]) return;

        if (!itemIcon) return;

        itemIcon.color = new Color(1, 1, 1, 0.5f); // 드래그 시작하면 버려질 아이템은 불투명하게

        dragObject = new GameObject("DragIcon");
        dragObject.transform.SetParent(canvas.transform, false);

        Image dragImage = dragObject.AddComponent<Image>();
        dragImage.sprite = itemIcon.sprite;
        dragImage.color = new Color(1, 1, 1, 0.8f); // 불투명한 채로 옮겨가는 복제 오브젝트

        RectTransform dragRect = dragObject.GetComponent<RectTransform>();
        dragRect.sizeDelta = itemIcon.rectTransform.sizeDelta;
        dragRect.position = itemIcon.transform.position;

        dragObject.transform.SetAsLastSibling(); // 복제 오브젝트를 UI 맨 위로
    }
    
    public void OnDrag(PointerEventData eventData) 
    {
        if (!inventory.items[slotIndex]) return;

        if (!dragObject) return;
        dragObject.transform.position = eventData.position;

    }

    public void OnEndDrag(PointerEventData eventData) 
    {
        if (!inventory.items[slotIndex]) return;

        float mouseX = eventData.position.x;
        float mouseY = eventData.position.y;

        if (!backgroundRect) return;

        float backgroundWidth = backgroundRect.sizeDelta.x;
        float backgroundHeight = backgroundRect.sizeDelta.y;
        float screenWidth = Screen.width;
        float screenHeight = Screen.height;

        bool isDestroy = false;

		// 인벤토리 창 바깥으로 갈 경우 아이템 삭제
        if (mouseX < (screenWidth - backgroundWidth) / 2 || mouseX > (screenWidth + backgroundWidth) / 2 ||
            mouseY < (screenHeight - backgroundHeight) / 2 || mouseY > (screenHeight + backgroundHeight) / 2)
        {
            if (!inventory || !uiManager) return;
            inventory.RemoveItem(slotIndex);
            uiManager.UpdateItemUI();
            isDestroy = true;
            Debug.Log("아이템삭제완료");
        }

		// 아이템 UI 처리
        CleanupDragIcon(isDestroy);
    }

    private void CleanupDragIcon(bool destroy)
    {
        if (dragObject)
        {
        	// 드래그가 끝나면 복제 오브젝트는 삭제
            Destroy(dragObject);
            dragObject = null;
            // 아이템이 삭제됐다면 버린 아이템 슬롯은 투명화
            if (destroy)
            {
                itemIcon.color = new Color(1, 1, 1, 0f);
            }
            // 삭제하지 않았다면 드래그한 아이템 스롯은 원래 투명도로
            else
            {
                itemIcon.color = new Color(1, 1, 1, 1f);
            }
        }
    }
}


🎮 중간 결과

인벤토리 슬롯 안의 아이템을 클릭 앤 드래그 드롭을 하게 됩니다. 인벤토리 창 안에 드롭을 할 경우 삭제되지 않고, 창 밖으로 버려야 삭제됩니다.


🗑️ 맵으로 아이템 버리기

이제 인벤토리에서 꺼낸 아이템은 맵에 버려져야 합니다. 그럼 해당 Prefab 정보가 필요하고, 스크립트에서 직접 Spawn하게 해야합니다.

1. ItemData에 Prefab 정보 추가

// ItemData.cs

// 각 Data에 맞는 Prefab을 에디터에서 넣어줌
public GameObject itemPrefab;

2. 물리엔진을 이용한 아이템 버리기

// Inventory.cs

// Rigidbody를 이용하여 '던져서 버리는' 느낌을 줌
// ThrowItem 함수는 InventorySlot 스크립트의 OnEndDrag에 넣음
public void ThrowItem(int index)
{
    ItemData item = items[index];

    if (!item) return;

    Vector3 dropPosition = transform.position + transform.forward * 0.5f + Vector3.up * 0.1f;

    GameObject thrownItem = Instantiate(item.itemPrefab, dropPosition, Quaternion.identity);

    Rigidbody rb = thrownItem.GetComponent<Rigidbody>();
    if (rb != null)
    {
        Vector3 throwForce = transform.forward * 5f + Vector3.up * 2f;
        rb.AddForce(throwForce, ForceMode.Impulse);
    }

}

3. 각 Prefab에 Rigidbody 추가

  1. 각 Prefab의 Component에서 Mesh ColliderIs Trigger를 체크 해제
  2. Rigidbody 컴포넌트 추가

🎮 최종 결과

마치 정말 던져서 버리는 것처럼 구현됩니다.


📚 오늘의 배운 점

  • DragHandler
  • UI창 크기를 통한 결과값 제어
  • Rigidbody를 이용한 아이템 Instantiate

🎯 다음 계획

다음 글에서는:

  1. 제작 아이템 추가
  2. 제작대 시스템 구현
profile
Unreal Engine & Unity 게임 개발자

0개의 댓글