Add force based on drag speed

Hey everyone, I’m wondering how you can add force to a kinematic object based on the drag speed. Say the user is dragging a cube, and it’s going to hit another cube. The faster of his dragging speed, the more force will push to another cube.

Thanks!

Steven

It’s not ideal, but this works. It will let you throw the object left/right/up/down in relation to the camera. Made for an FPS style view.

Camera theCam = GameObject.FindGameObjectWithTag("MainCamera").camera;

rigidbody.AddForce(theCam.transform.right * Input.GetAxis("Mouse X") * 10f, ForceMode.Impulse);
rigidbody.AddForce(theCam.transform.up * Input.GetAxis("Mouse Y") * 10f, ForceMode.Impulse);

Add inside an OnMouseUp function after dragging, or similar.

rigidbody.isKinematic should ideally be false when dragging, then make it true before this code.

Here’s a rough ready to use script:

using UnityEngine;
using System.Collections;

public class DragDrop : MonoBehaviour {
	
	private Camera theCam;
	private bool dragging;
	
	void Start ()
	{
		theCam = GameObject.FindGameObjectWithTag("MainCamera").camera;
	}
	
	void LateUpdate ()
	{
		// This draws a line (ray) from the camera at a distance of 3
		// If it hits something, it moves the object to that point, if not, it moves it to the end of the ray (3 units out)
		if (dragging)
		{
			Ray ray = theCam.ScreenPointToRay(Input.mousePosition);

			RaycastHit hit;

			if (Physics.Raycast(ray, out hit, 3f))
			{
				transform.position = hit.point;
			}
			else
			{
				transform.position = ray.GetPoint(3f);
			}
		}
	}
	
	void OnMouseDown()
	{
		dragging = true;
		rigidbody.isKinematic = true;
		collider.enabled = false;
	}
	
	// Adds the force when you let go based on the Mouse X/Y values.
	void OnMouseUp()
	{
		dragging = false;
		rigidbody.isKinematic = false;
		collider.enabled = true;
		
		rigidbody.AddForce(theCam.transform.right * Input.GetAxis("Mouse X") * 10f, ForceMode.Impulse);
    	rigidbody.AddForce(theCam.transform.up * Input.GetAxis("Mouse Y") * 10f, ForceMode.Impulse);
	}
	
}

To make it work without disabling the collider, you can use a LayerMask on the Raycast, or put the object onto the IgnoreRaycast layer.

You don’t need to add the force yourself, the physic engine can take care of it. But of it to work, the cubes you’re not dragging mustn’t be kinematic, so I suggest you do the switch on mouse down. Also, as a mouse move can be pretty fast, use continuous dynamic collision detection on the dragged cube, and continuous on the others, so it won’t just pass through.

If you really want to stick with all-kinematics, you can simulate a force by moving the object by a fading vector ( pos += forward * 5, *4, *3, *2.5 … ), the vector being, on collision, pos - collider.pos. I doubt that it will be realistic though …

Hey Berenger,

Thanks for your reply.

I tried the code below:

if (theTouch.phase == TouchPhase.Ended || theTouch.phase == TouchPhase.Canceled) {
  rigidbody.isKinematic = true;
  return;
} else {
  rigidbody.isKinematic = false;
  var p:Vector3 = Camera.main.ScreenToWorldPoint(
   new Vector3 (theTouch.position.x, theTouch.position.y, 300));
  transform.position = p;
}

It looks like the dragging cube can pass through other objects. I’m using continuous dynamic collision detection.

Thanks!

Steven

Did you find an answer yet? I’m looking for kinda the same solution. I got a sphere in 2D(x,y), and I’m controling it by touch. When I stop my drag on the sphere, I want it to continue in the angle and speed it had, at the point of release. Furthermore it should maintain a realistic speed/velocity, and eventually stop.

So if you found a solution, please share it :slight_smile: