보통 생존게임에서 아이템을 버릴때는, 인벤토리의 아이템을 클릭하고 인벤토리 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하게 해야합니다.
// ItemData.cs
// 각 Data에 맞는 Prefab을 에디터에서 넣어줌
public GameObject itemPrefab;
// 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);
}
}
Mesh Collider의 Is Trigger를 체크 해제Rigidbody 컴포넌트 추가마치 정말 던져서 버리는 것처럼 구현됩니다.
Instantiate다음 글에서는: