In this tutorial, we will implement a drag and drop item functionality in Unity. We will drag a UI item and drop it to instantiate a prefab on a 3D scene.
Contact me
Find the GitHub repository of this tutorial at https://github.com/shamim-akhtar/drag-and-drop.
Click to try the WebGL version below. NOTE: The WebGL version might not work for mobile devices.
https://faramira.com/downloads/dragdrop/WebGL/
The Unity Project
- Create a new Unity 3D project.
The Ground
- Right-click on the Hierarchy window and add a plan. Name it Ground.
- Create a folder in Assets and call it Resources. Create another folder in Resources and name it Textures. Download the checkerboard image and put it in the folder Assets/Resources/Textures. Drag and drop this image onto the ground.
- Set the Ground’s scale to be 10, 1, 10
- Double-click on the checkerboard material and open the material file. Set the tile factor to 10, 10 as shown below.
- Add a Box Collider component to the ground.
- The Ground’s Inspection should look like below.
The Dummy Prefabs
Next, we will create some dummy prefabs to initialise by dragging and dropping UI items. We will associate each UI item with one such prefab so that when we drop the UI item, we instantiate the correct prefab associated with that UI item.
For our demo, we will create a cube, a sphere and a cylinder. Go ahead and carry out the following steps.
- Right-click on the Hierarchy window and create a new empty game object. Name it ObjCube and reset the transform.
- Select ObjCube and add a cube game object as shown below.
- Create a material and name it MatCube. Set a colour to the material by selecting the Albedo, as shown below.
- Set this material to the Cube.
- Create a folder in the Resources directory; name it Prefabs. Drag and drop ObjCube to the Prefabs folder, and make it a prefab.
- Delete ObjCube from the Hierarchy.
Repeat the above steps for a Sphere and a Cylinder. You can create a different material for the Sphere and the Cylinder.
Your Prefabs folder should now have three prefabs.
- ObjCube
- ObjSphere
- ObjCylinder
The Canvas and the UI Item
Next, we create the Canvas and the UI items that we will drag.
- Right-click on the Hierarchy window and create a new Canvas. Make sure that we have the settings as shown in the diagram below.
- Select the canvas and add a new UI Panel. Name this Panel as CardsPanel. Set the CardPanel’s parameters as shown below.
- Create three subpanels within this CardPanel. Name the first sub-panel as Card1, the second as Card2 and the third as Card3.
- To each of these sub-panels, add two sprites. Name them Inner and Outer.
- Set the Outer sprite’s parameter as shown in the picture below.
- Download the icon for the cube, the icon for the sphere and the icon for the cylinder. Put these images in the Textures folder. Convert them to 2D sprite type.
- Select the Inner sprite for Card1 and then set the width and height to be 50, 50. Drag and drop icon_sphere as set as the sprite for the Inner (as shown below).
- Similarly, for Card2 Inner, set the icon_cylinder and for Card3 Inner, set icon_cube.
- Your UI should like the below picture.
- Select the Camera and set the transform values as below. These values will make the camera position and orientation a bit better for us to view the ground.
The Drag UI Item Script
So far, we have only created our scene for testing the drag and drop of UI items to instantiate prefabs on the scene. We will now begin the necessary script for our main feature.
- Go ahead and create a new C# script file named DragUIItem.
- Double-click this file and open it in Visual Studio.
- Make the following change to the class declaration.
public class DragUIItem :
MonoBehaviour,
IBeginDragHandler,
IDragHandler,
IEndDragHandler
{
}
Code language: C# (cs)
- We want to implement three interfaces for our drag and drop to work. These interfaces are IBeginDragHandler, IDragHandler, and IEndDragHandler.
- Add the following variables to the class.
[SerializeField]
GameObject PrefabToInstantiate;
[SerializeField]
RectTransform UIDragElement;
[SerializeField]
RectTransform Canvas;
private Vector2 mOriginalLocalPointerPosition;
private Vector3 mOriginalPanelLocalPosition;
private Vector2 mOriginalPosition;
Code language: C# (cs)
- Line 2 from the above code stores the reference to the prefab that we want to instantiate.
- The variable in line 4 holds the reference to the UI element that we will drag. The variable in line 6 contains the reference to the canvas.
The Start Method
In the Start method, we store the initial position of the draggable UI item.
private void Start()
{
mOriginalPosition = UIDragElement.localPosition;
}
Code language: C# (cs)
Implement Interface Functions
- Next, we implement the interface functions. These are:
OnBeginDrag
public void OnBeginDrag(PointerEventData data)
{
mOriginalPanelLocalPosition = UIDragElement.localPosition;
RectTransformUtility.ScreenPointToLocalPointInRectangle(
Canvas,
data.position,
data.pressEventCamera,
out mOriginalLocalPointerPosition);
}
Code language: C# (cs)
OnDrag
public void OnDrag(PointerEventData data)
{
Vector2 localPointerPosition;
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(
Canvas,
data.position,
data.pressEventCamera,
out localPointerPosition))
{
Vector3 offsetToOriginal =
localPointerPosition -
mOriginalLocalPointerPosition;
UIDragElement.localPosition =
mOriginalPanelLocalPosition +
offsetToOriginal;
}
}
Code language: JavaScript (javascript)
OnEndDrag
public void OnEndDrag(PointerEventData eventData)
{
StartCoroutine(
Coroutine_MoveUIElement(
UIDragElement,
mOriginalPosition,
0.5f));
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(
Input.mousePosition);
if (Physics.Raycast(ray, out hit, 1000.0f))
{
Vector3 worldPoint = hit.point;
//Debug.Log(worldPoint);
CreateObject(worldPoint);
}
}
Code language: C# (cs)
- In the above code, the highlighted section uses a coroutine to reset the draggable UI’s position back to its initial position.
public IEnumerator Coroutine_MoveUIElement(
RectTransform r,
Vector2 targetPosition,
float duration = 0.1f)
{
float elapsedTime = 0;
Vector2 startingPos = r.localPosition;
while (elapsedTime < duration)
{
r.localPosition =
Vector2.Lerp(
startingPos,
targetPosition,
(elapsedTime / duration));
elapsedTime += Time.deltaTime;
yield return new WaitForEndOfFrame();
}
r.localPosition = targetPosition;
}
Code language: C# (cs)
- Then, we do a raycast to determine where the ray intersects on the ground. If there is a hit, then we call the CreateObject method.
- Finally, the CreateObject method is as below.
public void CreateObject(Vector3 position)
{
if (PrefabToInstantiate == null)
{
Debug.Log("No prefab to instantiate");
return;
}
GameObject obj = Instantiate(
PrefabToInstantiate,
position,
Quaternion.identity);
}
Code language: C# (cs)
Attach the Script and Configure
- Go back to Unity editor and attach the DragUIItem script to each of the Inner images of Card1, Card2 and card3.
- Select Inner from Card1 and associate the serialisable fields as below.
- Similarly, do the same process for Inner from card2 and Inner from Card3 (with different prefabs).
Click Play and run the application. You should now drag the UI items onto the Ground and see the instantiated prefabs on the ground, as shown below.
Read My Other Tutorials
- Graph-Based Pathfinding Using C# in Unity
- 2D Grid-Based Pathfinding Using C# and Unity
- 8-Puzzle Problem Using A* in C# and Unity
- Create a Jigsaw Puzzle Game in Unity
- Implement a Generic Pathfinder in Unity using C#
- Create a Jigsaw Puzzle Game in Unity
- Generic Finite State Machine Using C#
- Implement Bezier Curve using C# in Unity
- Create a Jigsaw Tile from an Existing Image
- Create a Jigsaw Board from an Existing Image
- Solving 8 puzzle problem using A* star search
- A Configurable Third-Person Camera in Unity
- Player Controls With Finite State Machine Using C# in Unity
- Finite State Machine Using C# Delegates in Unity
- Enemy Behaviour With Finite State Machine Using C# Delegates in Unity
- Augmented Reality – Fire Effect using Vuforia and Unity
- Implementing a Finite State Machine Using C# in Unity
- Solving 8 puzzle problem using A* star search in C++
- What Are C# Delegates And How To Use Them
- How to Generate Mazes Using Depth-First Algorithm
A committed and optimistic professional who brings passion and enthusiasm to help motivate, guide and mentor young students into their transition to the Industry and reshape their careers for a fulfilling future. The past is something that you cannot undo. The future is something that you can build.
I enjoy coding, developing games and writing tutorials. Visit my GitHub to see the projects I am working on right now.
Educator | Developer | Mentor