Skip to content

Instantly share code, notes, and snippets.

@wakeup5
Created November 10, 2020 15:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wakeup5/c929daa1ffd517c3d9dbeb642daf329b to your computer and use it in GitHub Desktop.
Save wakeup5/c929daa1ffd517c3d9dbeb642daf329b to your computer and use it in GitHub Desktop.
Unity UGUI Drag and Drop
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UniRx;
using UnityEngine;
using UnityEngine.EventSystems;
namespace Waker.UI.DragAndDrop
{
public class DragAndDropManager : MonoBehaviour
{
[SerializeField] private GameObject dragObject;
[SerializeField] private Vector2 dragOffset;
[SerializeField] private Canvas canvas;
private DragAndDropSlot pressedDragSlot;
private RectTransform rectTransform;
private RectTransform dragObjectTransform;
private Camera canvasCamera;
private Subject<DragEvent> onBeginDrag = new Subject<DragEvent>();
private Subject<DropEvent> onDrop = new Subject<DropEvent>();
private Subject<DragEvent> onEndDragWithoutDrop = new Subject<DragEvent>();
public IObservable<DragEvent> BeginDragAsObservable() => onBeginDrag;
public IObservable<DropEvent> DropAsObservable() => onDrop;
public IObservable<DragEvent> EndDragWithoutDropAsObservable() => onEndDragWithoutDrop;
private void Awake()
{
// Set variables
rectTransform = transform as RectTransform;
dragObject.SetActive(false);
dragObject.transform.SetParent(transform);
dragObjectTransform = dragObject.transform as RectTransform;
canvasCamera = canvas.worldCamera;
if (canvasCamera == null)
{
canvasCamera = Camera.main;
}
}
internal void OnBeginDrag(DragAndDropSlot slot, PointerEventData eventData)
{
pressedDragSlot = slot;
dragObject.SetActive(true);
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(
rectTransform,
eventData.position,
canvasCamera,
out var localPoint))
{
dragObjectTransform.anchoredPosition = localPoint + dragOffset;
}
DragEvent dragEvent = new DragEvent(this, pressedDragSlot, dragObject);
onBeginDrag.OnNext(dragEvent);
ExecuteEvents.Execute<IDragAndDropHandler>(pressedDragSlot.gameObject, null, (o, a) => o.OnBeginDrag(dragEvent));
}
internal void OnDrag(DragAndDropSlot slot, PointerEventData eventData)
{
if (pressedDragSlot == null)
{
return;
}
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(
rectTransform,
eventData.position,
canvasCamera,
out var localPoint))
{
dragObjectTransform.anchoredPosition = localPoint + dragOffset;
}
}
internal void OnEndDrag(DragAndDropSlot slot, PointerEventData eventData)
{
if (pressedDragSlot == null)
{
return;
}
DragEvent dragEvent = new DragEvent(this, pressedDragSlot, dragObject);
onEndDragWithoutDrop.OnNext(dragEvent);
ExecuteEvents.Execute<IDragAndDropHandler>(pressedDragSlot.gameObject, null, (o, a) => o.OnEndDragWithoutDrop(dragEvent));
pressedDragSlot = null;
dragObject.SetActive(false);
}
internal void OnDrop(DragAndDropSlot slot, PointerEventData eventData)
{
if (pressedDragSlot == null)
{
return;
}
DropEvent dropEvent = new DropEvent(this, pressedDragSlot, slot, dragObject);
onDrop.OnNext(dropEvent);
ExecuteEvents.Execute<IDragAndDropHandler>(pressedDragSlot.gameObject, null, (o, a) => o.OnDrop(dropEvent));
ExecuteEvents.Execute<IDragAndDropHandler>(slot.gameObject, null, (o, a) => o.OnDrop(dropEvent));
pressedDragSlot = null;
dragObject.SetActive(false);
}
public void StopDrag()
{
DragEvent dragEvent = new DragEvent(this, pressedDragSlot, dragObject);
onEndDragWithoutDrop.OnNext(dragEvent);
ExecuteEvents.Execute<IDragAndDropHandler>(pressedDragSlot.gameObject, null, (o, a) => o.OnEndDragWithoutDrop(dragEvent));
pressedDragSlot = null;
dragObject.SetActive(false);
}
}
public struct DropEvent
{
public DragAndDropSlot dragSlot;
public DragAndDropSlot dropSlot;
public GameObject dragObject;
public DropEvent(DragAndDropManager manager, DragAndDropSlot dragSlot, DragAndDropSlot dropSlot, GameObject dragObject)
{
this.dragSlot = dragSlot;
this.dropSlot = dropSlot;
this.dragObject = dragObject;
}
}
public struct DragEvent
{
private DragAndDropManager manager;
public DragAndDropSlot dragSlot;
public GameObject dragObject;
public DragEvent(DragAndDropManager manager, DragAndDropSlot dragSlot, GameObject dragObject)
{
this.manager = manager;
this.dragSlot = dragSlot;
this.dragObject = dragObject;
}
public void StopDrag()
{
manager.StopDrag();
}
}
}
using System;
using UniRx;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace Waker.UI.DragAndDrop
{
public class DragAndDropSlot : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler, IDropHandler, IInitializePotentialDragHandler//, IPointerDownHandler, IPointerClickHandler
{
[SerializeField] private bool activeScrolling = false;
private ScrollRect scrollRect;
private Button button;
private bool isScroll = false;
private DragAndDropManager manager;
private void OnEnable()
{
scrollRect = GetComponentInParent<ScrollRect>();
button = GetComponent<Button>();
manager = GetComponentInParent<DragAndDropManager>();
}
public void OnBeginDrag(PointerEventData eventData)
{
if (button) button.interactable = false;
if (activeScrolling && WhetherScrolling(scrollRect, eventData.delta))
{
scrollRect.OnBeginDrag(eventData);
isScroll = true;
return;
}
if (manager) manager.OnBeginDrag(this, eventData);
}
public void OnDrag(PointerEventData eventData)
{
if (activeScrolling && scrollRect && isScroll)
{
scrollRect.OnDrag(eventData);
return;
}
if (manager) manager.OnDrag(this, eventData);
}
public void OnEndDrag(PointerEventData eventData)
{
if (button) button.interactable = true;
if (activeScrolling && scrollRect && isScroll)
{
scrollRect.OnEndDrag(eventData);
isScroll = false;
return;
}
if (manager)
{
if (eventData.pointerCurrentRaycast.gameObject?.GetComponentInParent<DragAndDropSlot>() == this)
{
OnDrop(eventData);
return;
}
manager.OnEndDrag(this, eventData);
}
}
public void OnDrop(PointerEventData eventData)
{
if (manager) manager.OnDrop(this, eventData);
}
public void OnInitializePotentialDrag(PointerEventData eventData)
{
if (scrollRect) scrollRect.OnInitializePotentialDrag(eventData);
}
public void StopDrag()
{
if (manager) manager.StopDrag();
}
private static bool WhetherScrolling(ScrollRect scroll, Vector2 delta)
{
if (!scroll)
{
return false;
}
if (scroll.horizontal && scroll.vertical)
{
return true;
}
if (scroll.horizontal && Mathf.Abs(delta.x) > Mathf.Abs(delta.y))
{
return true;
}
if (scroll.vertical && Mathf.Abs(delta.x) < Mathf.Abs(delta.y))
{
return true;
}
return false;
}
}
}
using UnityEngine.EventSystems;
namespace Waker.UI.DragAndDrop
{
public interface IDragAndDropHandler : IEventSystemHandler
{
void OnBeginDrag(DragEvent e);
void OnEndDragWithoutDrop(DragEvent e);
void OnDrop(DropEvent e);
}
}
#region 드래그 앤 드랍 이벤트
public void OnBeginDrag(DragEvent e)
{
if (!item.Opened || !(item is IArmsItem arms))
{
e.StopDrag();
return;
}
var itemInfo = e.dragObject.GetComponent<ItemInfo>();
itemInfo.SetItemData(arms.ItemData);
itemInfo.SetItemLevel(arms.Level);
itemInfo.SetItemStar(arms.Star);
}
public void OnEndDragWithoutDrop(DragEvent e)
{
// Do nothing...
}
public void OnDrop(DropEvent e)
{
var equipSlot = e.dropSlot.GetComponent<UIEquipSlot>();
if (equipSlot &&
item is IArmsItem arms)
{
equipSlot.Equip(arms);
}
}
#endregion
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment