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:
using UnityEngine;
public class Draggable : MonoBehaviour
{
void OnMouseDrag()
{
transform.position = GetMousePositionInWorldSpace();
}
}
(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:
- Player clicks the mouse on the button, generating a mouse down event
- The button instantiates a Draggable object at a location underneath the mouse
- Now the player has the mouse down and the pointer is over the Draggable object, so the object should call OnMouseDrag every frame
- 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?