Implementations

Drag and Drop Using an Arrow in Unity

Since Chambergon Battle Logic (CBL) is a card game — and players often need to actually put together the contents of a card — we need to be able to drag and drop stuff.

Here’s how I am currently implementing drag-and-drop functionality in the early stages of remaking CBL in Unity.

Instead of moving the object as it is dragged, I draw an arrow from the point of the initial click to the current mouse position. For the arrow, I have adapted ShawnFeatherly’s approach from Unity Answers¬†as follows:

//This doesn’t need to be public, but it helps when you’re initially trying to find the right size
public float arrowheadSize;
Vector3 startPosition, mouseWorld;
GameObject arrow;
LineRenderer arrowLine;

void Start(){

arrow = GameObject.FindGameObjectWithTag(“Arrow”);
arrowLine = arrow.GetComponentInChildren<LineRenderer> ();
mouseWorld = new Vector3 ();
arrowheadSize = 0.02f;

}

void OnMouseDown(){

mouseWorld = Camera.main.ScreenToWorldPoint (

new Vector3 (Input.mousePosition.x,
Input.mousePosition.y,
Camera.main.nearClipPlane
));

startPosition = mouseWorld;

}

void OnMouseDrag(){

//Turn on the arrow
arrowLine.enabled = true;
DrawArrow ();

}

void DrawArrow(){

mouseWorld = Camera.main.ScreenToWorldPoint (

new Vector3 (Input.mousePosition.x,
Input.mousePosition.y,
Camera.main.nearClipPlane
));

//The longer the line gets, the smaller relative to the entire line the arrowhead should be
float percentSize = (float) (arrowheadSize / Vector3.Distance (startPosition, mouseWorld));
//h/t ShawnFeatherly (http://answers.unity.com/answers/1330338/view.html)
arrowLine.SetPosition (0, startPosition);
arrowLine.SetPosition (1, Vector3.Lerp(startPosition, mouseWorld, 0.999f – percentSize));
arrowLine.SetPosition (2, Vector3.Lerp (startPosition, mouseWorld, 1 – percentSize));
arrowLine.SetPosition (3, mouseWorld);
arrowLine.widthCurve = new AnimationCurve (

new Keyframe (0, 0.4f),
new Keyframe (0.999f – percentSize, 0.4f),
new Keyframe (1 – percentSize, 1f),
new Keyframe (1 – percentSize, 1f),
new Keyframe (1, 0f));

}

void OnMouseUp(){

//Turn off the arrow
arrowLine.enabled = false;
RaycastHit hit;
Physics.Raycast(Camera.main.ScreenPointToRay (Input.mousePosition), out hit, 100);
transform.position = new Vector3(hit.point.x, transform.position.y, hit.point.z);

}

A few things to note:

OnMouseDown(), OnMouseUp(), and OnMouseDrag() only seem to be called for objects that have RigidBodies and colliders.

Second, the code above only works if you have some sort of backdrop collider (attached to the plane or ground on which you are moving objects around).

Third, since this is in 3D, it only works if the objects being dragged around are relatively close (on the “depth” axis) to the backdrop collider. Otherwise, perspective issues will arise such that the point of the arrow won’t be anywhere near where the object ends up.

Fourth, the code for the arrow changes the percentage of the total line devoted to the arrowhead based on how long the line is and an arbitrary length you decide on. If you don’t include that correction, the arrowhead will stretch as the line lengthens.

 

Micah has a B.A. in computer science and a Ph.D. in philosophy. He taught for almost a decade at the college level, and now teaches high school philosophy of science.

Leave a Reply

Your email address will not be published. Required fields are marked *