Как исправить проблему, из-за которой карта не возвращается в руку?

Подскажите, пожалуйста, как исправить проблему: при перетаскивании карты, если она не попадает в зону сброса, она «залипает» и возвращается в руку только после того, как я возьму новую карту или передвину её к краю стола. Ниже — код карты: <br/> Код карты: <br/> <pre><code class="cs">using UnityEngine;
  • 18 марта 2026 г. 10:02
Ответы на вопрос 2
Частая причина такого «залипания» — неправильная обработка начала/конца перетаскивания (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 и проверку попадания на зону), я укажу конкретно, где исправить.
Судя по коду, у тебя во время драга стреляет OnMouseExit — курсор уходит за границу коллайдера карты, и он дёргает DOKill() плюс сбрасывает rotation и scale прямо посреди перетаскивания. Раскомментируй <code>isDragging</code> (он у тебя уже заготовлен), ставь <code>true</code> в OnMouseDown, <code>false</code> в OnMouseUp, а в OnMouseEnter и OnMouseExit первой строкой добавь <code>if (isDragging) return;</code> . Ну и если после этого всё равно не возвращается — проверь что в OnMouseUp ветка без drop зоны реально вызывает UpdateCardsPosition.
Похожие вопросы