Hi all, sorry if this is posted in the wrong place, I did not know where else to post it. I am working for an inventory system for my game. It works, more or less, but I am having an issue with the drag and drop.
When I drag items from the inventory item slots (controlled by one script) into the equipped weapon slot(controlled by another script) for the first once or twice it works, but if you drag back and forwards more than a few times, the item is destroyed or the game even crashes. I admit I have turned to chatGPT to help me build it, as I am relatively new to coding, and I guess this is partly where the problems come from.
Here are the scripts involved. Firstly, my main Inventory script:
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Inventory
{
private static Inventory instance;
public static Inventory Instance
{
get
{
if (instance == null)
{
instance = new Inventory(); // Create the inventory instance if it doesn't exist
}
return instance;
}
}
[SerializeField] private List<Item> items = new List<Item>(); // List to hold items
[SerializeField] private int maxInventorySize = 10; // Define max size of inventory
public bool AddItem(Item item)
{
if (item == null)
{
Debug.Log("Cannot add null item!");
return false; // Item is null
}
if (items.Count < maxInventorySize)
{
items.Add(item);
Debug.Log($"{item.name} added to inventory.");
return true; // Item added successfully
}
else
{
Debug.Log("Inventory is full!");
return false; // Inventory full
}
}
public bool RemoveItem(Item item)
{
if (item == null)
{
Debug.Log("Cannot add null item!");
return false; // Item is null
}
if (items.Contains(item))
{
items.Remove(item);
Debug.Log($"{item.name} removed from inventory.");
return true; // Item removed successfully
}
else
{
Debug.Log($"{item.name} not found in inventory!");
return false; // Item not found
}
}
public int GetItemCount(Item item)
{
int count = 0;
foreach (var invItem in items)
{
if (invItem == item)
{
count++;
}
}
return count;
}
public List<Item> GetItems()
{
return items; // Return the list of items
}
}
My Item slot script:
using UnityEngine;
using TMPro;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class ItemSlot : MonoBehaviour, IPointerDownHandler, IDragHandler, IEndDragHandler, IDropHandler
{
[SerializeField] private Image itemIcon; // Reference to the item icon image
[SerializeField] private TextMeshProUGUI itemNameText; // Reference to the item name text
[SerializeField] private TextMeshProUGUI itemCountText; // Reference to the item count text
protected static ItemSlot draggedFromSlot;
protected static Image draggedItemIcon; // Reference to the icon being dragged
private Vector3 startPosition;
private Transform startParent;
public Item currentItem;
public int itemCount;
public ItemType acceptedItemType = ItemType.Any;
public void SetItem(Item item, int count)
{
currentItem = item;
itemCount = count;
if (item == null)
{
itemIcon.sprite = null;
itemNameText.text = "";
itemCountText.text = "";
itemIcon.color = new Color(1, 1, 1, 0); // Transparent when no item
return;
}
itemIcon.sprite = item.GetIcon();
itemIcon.color = Color.white;
itemNameText.text = item.itemName;
itemCountText.text = count > 1 ? count.ToString() : "";
}
public void ClearSlot()
{
currentItem = null;
itemCount = 0;
itemIcon.sprite = null;
itemIcon.color = new Color(1, 1, 1, 0); // Make it transparent
itemNameText.text = "";
itemCountText.text = "";
}
public void OnPointerDown(PointerEventData eventData)
{
if (currentItem != null)
{
// Store initial info for dragging
draggedFromSlot = this;
draggedItemIcon = itemIcon;
startPosition = itemIcon.transform.position;
startParent = itemIcon.transform.parent;
itemIcon.raycastTarget = false; // Disable raycast to allow proper dragging
}
}
public virtual void OnDrag(PointerEventData eventData)
{
if (draggedItemIcon != null)
{
draggedItemIcon.transform.position = Input.mousePosition; // Follow the mouse
}
}
public virtual void OnDrop(PointerEventData eventData)
{
Debug.Log("ItemSlot OnDrop called.");
// Find all ItemSlots in the hierarchy
ItemSlot[] allSlots = FindObjectsOfType<ItemSlot>();
foreach (ItemSlot slot in allSlots)
{
RectTransform dropArea = slot.GetComponent<RectTransform>();
if (RectTransformUtility.RectangleContainsScreenPoint(dropArea, eventData.position, eventData.pressEventCamera))
{
if (draggedFromSlot != null && draggedFromSlot != slot)
{
Item tempItem = slot.currentItem;
int tempItemCount = slot.itemCount;
// Check if draggedFromSlot is valid
if (draggedFromSlot.currentItem == null)
{
Debug.LogError("Dragged item is null!");
return;
}
// If dragged from EquippedWeaponSlot, update the unit's inventory
if (draggedFromSlot is EquippedWeaponSlot equippedSlot)
{
Unit unit = equippedSlot.Unit;
if (unit != null)
{
// Update Unit's inventory: add the dragged item to inventory, remove equipped item
if (unit.AddItem(draggedFromSlot.currentItem))
{
unit.RemoveItem(tempItem);
}
else
{
Debug.LogError("Failed to add item to unit's inventory.");
return;
}
}
}
// Swap the items
slot.SetItem(draggedFromSlot.currentItem, draggedFromSlot.itemCount);
draggedFromSlot.SetItem(tempItem, tempItemCount);
Debug.Log($"Swapped items: {slot.currentItem?.itemName} <-> {draggedFromSlot.currentItem?.itemName}");
}
return;
}
}
}
public virtual void OnEndDrag(PointerEventData eventData)
{
if (draggedItemIcon != null)
{
// If dropped in a valid slot, reset raycast
draggedItemIcon.raycastTarget = true;
// If the parent is unchanged, reset the position
if (itemIcon.transform.parent == startParent)
{
itemIcon.transform.position = startPosition;
}
// Reset dragging references
draggedItemIcon = null;
draggedFromSlot = null;
}
}
}
and my EquippedWeaponSlot script:
using UnityEngine;
using TMPro;
using System;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class EquippedWeaponSlot : ItemSlot
{
[SerializeField] private Unit unit; // Reference to the Unit that owns this weapon slot
public Unit Unit => unit; //remove if broken
private void OnEnable()
{
UnitActionSystem.Instance.OnSelectedUnitChanged += HandleSelectedUnitChanged;
}
private void OnDisable()
{
UnitActionSystem.Instance.OnSelectedUnitChanged -= HandleSelectedUnitChanged;
}
private void Start()
{
// Initial unit assignment if necessary
UpdateUnitReference(UnitActionSystem.Instance.GetSelectedUnit());
}
private void HandleSelectedUnitChanged(object sender, EventArgs e)
{
UpdateUnitReference(UnitActionSystem.Instance.GetSelectedUnit());
}
private void UpdateUnitReference(Unit newUnit)
{
unit = newUnit;
if (unit == null)
{
Debug.LogError("Unit reference could not be found!");
}
}
public override void OnDrop(PointerEventData eventData)
{
Debug.Log("EquippedWeaponSlot OnDrop called.");
ItemSlot[] allSlots = FindObjectsOfType<ItemSlot>();
foreach (ItemSlot itemSlot in allSlots)
{
RectTransform dropArea = itemSlot.GetComponent<RectTransform>();
if (RectTransformUtility.RectangleContainsScreenPoint(dropArea, eventData.position, eventData.pressEventCamera))
{
if (ItemSlot.draggedFromSlot != null && ItemSlot.draggedFromSlot != itemSlot)
{
Item tempItem = itemSlot.currentItem;
int tempItemCount = itemSlot.itemCount;
this.SetItem(ItemSlot.draggedFromSlot.currentItem, ItemSlot.draggedFromSlot.itemCount);
if (unit == null)
{
Debug.LogError("Unit reference is not assigned in EquippedWeaponSlot.");
return;
}
if (ItemSlot.draggedFromSlot.currentItem != null)
{
if (ItemSlot.draggedFromSlot.currentItem.itemType == ItemType.Weapon)
{
Debug.Log($"Equipping weapon: {ItemSlot.draggedFromSlot.currentItem.name}");
unit.SetEquippedWeapon(ItemSlot.draggedFromSlot.currentItem); // Ensure unit reference is not null
WeaponManager weaponManager = unit.GetComponent<WeaponManager>();
if (weaponManager != null)
{
weaponManager.UpdateEquippedWeapon(ItemSlot.draggedFromSlot.currentItem);
}
}
else
{
Debug.LogError("Dragged item is not a valid weapon type!");
}
}
else
{
Debug.LogError("Dragged item is null!");
}
ItemSlot.draggedFromSlot.SetItem(tempItem, tempItemCount); // this should update the inventory list, but doesnt
InventoryUI.Instance.Refresh();
}
return;
}
}
}
// Optional: Override OnEndDrag if you want to do anything specific when dragging ends
public override void OnEndDrag(PointerEventData eventData)
{
base.OnEndDrag(eventData);
// Any additional functionality for when the drag ends can be added here
}
}