Search Unity

Question Obtain OnMouseDrag() behavior immediately after instantiating an object

Discussion in 'Scripting' started by m098shrh7s7r95s9, Jan 24, 2023.

  1. m098shrh7s7r95s9

    m098shrh7s7r95s9

    Joined:
    Dec 23, 2022
    Posts:
    4
    My question is essentially the same as Instantiate prefab with mouse drag - Unity Forum, but that one is for an older version of Unity and didn't yield a solution, so I am creating a new thread.

    Here is a script that, when attached to a game object, allows the player to click and drag the object around on the screen:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class Draggable : MonoBehaviour
    4. {
    5.     void OnMouseDrag()
    6.     {
    7.         transform.position = GetMousePositionInWorldSpace();
    8.     }
    9. }
    (Here
    GetMousePositionInWorldSpace()
    is a custom function which I have omitted for brevity.)

    In my game, I have a UI button that, when clicked, instantiates a game object that has the Draggable script attached to it, with its location immediately under the mouse. I expected that this setup would allow the player to "drag out" the game object according to the following sequence of events:
    1. Player clicks the mouse on the button, generating a mouse down event
    2. The button instantiates a Draggable object at a location underneath the mouse
    3. Now the player has the mouse down and the pointer is over the Draggable object, so the object should call OnMouseDrag every frame
    4. The player keeps the mouse button held down, drags the object to where they want it, and then lets go
    However, this doesn't work, because (as I have confirmed by adding some debug statements) the UI button doesn't call the function you associate with it until the mouse up event occurs over the button. Therefore, by the time the prefab is instantiated, the mouse is no longer down, and OnMouseDrag is not called. There is another old thread AddListener to OnPointerDown of Button instead of onClick - Unity Answers about this issue, but the workaround proposed there is a bit hacky, and I have to wonder if a better solution hasn't come about in the years since. Moreover, even if I can get the prefab to instantiate on mouse down, this may not solve my issue, because I would then need to confirm that the OnMouseDown method does, in fact, get called.

    One workaround I have come up with is to include a
    bool dragModeActive
    in Draggable, toggle it on mouse down, and use the Update method with an if statement to encode my dragging behavior, but this would add considerable overhead in a scene with hundreds of assets when the player can only drag one at a time.

    How can I enable the player to "drag a game object" out of a UI button as described above?
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,735
    This is the reference timing diagram. You can see why your expectations are not met.

    Here is some timing diagram help:

    https://docs.unity3d.com/Manual/ExecutionOrder.html

    Notably the OnMouse* events happen before Update() occurs, and I assume they are collected and processed in separate batched steps.

    Would it? Humans are really really bad at assessing computer performance. I would try it first. It sounds like it would take five minutes to try.

    EDIT: I forgot I made one of these in my proximity buttons package. You can try it out right now, just clone a few hundred of these and see:

    https://github.com/kurtdekker/proxi...s/Assets/DemoWorldDragging/SimpleWorldDrag.cs

    The script would have to be hacked to make it so that the mouse (or touch) is immediately connected to the spawned object in the way you need, but it's pretty simple to do and test.
     
  3. m098shrh7s7r95s9

    m098shrh7s7r95s9

    Joined:
    Dec 23, 2022
    Posts:
    4
    This is precisely the part I am asking about. How do you "connect" the mouse to the spawned object?
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,735
    Look through the script I posted above:

    - identify the detection of touch that triggers "gripping"

    - provide an alternate way to trigger that state, eg, make an external "you have been clicked" mechanism, which you then use from the button.

    - use that way to force the drag state on the freshly-spawned object