Частая причина такого «залипания» — неправильная обработка начала/конца перетаскивания (IBeginDrag/IDrag/IEndDrag) и/или то, что карточка продолжает блокировать raycast'ы во время/после перетаскивания, поэтому зона сброса не получает события и проверка попадания не срабатывает. Ещё может быть, что OnEndDrag не вызывается (например, если курсор вышел за окно) и возврат в руку выполняется только при каком‑то другом действии.
Рекомендации и рабочий шаблон решения:
- Сохраняйте оригинальный parent, позицию и индекс в иерархии при начале перетаскивания.
- Переносите карточку во внешний Canvas (или в корень канвы) чтобы позиционирование было корректным поверх UI.
- Во время перетаскивания у CanvasGroup выставляйте blocksRaycasts = false, чтобы нижележащие зоны могли получать события. В OnEndDrag возвращайте blocksRaycasts = true.
- В OnEndDrag делайте raycast по eventData (GraphicRaycaster) и проверяйте, есть ли под курсором валидная drop‑зона; если нет — возвращайте карточку в сохранённое положение/parent.
- На крайний случай (если OnEndDrag не вызывается) можно в Update отслеживать Input.GetMouseButtonUp и завершать перетаскивание вручную.
Пример реализации (упражнение с UI, Canvas и EventSystem):
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using System.Collections.Generic;
public class CardDrag : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
private Transform originalParent;
private int originalSibling;
private Vector3 originalLocalPos;
private Canvas rootCanvas;
private CanvasGroup canvasGroup;
private GraphicRaycaster raycaster;
private void Awake()
{
canvasGroup = GetComponent<CanvasGroup>();
rootCanvas = GetComponentInParent<Canvas>();
if (rootCanvas != null) raycaster = rootCanvas.GetComponent<GraphicRaycaster>();
}
public void OnBeginDrag(PointerEventData eventData)
{
originalParent = transform.parent;
originalSibling = transform.GetSiblingIndex();
originalLocalPos = transform.localPosition;
// Поднять карточку выше всех (чтобы видеть поверх)
transform.SetParent(rootCanvas.transform, true);
if (canvasGroup != null) canvasGroup.blocksRaycasts = false;
}
public void OnDrag(PointerEventData eventData)
{
// Простая позиция по курсору. Для Canvas в режиме Screen Space - Overlay достаточно eventData.position
transform.position = eventData.position;
}
public void OnEndDrag(PointerEventData eventData)
{
if (canvasGroup != null) canvasGroup.blocksRaycasts = true;
// Проверим, попали ли на drop-зону
if (raycaster != null)
{
List<RaycastResult> results = new List<RaycastResult>();
raycaster.Raycast(eventData, results);
foreach (var r in results)
{
// Предположим, у зоны есть компонент DropZone (или реализован IDropHandler)
var dz = r.gameObject.GetComponent<DropZone>();
if (dz != null)
{
dz.Accept(this.gameObject); // ваша логика принятия
return;
}
}
}
// Если не попали — вернуть в руку
transform.SetParent(originalParent, true);
transform.SetSiblingIndex(originalSibling);
transform.localPosition = originalLocalPos;
}
}
И пример простого DropZone:
public class DropZone : MonoBehaviour
{
public void Accept(GameObject card)
{
card.transform.SetParent(this.transform, false);
card.transform.localPosition = Vector3.zero;
// дополнительная логика принятия карты...
}
}
Проверьте также:
- На Canvas должен быть GraphicRaycaster.
- У карточки/элементов UI установлен CanvasGroup (или добавьте его).
- У объектов UI, через которые вы хотите пробрасывать raycast, поле "Raycast Target" у Image/Text включено.
- Если используете 3D-коллайдеры/Physics → нужно использовать Physics.Raycast по камере, а не GraphicRaycaster.
- Если OnEndDrag не вызывается при выходе курсора из окна, добавьте защиту: отслеживайте Input.GetMouseButtonUp(0) в Update и завершайте текущее перетаскивание вручную.
Если пришлёте свой полный код (Begin/Drag/End и проверку попадания на зону), я укажу конкретно, где исправить.