- Home /
OnDrop called on wrong GameObject
I am implementing a drag and drop inventory interface - I have a UI Panel with an Inventory script on it, which instantiates an appropriate number of InventorySlot prefabs on Start(). The prefabs consist of a UI Image with an InventorySlot script and a InventoryDropHandler attached, and a child UI Image with a InventoryDragHandler attached. The idea is that the child image has the item icon on it, can be dragged to other slots and the parent InventorySlot object will handle the drop.
I've been using this tutorial as a basis: https://www.youtube.com/watch?v=c47QYgsJrWc≈p=desktop - the only thing I'm doing slightly differently is that I'm not changing the parent of the child item icon object to the new InventorySlot, instead I am assigning the internal GameObject which represents my actual item to the new slot, setting the child icon based on that, and resetting the original item icon back to it's previous state.
My problem is that after moving from one slot to the other (which works as expected), if I try to move back to the original slot (or any other slot that has held an item), the OnDrop function gets called on whichever InventorySlot the item is currently in, rather than the destination. I can't see anyway this is happening so I'm baffled.
Any help would be much appreciated - here are the appropriate scripts:
Inventory.cs (on the parent panel)
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Inventory : MonoBehaviour {
public int slotSize = 32;
public int offset = 5;
public List<InventorySlot> slots = new List<InventorySlot>();
public GameObject slotPrefab;
public static GameObject draggingItem;
public static bool isDragging = false;
// Use this for initialization
void Start () {
// create an appropriate number of slots for the size of the panel
RectTransform panelRect = GetComponent<RectTransform> ();
int columns = (int)Mathf.Floor (panelRect.rect.width / (slotSize + offset));
int rows = (int)Mathf.Floor (panelRect.rect.height / (slotSize + offset));
for (int x = 0; x < columns; x++) {
for (int y = 0; y < rows; y++)
{
GameObject newSlot = Instantiate(slotPrefab);
newSlot.transform.SetParent(this.transform);
slots.Add (newSlot.GetComponent<InventorySlot>());
}
}
}
public void AddItemToInventory(GameObject item)
{
if (item.GetComponent<InventoryItem> () != null) {
foreach (InventorySlot slot in slots)
{
if (slot.itemInSlot == null)
{
slot.PutItemInSlot(item);
break;
}
}
}
}
}
InventorySlot.cs (on the parent Image in the prefab)
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class InventorySlot : MonoBehaviour {
public GameObject itemInSlot;
protected Image itemIcon;
// Use this for initialization
void Start () {
itemIcon = this.transform.Find ("ItemIcon").GetComponent<Image> ();
}
public void ResetImagePosition()
{
transform.Find ("ItemIcon").position = Vector3.zero;
transform.Find ("ItemIcon").gameObject.GetComponent<CanvasGroup> ().blocksRaycasts = true;
}
public void PutItemInSlot(GameObject obj)
{
InventoryItem item = obj.GetComponent<InventoryItem> ();
if (!item) {
return;
}
obj.SetActive (false);
itemInSlot = obj;
itemIcon.gameObject.SetActive (true);
itemIcon.sprite = item.icon;
if (item.currentSlot != null) {
item.currentSlot.RemoveItemFromSlot();
}
item.currentSlot = this;
}
public void RemoveItemFromSlot()
{
itemInSlot = null;
itemIcon.gameObject.SetActive (false);
itemIcon.sprite = null;
}
}
InventoryDragHandler.cs (on the child Image in the prefab)
using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
public class InventoryDragHandler : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler {
protected Vector3 startPosition;
#region IBeginDragHandler implementation
public void OnBeginDrag (PointerEventData eventData)
{
Inventory.draggingItem = GetComponentInParent<InventorySlot> ().itemInSlot;
Inventory.isDragging = true;
GetComponent<CanvasGroup> ().blocksRaycasts = false;
startPosition = transform.position;
}
#endregion
#region IDragHandler implementation
public void OnDrag (PointerEventData eventData)
{
transform.position = Input.mousePosition;
}
#endregion
#region IEndDragHandler implementation
public void OnEndDrag (PointerEventData eventData)
{
transform.position = startPosition;
Inventory.isDragging = false;
Inventory.draggingItem = null;
}
#endregion
}
InventoryDragHandler.cs (on the parent Image in the prefab)
using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
public class InventoryDropHandler : MonoBehaviour, IDropHandler {
public InventorySlot slot;
void Start()
{
slot = GetComponent<InventorySlot> ();
//Debug.Log ("Started drop handler", slot);
}
#region IDropHandler implementation
public void OnDrop (PointerEventData eventData)
{
Debug.Log ("Dropped", slot);
if (slot.itemInSlot == null) {
Inventory.draggingItem.GetComponent<InventoryItem>().currentSlot.ResetImagePosition();
slot.PutItemInSlot(Inventory.draggingItem);
}
}
#endregion
}
InventoryItem.cs (this goes on any GameObject I want to be able to place in an inventory
using UnityEngine;
using System.Collections;
public class InventoryItem : MonoBehaviour {
public Sprite icon;
public InventorySlot currentSlot;
}
Pay close attention to hierarchy with debug.log to see what is firing where. Parent/Child relations seem to have.. interesting effects with the Event System. I just got done figuring out the parent's OnPointerEnter was firing off even when thepointer hovered a child that was offset from it.
Good luck, event system bugs are the hardest I've had to find so far and the documentation is garbage.
Cheers.
I've long since dropped this project and have moved to UE4 for my hobby projects, but thanks for the comment! Brought back good memories of working on this :) Good luck with your project!
(Also just noticed this isn't the same Unity account I wrote the question with, hah)
Answer by text23d · Oct 26, 2017 at 02:39 PM
I also used same tutorial and had same problem. Then I started experimenting with Canvas/Canvas component. I changed "render mode" to three ooptions, and concluded that "screen space - overlay" works best. also, see that there is "PIXEL PERFECT" chaeckbox? I just checked it and it seems like this Drag-and-drop Inventory is now working perfectly. COOL!!!! ;-)