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);
}
}
2 Answers
2
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.
Might be worth checking out this thread on the forums too: https://forum.unity.com/threads/how-do-i-make-a-drag-script-with-physics.1560507/
– dstearsThanks, this worked! I did need to edit this a bit (specifically, replace all instances of = eventData.position with += eventData.delta / canvas.scaleFactor, eventData.position just caused the object to constantly launch 60° up-right) but it worked just fine otherwise. One thing I found was that when calculating flingDirection, I needed to add previousPos at the start, but since you had subtracted previousPos at the end, those two operations cancelled out, leaving previousPos unnecessary.
– a1a1a1a1a1a1a1a