Search Unity

Unity UI [Solved] Trying to detect a drop directly on the canvas

Discussion in 'UGUI & TextMesh Pro' started by Sun-Dog, Mar 15, 2018.

  1. Sun-Dog

    Sun-Dog

    Joined:
    Mar 23, 2009
    Posts:
    144
    I am essentially trying to drop onto nothing.

    I'm recreating a classic fRPG Inventory. I have a reliable drag and drop system that detects icon drops onto targets using implementations of IDropHandler and OnDrop.

    My UI resides in a full screen canvas.

    I want to be able to drop an icon into "nothing" (essentially the empty canvas), detect the drop and bring up my modal window with a "Do you want to destroy / drop <this item>?" [Yes] [No] Message. (Modal window is working fine, btw).

    What's not working are any of my attempts to detect a drop onto the canvas, nor have I done well at finding a way to check what's under the pointer to analyse that data to trigger the modal window.

    One thought was the IsPointerOverGameObject (iirc the name), but as the canvas is a UI Element and it's fullscreen, my pointer will always return true with that one.

    Any thoughts on the best way to check if I've done a PointerUp or Drop over nothing but the canvas?
     
  2. Sun-Dog

    Sun-Dog

    Joined:
    Mar 23, 2009
    Posts:
    144
    Hum.... some progress:

    I discovered that PointerEventData has hovered.

    That means I can do this:

    Code (csharp):
    1.  
    2.     public void OnPointerUp (PointerEventData data)
    3.     {
    4.         // Some Code
    5.  
    6.             List<GameObject> hoveredList = data.hovered;
    7.             foreach (var GO in hoveredList)
    8.             {
    9.                 Debug.Log("Hovering over: " + GO.name);
    10.             }
    11.         // More Code
    12.     }
    13.  
    f621c108fc410aeae860e3f5f94cbd2d.png

    This, however, just gives me a list of all of the GameObjects in the hierarchy under the pointer, and when it's not over a UI Element (eg: the UI "Void") where I want to detect a drop outside the UI, I just get a list of all of the walls and floors and chests in the scene under the pointer. I'm not sure how I can sort this into valid data to prove there is no UI Elements there, so therefore it's not in the UI, so therefore I can destroy it...

    Better, still not optimal.

    Anyone else have any thoughts?
     
  3. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    I'm fairly positive that OnDrop occurs before OnEndDrag. This means that you can unparent a UI object when you drag it, and re-parent for a valid drop. If OnEndDrag occurs and the parent is the canvas, you can execute your logic at that time.
     
  4. Sun-Dog

    Sun-Dog

    Joined:
    Mar 23, 2009
    Posts:
    144
    Poop. Good idea. Sadly, the UI Object is always parented directly to the canvas.

    What I'm doing is using a "Dragging Item" that I use when an icon/item is "grabbed" from a slot, rather than moving the icon/item clicked on itself. [edit] I transfer all of the necessary data to the dragging item: its icon, a reference to the item, etc..[/edit] This way, I can leave the "slot" where it is (and this is important as it's in a layout group) is and just make it an "empty slot". This means I can't test who's the parent or a parent change.

    DraggingObject.png
    *simplified hierarchy

    The "OnDrops" are handled independently by whatever received the "OnDrop" event, so if I drop on another slot or another panel, they have their own "OnDrop" to handle the event. Dropping on the inventory panel, but missing a slot, will try to add the item generically to the inventory. Dropping on as slot will try to add at that slot, or add to stack or swap item ... or whatever the logic needs to be. This means that the "void" or base canvas needs to detect the drop independently.

    I'm currently experimenting on the rout of making a "drop catcher" layer that resided under the entire UI.

    My problem there is that i need to click into the scene, and an invisible image layer that can detect the drop also blocks all raycasts into the scene. If I disable "blocks raycasts" or if I make "raycast target = false" then the UI Element doesn't detect the event!

    Bother!
     
    Last edited: Mar 17, 2018
  5. Sun-Dog

    Sun-Dog

    Joined:
    Mar 23, 2009
    Posts:
    144
  6. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Hmm.. I did a similar thing (with a 'dragged' object) representing inventory items, for instance. However, instead of what you did, I still ran "OnDrag" on the slot, but simply moved the draggable item in its place (never moved the inventory slot item). This way, I didn't really transfer much - just the icon, I think?

    You could maybe have something like:
    Code (csharp):
    1. void OnDrop(PointerEventData data) {
    2.    InvItem ii = data.pointerDrag.GetComponent<InvItem>();
    3.    if(ii) {
    4.        ii.validDrop = true;
    5.      }
    6.   }
    7. void OnEndDrag(PointerEventData data) {
    8.    if(!validDrop) // dropped in void
    9.    validDrop = false; // just reset for future use, doesn't matter if it was valid or not at this point, I think.
    10.   }
    Okay, so I'm going to leave that there. I think that might work.. however, I just had another thought after I wrote that. What if you destroy the dragged image (which I assume you do 'OnDrop') if it's successful, and then set it to null there.. again, if successful.
    Now, if OnEndDrag, the draggable image isn't null, you know you're in the void?

    This second idea would avoid that extra bit of saving a variable.

    Let me know if that makes sense, or if I wrote it too quickly without thinking it through lol
     
    BlackJak99 likes this.
  7. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
  8. Sun-Dog

    Sun-Dog

    Joined:
    Mar 23, 2009
    Posts:
    144
    Oh! (Crosspost!)

    That's a cool solution! I may have a rethink.

    Thanks!

    I get what you're doing there now.
     
  9. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    :) Of course, just checking "activeSelf" for the dragged image is cool, too.. if you re-use that image/game object.