using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; /// /// Drag & Drop предметов между слотами. /// Один общий DragIconCanvas на все слоты — создаётся при первом старте. /// public class InventoryDragDrop : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler, IPointerEnterHandler, IPointerExitHandler { public Slot slot; public int slotIndex; [SerializeField] private float dragIconScale = 1.2f; [SerializeField] private bool allowDropOutside = true; [SerializeField] private float dropThreshold = 100f; // ── Общий на все слоты drag-icon ───────────────────────────────────────── private static GameObject _sharedCanvas; private static RectTransform _sharedIcon; private static Image _sharedImage; // ── Per-instance поля ───────────────────────────────────────────────────── private CanvasGroup _canvasGroup; private bool _isDragging; private RectTransform _inventoryPanelRect; // ── Unity lifecycle ─────────────────────────────────────────────────────── void Start() { _canvasGroup = GetComponent(); // Создаём общий DragCanvas один раз для всех слотов if (_sharedCanvas == null) CreateSharedDragCanvas(); // Ищем rect инвентарной панели для определения «вне панели» if (InventoryManager.Instance?.inventoryPanel != null) _inventoryPanelRect = InventoryManager.Instance.inventoryPanel .GetComponent(); } private static void CreateSharedDragCanvas() { _sharedCanvas = new GameObject("DragIconCanvas"); DontDestroyOnLoad(_sharedCanvas); var c = _sharedCanvas.AddComponent(); c.renderMode = RenderMode.ScreenSpaceOverlay; c.sortingOrder = 1000; c.overrideSorting = true; _sharedCanvas.AddComponent(); var iconGO = new GameObject("DragIcon"); iconGO.transform.SetParent(_sharedCanvas.transform, false); _sharedIcon = iconGO.AddComponent(); _sharedIcon.sizeDelta = new Vector2(48, 48); _sharedImage = iconGO.AddComponent(); _sharedImage.raycastTarget = false; iconGO.SetActive(false); } // ── Drag handlers ───────────────────────────────────────────────────────── public void OnBeginDrag(PointerEventData eventData) { if (slot == null || slot.IsEmpty) return; _isDragging = true; if (_canvasGroup != null) _canvasGroup.blocksRaycasts = false; if (_sharedIcon != null && slot.item?.icon != null) { _sharedImage.sprite = slot.item.icon; _sharedIcon.localScale = Vector3.one * dragIconScale; _sharedIcon.position = eventData.position; _sharedIcon.gameObject.SetActive(true); } var bg = GetComponent(); if (bg != null) bg.color = new Color(1f, 1f, 1f, 0.5f); } public void OnDrag(PointerEventData eventData) { if (!_isDragging || _sharedIcon == null) return; _sharedIcon.position = eventData.position; } public void OnEndDrag(PointerEventData eventData) { if (!_isDragging) return; _isDragging = false; if (_sharedIcon != null) { _sharedIcon.gameObject.SetActive(false); _sharedIcon.localScale = Vector3.one; } if (_canvasGroup != null) _canvasGroup.blocksRaycasts = true; var bg = GetComponent(); if (bg != null) bg.color = slot.IsEmpty ? new Color(0.25f, 0.25f, 0.25f, 0.8f) : new Color(0.35f, 0.35f, 0.35f, 0.95f); // Сначала ищем целевой слот (инвентарь ИЛИ хотбар) var raycastResults = new System.Collections.Generic.List(); EventSystem.current.RaycastAll(eventData, raycastResults); Slot targetSlot = null; foreach (var result in raycastResults) { var s = result.gameObject.GetComponent(); if (s != null && s != slot) { targetSlot = s; break; } } if (targetSlot != null) { // Нашли слот — перемещаем (работает и для хотбара) InventoryManager.Instance?.SwapSlots(slot, targetSlot); return; } // Слот не найден — выбросить в мир если за пределами инвентаря if (allowDropOutside && IsOutsideInventory(eventData.position)) DropItemOutside(); } // ── Вспомогательные ─────────────────────────────────────────────────────── private bool IsOutsideInventory(Vector2 screenPos) { if (_inventoryPanelRect == null) return false; Vector3[] corners = new Vector3[4]; _inventoryPanelRect.GetWorldCorners(corners); return screenPos.x < corners[0].x - dropThreshold || screenPos.x > corners[2].x + dropThreshold || screenPos.y < corners[0].y - dropThreshold || screenPos.y > corners[2].y + dropThreshold; } private void DropItemOutside() { if (slot == null || slot.IsEmpty) return; var item = slot.item; int amount = slot.amount; Vector3 dropPos = Vector3.zero; if (Camera.main != null) dropPos = Camera.main.transform.position + Camera.main.transform.forward * 2f; if (InventoryItemFactory.Instance != null) InventoryItemFactory.Instance.DropItem(item, amount, dropPos); slot.Clear(); Debug.Log($"[DragDrop] Выброшен: {item.itemName} x{amount}"); } public void OnPointerEnter(PointerEventData eventData) { } public void OnPointerExit(PointerEventData eventData) { } }