Throw an object on the canvas

I am trying to create a draggable physics object on the Canvas, and one thing I’m trying to do is allow the player to throw the object by letting go of it while moving it, but I’ve tried many things to make this work, and it’ll just stop when you let go of it.

Any help?

Camera cam;
public Canvas canvas;
Rigidbody2D rb;
RectTransform rectTransform;
Vector3 previousPosition;

void Start()
{
    cam = Camera.main;
    rb = GetComponent<Rigidbody2D>();
    rectTransform = GetComponent<RectTransform>();
    previousPosition = new Vector2(260, -160);
}

void LateUpdate()
{
    // This should happen after OnEndDrag() so OnEndDrag() will use the value from the previous frame.
    previousPosition = cam.ScreenToWorldPoint(Input.mousePosition);
}

public void OnBeginDrag(PointerEventData eventData)
{
    rb.constraints = RigidbodyConstraints2D.FreezePositionX | RigidbodyConstraints2D.FreezePositionY;
    rb.gravityScale = 0.0f;
}
  
public void OnDrag(PointerEventData eventData)
{
    rectTransform.anchoredPosition += eventData.delta / canvas.scaleFactor;
}

public void OnEndDrag(PointerEventData eventData)
{
    rb.constraints = RigidbodyConstraints2D.None;
    rb.gravityScale = 100.0f;
    Vector3 position = cam.ScreenToWorldPoint(Input.mousePosition);
    rb.AddForce(new Vector2(position.x, position.y) - new Vector2(previousPosition.x, previousPosition.y) / Time.deltaTime, ForceMode2D.Impulse);
}
}

I’m not sure if Physics are supposed to be applied to stuff on the Canvas, but from a bit of experimentation it seems like it does work. However, I noticed different behavior when I set the Canvas to “Screen Space - Overlay” vs “Screen Space - Camera”. I’m not sure if this means that you’ll get different behavior depending on the resolution the game is running at.

Do you mean that not even gravity will pull it down? When I add a RigidBody2D to an Image on the Canvas, I see it drop.
If you mean that the throw force doesn’t work as expected, then I suggest that you print out the value of the Force calculated and see if it matches what you intend. It may help to just set the RigidBody2D velocity to the value you want rather than using forces.

By the way, with the way you have the parenthesis set, only the second Vector2 will be divided by Time.deltaTime. Is that what you intended?

rb.AddForce(new Vector2(position.x, position.y) - new Vector2(previousPosition.x, previousPosition.y) / Time.deltaTime

For what it’s worth, this code worked for me on a “ScreenSpace - Overlay” canvas. But I still think it would be better to do this off the Canvas if possible.

Vector2 previousPos;

public void OnDrag(PointerEventData eventData)
{
    Debug.Log("OnDrag eventData.position=" + eventData.position);
    myRect.anchoredPosition = eventData.position;
    previousPos = eventData.position;
}

public void OnEndDrag(PointerEventData eventData)
{
    Debug.Log("EndDrag eventData.position=" + eventData.position);
    Vector2 flingDirection = eventData.position - previousPos;
    flingDirection *= 10f;
    Debug.Log("flingDirection:" + flingDirection);
    GetComponent<Rigidbody2D>().velocity = flingDirection;  
}

Sometimes this could just be that case of adjusting some values, have you tried some trial and error with different values to change the force of the throwing motion?

Your code seems correct, but I may be wrong.