Equivalent of OnMouseDrag() in new input system

Hello, I’m converting a recent project to use the new input system. The project is a tarot-deck, where each playing card is an object with a collider and rigidbody. I have some functionality working great already, for example, if I want to flip a card over, I use the right mouse button like this:

public void OnPointerDown(PointerEventData eventData)
    {
        if (eventData.button == PointerEventData.InputButton.Right)
        {
            rb.AddForce((new Vector3(0.08f, 1, 0) * flipForce), ForceMode.Impulse);
            rb.AddRelativeTorque(0, 0, flipTorque, ForceMode.Impulse);
        }
}

However, I tried to add a “drag-and-drop” behaviour to the OnPointerDown() function, and I’ve got stuck. The documentation for the IPointerDownHandler says that it “Detects ongoing mouse clicks until release of the mouse button”, so I thought I could just take my old code from an OnMouseDrag() function and paste it into OnPointerDown(). However, this only seems to fire on the first frame that I press the left mouse button. Here’s my entire OnPointerDown() function, with the old code from OnMouseDrag():

public void OnPointerDown(PointerEventData eventData)
    {
        if (eventData.button == PointerEventData.InputButton.Right)
        {
            rb.AddForce((new Vector3(0.08f, 1, 0) * flipForce), ForceMode.Impulse);
            rb.AddRelativeTorque(0, 0, flipTorque, ForceMode.Impulse);
        }

        if (eventData.button == PointerEventData.InputButton.Left) //What follows is the contents of the old "void OnMouseDrag()"
        {
            Plane plane = new Plane(Vector3.up, new Vector3(0, 0.33f, 0)); //create a new plane somewhere above the table
            Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue()); //create a ray from the mouse screen position to the table
            float distance;

            if (!GameManager.IsPointerOverUIObject())
            {
                //Plane.Raycast returns the distance along the ray, where it intersects with the plane
                if (plane.Raycast(ray, out distance))
                {
                    transform.position = ray.GetPoint(distance); //sets the objects position to the point along the ray specified by "distance"

                    if (FacingUp() == true) //also rotates the cardto a standard rotation ???maybe add a random range???
                    {
                        transform.rotation = Quaternion.Euler(new Vector3(0, 0, 0));
                    }
                    else
                    {
                        transform.rotation = Quaternion.Euler(new Vector3(0, 0, 180));
                    }

                    //freeze the constraints of the object while moving
                    rb.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationY | RigidbodyConstraints.FreezeRotationZ;
                }
            }
        }
    }

What approach should I take instead? It now seems obvious that I need something different for my single-fire card flip (with the right mouse button), and my every-frame card drag (with the left mouse button), but I’m not sure how the new input system is supposed to handle the latter.

https://docs.unity3d.com/Packages/com.unity.inputsystem@1.0/manual/KnownLimitations.html

Drag is supported by the old only.

Not exactly what it says there. OnMouseDrag will not be called, that does not mean that you can’t get mouse drag working. It is more complicated than the old way, but this guy figured it out:

https://www.youtube.com/watch?v=WjPDPyt3pBY

All props to him.

4 Likes

works like a charm…

1 Like

Glad you folks found my approach was useful. I didn’t even know I had been mentioned here until a British filmmaker (hi, Max!) who also needs this found me via this discussion. Nice to know my little tutorial is finding an audience.

4 Likes