A downloadable asset pack

Download NowName your own price

Simple Drag & Drop Asset

A simple but powerful base for implementing simple UI draggable objects & drop areas in your Unity games. (Small note: This has nothing to do with the "Drag & Drop" of external files into your Unity game window. In this aspect the asset name may be a bit misleading... )

HOW TO INSTALL IT:

For Unity 2020.1 and above (Should work with Unity 2019 versions too, but i haven't tested it, so idk)

  • Download the "single-drag-and-drop-asset.zip" file
  • Unzip the file in your desktop (or anywhere you want, just not inside your Unity project folder)
  • Open your Unity desired project, and open the "Window/Package Manager"
  • On the top left you should see a "+" icon, click it and select "Add package from disk"
  • Search the folder you've extracted before, open it, select the "package.json" file, and confirm
  • Unity now should import the asset files inside your project
  • Done!! You're ready to use the Simple Drag and Drop asset pack

NOW... NOW WHAT??

You've successfully imported the package in your Unity project, now how do you use it?? You may think:

The only thing i see changed from when i've imported the package are the "Drag Canvas Preloader", the "Drop Position Processor - Simple" and the "Snap Back Object" component. How do i make a draggable object?? This is very confusing, and not simple at all!!

And i hear you, User across the internet. That's why i choose to explain, step-by-step how this asset works, and more importantly, how to use it yourself. But first...

WAIT!! I don't want to real ALL that!!

Don't worry, it's not like you have to read it all at the same time. You don't even have to if you don't want to. Feel free to swing back by if you need any help with anything.

Also the code should be well documented (or at least, I've tried my best to) in case you want to take a peak and learn like that.

Code?? Eww...

Well... I don't know what to respond to that... This is just a base for implementing your very own drag & drop system, so you'll have to dip your hands into some code a bit. If programming isn't your thing, don't be afraid: I'll guide you step-by-step into creating your draggable objects. And i will even respond your question if needed in the comment section. 

Still, if coding totally disgusts you, and don't even want to touch the code editor, then I'm afraid this asset isn't for you :/

WHAT ABOUT THE ASSET'S LICENSING??

CC0

Yep, you've heard me right. CC0. You can use this asset however you like (this means even editing it if you want), in whatever project you like, whenever it's commercial or not, and you don't even have to credit me.

Although, please do credit me it anyway, and share whatever project you'll end up using this asset on. I'm super curios about it, and it's greatly appreciated it.

But why you're giving away your hard away away like that?? Aren't you worried someone might steal your code and sell it without giving you a cent??

Not at all... Well, that's not entirely true, I am a bit worried about some things, to be honest...

...But i figured that this is stuff that anyone can code it in a few days if really wanted to do that, so that's really not a problem. Plus my code is not even that great, i'm sure there's a lot of room for improvement i am not aware of at the moment.

I did even considered to selling myself for a few cents (something around 0.99€ or something), but turned against it because nobody would actually have bough it, and few ones that did they probably  would end up be disappointed. So i prefer it like this. It's a win-win for everybody, really.

THE BASIC STUFF

HOW IS THIS ASSET STRUCTURED?? HOW DOES IT WORK??

This asset is subdivided in 3 sections, also know them as namespaces:

  • Marxy37.SimpleDragAndDrop: This namespace includes the core basic for drag & drop objects, as well as the ever useful UIMonoBehaviour class (Monobehaviour with a rectTransform component).
  • Marxy37.SimpleDragAndDrop.Extra: This includes some extra stuff outside of the core classes: draggable objects for inventory, button conversions, snappable game objects, and more.
  • Marxy37.SimpleDragAndDrop.Editor: This is just if you're feeling fancy and want to add your custom scripts to the existing Drag & Drop editor

To use the functionality of the classes inside one of the namespaces in your custom c# class just add this line on the very top of your code:

using [namespace_name];

[ ! ] One small thing i should probably point out before you start using this asset is that the draggable objects only work with Screen Space - Overlay Canvas. With every other types of canvas (Screen Space - Camera, World Space, or even scaled down/up canvases inside another Canvas) the draggable functionality doesn't work as intended. I've tried to make it work with other types of canvases, but couldn't. [ ! ]

[ ! ] Also, I worn't be saying this troughout all this text (mostrly because i forgot, and this is an edit), but when dealing with already exisiting Unity methods, like Awake(), OnValidate(), etc. DO NOT hide them with the keyword "new" (otherwise you might break something). Instead, override them, and always remember to call the base function (again, because you might break something otherwise) [ ! ]

UI-MONOBEHAVIOUR: THE COMPONENT UNITY SHOULD IMPLEMENT IN BY DEFAULT

Most of the time, when implementing a Unity Monobehaviour for an object that goes inside a Canvas, the first lines of code you're going to write look something like this:

// Naming convenction may vary, obviously
private RectTransform _rectTransform;
⠀
private void Awake()
{
    _rectTransform = GetComponent<RectTransform>();
    // Rest of your Awake func.
}

So, i've implemented it so it does it by default, with UIMonoBehaviour. Easy and Simple as that. It even follows the Unity shitty coding and naming conventions standards.

And you can still use your Awake() function however you like, without having to override it.

CREATION OF A DRAGGABLE OBJECT

Why do I need to make my custom C# classes? Why the functionality of drag & drop isn't implimented by default?

Well, the answer basically boils down to: Customization. Because you might want different types of draggable objects, each with different behaviors and cases, and because I'm not a wizard, I can't predict it all. And because most of the time you don't want them to interact with each other i couldn't make an unified object with events/UnityEvents or something. If that's the behavior you're looking for tho, it is easily feasible with just a few lines of code.

Well, now let's get started on creating our first draggable object. First of all let's start by creating a C# Script. This will be your draggable object. You won't believe it but it's as simple as deriving from the DragObject class, like this:

using namespace Marxy37.SimpleDragAndDrop;
⠀
public class MyDraggableObject : DragObject
{
    // Your code here. Beware of the empty char between using and class
}

Now, if you go in your Canvas, create an empty GameObject, assign your class as a component and start play mode, you'll see that you have a draggable object in the scene

What can i do with it?? What can i customize it about it??

The draggable functionality can be activated/deactivated with IsActive (bool) without activating/deactivating the whole component/gameObject. You can add custom functionality to it with OnSetActiveAction(...).

You can check if an object is currently dragged with IsDragged (bool). If you need to cancel a drag while it's happening you can do that with CancelDrag().

You can add custom functionality on the beginning, during and on the end of the user drag overriding from OnBeginDragAction(...), OnDragAction(...) and OnEndDragAction(...). 

And finally, you can customize how the movement between the original parent canvas and the drag canvas is handled with StoreOriginalTransformInfo(...), ParentToDragCanvas(...) and ResetToOriginalPosition(...). This is stuff for advanced programmers only, and i suggest you to leave it as is, unless you really need to change it.

In the editor, you can also customize with what button (mouse button only) you can drag the object and if the object should be centered to the cursor at the beginning of the drag.

AND NOW, A PLACE WHERE TO DROP IT

Now that you have draggable objects, you probably want a place where to drop them: Introducting DropObject(s).

First of all, we need to declare the group of draggable object we want to accept. If you want to accept only one type of draggable object you can skip this step.

Can you give me an example?? I can't think of a single scenario where i could want to drop 2 different types of draggable objects inside the same slot

Sure: Let's say you have a draggable Rock object, a draggable Hay object and a draggable Stick object. Now you have 4 drop areas, one is a stone storage, that accepts one stone objects (the rock is made of stone), one is a grass storage, that accepts only grass-like objects (the hay is a grass-like object), and one is a wood storage, that accept only wood objects (the stick is made of wood). The fourth is a bit more complex: It's a crafting table that accepts both wood and rock objects, but not grass like objects. In this case we put both wood and rock objects (but not grass-like objects) inside a group, let's call it IDroppablePrimitiveCrafting, and tell the crafting table to accept only object with the group IDroppablePrimitiveCrafting.

You create a group, by creating a c# Script and writing this:

using namespace Marxy37.SimpleDragAndDrop;
⠀
// Note that this is NOT a MonoBehaviour, aka. a Unity script
public interface IMyDroppableGroup : IDroppable
{
    // Beware of the empty char between using and class.
    // If you want some custom functionality, this
    // is where you would declare it
}

and to add your custom draggable class into a droppable group, is as simple as doing this:

public class MyDraggableObject : DragObject, IMyDroppableGroup, IMyOtherDroppableGroup
This is very tideous to do: If i want to add another crafting table, I need to go through all my objects and update them. There really wasn't any better solution for this?

I know, but it's the only solution i could come up with sadly. If I ever find a better solution i'll consider  updating the asset.

Now, let's create the drop area object. Again, you won't believe it but it's as simple as deriving from the DropObject class, like this:

using namespace Marxy37.SimpleDragAndDrop;
⠀
public class MyDropArea: DropObject<IMyDroppableGroup>
{
    protected override void OnDropAction(IMyDroppableGroup objectDropped, DragInputButton button, Vector2 dropPos)
    {
        // Your code here. Beware of the empty char between using and class
    }
}

If you see that your compiler is giving you error, that's because you haven't override the OnDropAction(...) function. This is where you tell the game what to do when a valid droppable object is dropped inside the drop area.

Can one drop area support multiple droppable group types?

No. Only one.

I don't want to make a group, my drop area will only accept one type of object. How can i do that??

Well, it's as simple as writing the name of your droppable object class where the group object name normally goes, something like this:

public class MyDropArea: DropObject<MyDraggableObject>

You can also drop valid object from code (useful when implementing shortcut keys or virtual cursors) with Drop(...) and passing the object you want to drop inside the drop area.

DROP POSITION PROCESSOR: WHAT IT IS AND HOW DOES IT WORK??

You'll see that when you create a GameObject with your custom drop area component there is an empty field for a DropPositionProcessor. You'll also see that inside OnDropAction(...) there is a Vector2 param for the drop position. Normally, if you leave that field empty it's just going to return the raw pointer position (aka mouse position), but you can write custom processor assets, if you need custom position conversion or some other kind of position processing.

The asset provides a default position processor, that converts the position in a way where the bottom left corner returns Vector2.zero, and the top right corner returns Vector2.one.

Still, in case you want to create a custom one, create a C# Script, derive it from DropPositionProcessor and override the ProcessPosition(...) function. Something like this

using namespace Marxy37.SimpleDragAndDrop;
⠀
public class MyDropPositionProcessor: DropPositionProcessor
{
     public override Vector2 ProcessPosition(Vector2 posToProcess, RectTransform dropAreaRT,
        Canvas parentCanvas, RectTransform parentCanvasRT, bool dropFromCode)
     {
         // Your code here. Beware of the empty char between using and class
     } 
}
Wait... How do i assign it to the draggable object?? I have no way to do that...

You're right, i totally forgot!! You've create your own custom position processor, but if you leave it as it is right now, you have no way to create it. Above your class name add this line:

[CreateAssetMenu(menuName = StandardAssetMenuName + "Custom Name", order = StandardAssetOrder)]

Now, if you right click in the asset folder and go in the "Drag And Drop" section, you should now see that you can create "Position Processor - Custom Name".

Also, note that the DropPositionProcessor support can be called one inside another, like this:

[SerializeField]
private SimpleDropPositionProcessor _simpleProcessor;
⠀
public override Vector2 ProcessPosition(Vector2 posToProcess, RectTransform dropAreaRT, Canvas parentCanvas,
    RectTransform parentCanvasRT, bool dropFromCode)
{
    // Beware of the empty char between serialized field and function
    return _simpleProcessor.ProcessPosition(posToProcess, dropAreaRT, parentCanvas, parentCanvas, parentCanvasRT, dropFromCode) * -1;
}

... And that's all the core functionality of this asset!! I know that was a lot to uncover, but we're still half way there, we still need to cover the extra functionality and the editor extension. Let's start with...

THE EDITOR: LET'S GET FANCY AND LET'S ADD YOUR CUSTOM CLASS INTO THE DRAG AND DROP SECTION

Alright, so you want to add your custom classes with all the other component, or maybe you want the ability to create a gameObject with a simple right click. That should be easy enough with the MenuItemHelper. Let's import it inside the classes that you want to implement into the editor

using static namespace Marxy37.SimpleDragAndDrop.Editor.MenuItemHelper;
Wait... Why static?? What does it do there??

A static import is a comodity. It makes so that we basically don't have to write the static imported class behind varialbles or functions of that specific class, like they were stuff inhereted from a base class. And since the names are quite long and we're going to use it a lot, It makes the code a bit more bearable to the eye, in my opinion. But feel free to use the non-static way if you prefer.

Well now, Let's open the object you want to show in the editor (let's go with MyDraggableObject just for the sake of example):

For adding the object in the Component section, just write this line above the class name:

[AddComponentMenu(StandardDDComponentMenuName + "My Draggable Object")]

[ ! ] Note that if we didn't imported MenuItemHelper as static, we would have needed to write MenuItemHelper.StandardDDComponentMenuName instead [ ! ]

And, just like that, the component should appear in the "Drag And Drop" section

If we want to add it in the GameObject section instead, it's a bit more complex than that: we need to make a (private, so only Unity can see it) static function that creates said GameObject when invoked. Nothing we can't handle fortunatelly, and with the use of MenuItemHelper, it's easier than ever:

...Aaand, it's not limited to just creating GameObjects: If you really want it, it can also do, well, anything you want really... Go nuts with it!!

using UnityEditor;
⠀
[MenuItem(StandardDDIteMenumName + "My Draggable Object", priority = StandardDDItemPriority)]
private static void EditorCreateDragCanvasPreloaderGameObject()
{
    // Your Code
    _ = CreateGameObjectWithComponent<MyDraggableObject>("My Draggable Object");
    // Your Other Code
}

[ ! ] Note that if we didn't imported MenuItemHelper as static, we would have needed to write MenuItemHelper.StandardDDIteMenumNameMenuItemHelper.StandardDDItemPriority and MenuItemHelper.CreateGameObjectWithComponent<T>(...) instead. Now you see why i like for MenuItemHelper to be static. [ ! ]

Now, when we right click into the hiearchy to create a GameObject, if we click into the "Drag And Drop" section we should see that you can create "MyDraggableObject". Let's test it... And (hopefully) it works!!

But i don't want to add UnityEditor inside of my script class, i want to keep everything tidy and clean

I'm pretty sure you can write everything in a separate script file and i would still work the same. Though, for the sake of simplicity and explanation, i'm writing everything in the same script file

But how do i add custom functionality to the Inspector view??

Well, for that you'll need to make your own custom editor. And that's something  outside of my scripts scopeand/or functionality. I personally reccomend this great tutorial if you want to do just that.

NOW... FOR THE EXTRA STUFF!!

Small premise: I will NOT go as in depth as the other two, because this text is already too long to read (and there isn't much to talk about it anyway). Well, let's get started!!

SNAPBACK OBJECT / I-SNAPPABLE

This is my own implementation for game object (Not limited to UI object, unlike the other stuff) that should snap back into position. 

[ ! ] Don't get confused: SnapbackObject is the position where the object will snap back to, NOT the object that will snap back into position. (Yeah, i could have done a better job naming those two, i know. My mistake) [ ! ]

DRAG CANVAS PRELOADER

If you don't preload the drag canvas, sometimes, some funny stuff can happen because the drag canvas isn't properly set. Like, your UI object could shrink/expand, or even worst, outright disappear from the visible screen. That's why i've implemented a component that let's you preload it, without having to do it yourself.

INPUT CONVERSION

You need to convert the input button to string, or in a Unity readable format?? I've got you covered with the DragInputButtonConversionExtensions class!!

"INVENTORY" DRAGGABLE OBJECTS / GROUPS / DROP AREAS

Basically they're just like their normal counterpart, but they snap back into position when released and changes slot when dropped into an empty slot. (Both handled by the drop area). Previously said stuff still applies to this objects.

[ ! ] Alway, and i mean ALWAYS, make sure that every inventory object is inside of a inventory slot BEFORE starting the game. If you want an object that dosen't changes slot, but still snaps back into position, use an empty SnapBack object instead [ ! ]

Some of the new stuff that it's worth noting is:

  • [DragInventoryObject] CurrentSlot/CurrentSnapBackPosition: The slot/snapBack position where the draggable object is inside of.
  • [DragInventoryObject] StoreStartingSnapBackPositionTransformInfo(...): Finds the slot the item is inside of when it Start() runs. Can be overridden with custom behaviour
  • [DragInventoryObject] OnSlotChangedAction(...): Custom behaviour when changing slot
  • [DragInventoryObject] ChangeSlot(...): Changes the current slot. Can be overridden with custom behaviour
  • [DragInventoryObject] CurrentlyHoldedObject: The inventory object the slot is currently holding.
  • [DropInventoryObject] HoldDroppedObject(...): When a valid inventory object is dropped, this function gets called and, it isn't already holding an object, changes his slot to itself (aka. the drop area where it was dropped into). Both HoldDroppedObject(...) and the original OnDropAction(...) can be overridden with custom behaviour
  • [DropInventoryObject] SnapCurrentlyHoldedObjectInPlace(...): Snaps the object the slot is holding back into his original position. Can be overridden with custom behaviour

WOW... THAT WAS A LOT OF TEXT!!

It was indeed!! And i believe that's everything I could talk about. Well, maybe i could have gone a bit in depth with the "inventory" Drag & Drop system, but i really didn't want to drag on this long wall of text any further. So, th...

Wait... Where have you've been all this time?? Your last project was on December 2021. That was 7 months ago!! Are you planning to get back into game development??

Says no one ever, lol. Well, i wanted to insert this bit of an update, even if probably no one is gonna care about it. Or at least that's what i think, but who knows?? I might be wrong, life is full of surprises, after all... 

I am still very much into game development as I ever was, and don't play any time soon to leave it. I've got a bit lost tough: I choose to wanting to became a game developer when i was at a young age, probably because i liked games and wanted to create something I've enjoyed consuming, so I've devoted all my life into it, and by the time I've reached my goal i kinda... Lost my purpose?? Got burnout?? Been stuck to the past?? Idk how to describe it, it's a weird feeling.

Plus me working on two long-term projects dosen't help at all, and i have to admit, the lack of visible goals (and a bunch of negative stuff in my life, like struggling with finding job) made me a bit depressed, not going to lie. I know, i know, my gamedev journey is still young, and i've still got a lot to learn. This however dosen't make my feeling any better honestly. Anyway, enough about me....

We're finally come to the conlusion text. Did you read all of it?? I don't mind if you did, that is a lot to ask, honestly (If you did tho, your're a serious madlad, let me tell you!!). Anyway... Best regards, and:

THANK YOU!! For choosing to give a look at my asset!!

Download

Download NowName your own price

Click download now to get access to the following files:

simple-drag-and-drop-asset.zip 34 kB

Leave a comment

Log in with itch.io to leave a comment.