test mesh
This commit is contained in:
@@ -3,86 +3,84 @@ using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
/// <summary>
|
||||
/// Обработка Drag & Drop предметов между слотами и выброс за пределы инвентаря
|
||||
/// Drag & Drop предметов между слотами.
|
||||
/// Один общий DragIconCanvas на все слоты — создаётся при первом старте.
|
||||
/// </summary>
|
||||
public class InventoryDragDrop : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler, IPointerEnterHandler, IPointerExitHandler
|
||||
{
|
||||
public Slot slot;
|
||||
public int slotIndex;
|
||||
|
||||
[Header("Drag Visual")]
|
||||
[SerializeField] private RectTransform dragIcon;
|
||||
[SerializeField] private Image dragImage;
|
||||
[SerializeField] private float dragIconScale = 1.2f;
|
||||
[SerializeField] private float dragIconScale = 1.2f;
|
||||
[SerializeField] private bool allowDropOutside = true;
|
||||
[SerializeField] private float dropThreshold = 100f;
|
||||
|
||||
[Header("Drop Settings")]
|
||||
[SerializeField] private bool allowDropOutside = true;
|
||||
[SerializeField] private float dropThreshold = 100f; // пикселей за пределами инвентаря
|
||||
// ── Общий на все слоты drag-icon ─────────────────────────────────────────
|
||||
private static GameObject _sharedCanvas;
|
||||
private static RectTransform _sharedIcon;
|
||||
private static Image _sharedImage;
|
||||
|
||||
private Canvas _canvas;
|
||||
private CanvasGroup _canvasGroup;
|
||||
private bool _isDragging;
|
||||
private Vector2 _dragStartPosition;
|
||||
// ── Per-instance поля ─────────────────────────────────────────────────────
|
||||
private CanvasGroup _canvasGroup;
|
||||
private bool _isDragging;
|
||||
private RectTransform _inventoryPanelRect;
|
||||
|
||||
// ── Unity lifecycle ───────────────────────────────────────────────────────
|
||||
|
||||
void Start()
|
||||
{
|
||||
_canvas = GetComponentInParent<Canvas>();
|
||||
_canvasGroup = GetComponent<CanvasGroup>();
|
||||
|
||||
if (dragIcon == null)
|
||||
{
|
||||
CreateDragIcon();
|
||||
}
|
||||
// Создаём общий DragCanvas один раз для всех слотов
|
||||
if (_sharedCanvas == null)
|
||||
CreateSharedDragCanvas();
|
||||
|
||||
// Находим панель инвентаря
|
||||
var inventoryManager = FindObjectOfType<InventoryManager>();
|
||||
if (inventoryManager?.inventoryPanel != null)
|
||||
{
|
||||
_inventoryPanelRect = inventoryManager.inventoryPanel.GetComponent<RectTransform>();
|
||||
}
|
||||
|
||||
if (dragIcon != null)
|
||||
dragIcon.gameObject.SetActive(false);
|
||||
// Ищем rect инвентарной панели для определения «вне панели»
|
||||
if (InventoryManager.Instance?.inventoryPanel != null)
|
||||
_inventoryPanelRect = InventoryManager.Instance.inventoryPanel
|
||||
.GetComponent<RectTransform>();
|
||||
}
|
||||
|
||||
private void CreateDragIcon()
|
||||
private static void CreateSharedDragCanvas()
|
||||
{
|
||||
GameObject canvasGO = new GameObject("DragIconCanvas");
|
||||
canvasGO.transform.SetParent(_canvas != null ? _canvas.transform : transform.root);
|
||||
_sharedCanvas = new GameObject("DragIconCanvas");
|
||||
DontDestroyOnLoad(_sharedCanvas);
|
||||
|
||||
var dragCanvas = canvasGO.AddComponent<Canvas>();
|
||||
dragCanvas.overrideSorting = true;
|
||||
dragCanvas.sortingOrder = 1000;
|
||||
dragCanvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
||||
canvasGO.AddComponent<GraphicRaycaster>();
|
||||
var c = _sharedCanvas.AddComponent<Canvas>();
|
||||
c.renderMode = RenderMode.ScreenSpaceOverlay;
|
||||
c.sortingOrder = 1000;
|
||||
c.overrideSorting = true;
|
||||
_sharedCanvas.AddComponent<GraphicRaycaster>();
|
||||
|
||||
dragIcon = new GameObject("DragIcon").AddComponent<RectTransform>();
|
||||
dragIcon.SetParent(canvasGO.transform, false);
|
||||
dragIcon.sizeDelta = new Vector2(48, 48);
|
||||
var iconGO = new GameObject("DragIcon");
|
||||
iconGO.transform.SetParent(_sharedCanvas.transform, false);
|
||||
|
||||
dragImage = dragIcon.gameObject.AddComponent<Image>();
|
||||
dragImage.raycastTarget = false;
|
||||
_sharedIcon = iconGO.AddComponent<RectTransform>();
|
||||
_sharedIcon.sizeDelta = new Vector2(48, 48);
|
||||
|
||||
dragIcon.gameObject.SetActive(false);
|
||||
_sharedImage = iconGO.AddComponent<Image>();
|
||||
_sharedImage.raycastTarget = false;
|
||||
|
||||
iconGO.SetActive(false);
|
||||
}
|
||||
|
||||
// ── Drag handlers ─────────────────────────────────────────────────────────
|
||||
|
||||
public void OnBeginDrag(PointerEventData eventData)
|
||||
{
|
||||
if (slot == null || slot.IsEmpty) return;
|
||||
|
||||
_isDragging = true;
|
||||
_dragStartPosition = eventData.position;
|
||||
|
||||
if (_canvasGroup != null)
|
||||
_canvasGroup.blocksRaycasts = false;
|
||||
|
||||
if (dragIcon != null && slot.item?.icon != null)
|
||||
if (_sharedIcon != null && slot.item?.icon != null)
|
||||
{
|
||||
dragIcon.gameObject.SetActive(true);
|
||||
dragImage.sprite = slot.item.icon;
|
||||
dragIcon.localScale = Vector3.one * dragIconScale;
|
||||
dragIcon.position = eventData.position;
|
||||
_sharedImage.sprite = slot.item.icon;
|
||||
_sharedIcon.localScale = Vector3.one * dragIconScale;
|
||||
_sharedIcon.position = eventData.position;
|
||||
_sharedIcon.gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
var bg = GetComponent<Image>();
|
||||
@@ -92,20 +90,19 @@ public class InventoryDragDrop : MonoBehaviour, IBeginDragHandler, IDragHandler,
|
||||
|
||||
public void OnDrag(PointerEventData eventData)
|
||||
{
|
||||
if (!_isDragging || dragIcon == null) return;
|
||||
dragIcon.position = eventData.position;
|
||||
if (!_isDragging || _sharedIcon == null) return;
|
||||
_sharedIcon.position = eventData.position;
|
||||
}
|
||||
|
||||
public void OnEndDrag(PointerEventData eventData)
|
||||
{
|
||||
if (!_isDragging) return;
|
||||
|
||||
_isDragging = false;
|
||||
|
||||
if (dragIcon != null)
|
||||
if (_sharedIcon != null)
|
||||
{
|
||||
dragIcon.gameObject.SetActive(false);
|
||||
dragIcon.localScale = Vector3.one;
|
||||
_sharedIcon.gameObject.SetActive(false);
|
||||
_sharedIcon.localScale = Vector3.one;
|
||||
}
|
||||
|
||||
if (_canvasGroup != null)
|
||||
@@ -113,124 +110,66 @@ public class InventoryDragDrop : MonoBehaviour, IBeginDragHandler, IDragHandler,
|
||||
|
||||
var bg = GetComponent<Image>();
|
||||
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);
|
||||
bg.color = slot.IsEmpty
|
||||
? new Color(0.25f, 0.25f, 0.25f, 0.8f)
|
||||
: new Color(0.35f, 0.35f, 0.35f, 0.95f);
|
||||
|
||||
// Проверяем - выбросили за пределы инвентаря?
|
||||
if (allowDropOutside && IsOutsideInventory(eventData.position))
|
||||
{
|
||||
DropItemOutside();
|
||||
return;
|
||||
}
|
||||
|
||||
// Иначе - пробуем переместить в другой слот
|
||||
// Сначала ищем целевой слот (инвентарь ИЛИ хотбар)
|
||||
var raycastResults = new System.Collections.Generic.List<RaycastResult>();
|
||||
EventSystem.current.RaycastAll(eventData, raycastResults);
|
||||
|
||||
Slot targetSlot = null;
|
||||
|
||||
foreach (var result in raycastResults)
|
||||
{
|
||||
var slotComponent = result.gameObject.GetComponent<Slot>();
|
||||
if (slotComponent != null && slotComponent != slot)
|
||||
{
|
||||
targetSlot = slotComponent;
|
||||
break;
|
||||
}
|
||||
var s = result.gameObject.GetComponent<Slot>();
|
||||
if (s != null && s != slot) { targetSlot = s; break; }
|
||||
}
|
||||
|
||||
if (targetSlot != null && InventoryManager.Instance != null)
|
||||
if (targetSlot != null)
|
||||
{
|
||||
InventoryManager.Instance.SwapSlots(slotIndex, targetSlot.slotIndex);
|
||||
// Нашли слот — перемещаем (работает и для хотбара)
|
||||
InventoryManager.Instance?.SwapSlots(slot, targetSlot);
|
||||
return;
|
||||
}
|
||||
|
||||
// Слот не найден — выбросить в мир если за пределами инвентаря
|
||||
if (allowDropOutside && IsOutsideInventory(eventData.position))
|
||||
DropItemOutside();
|
||||
}
|
||||
|
||||
private bool IsOutsideInventory(Vector2 screenPosition)
|
||||
// ── Вспомогательные ───────────────────────────────────────────────────────
|
||||
|
||||
private bool IsOutsideInventory(Vector2 screenPos)
|
||||
{
|
||||
if (_inventoryPanelRect == null) return false;
|
||||
|
||||
// Получаем границы панели инвентаря в экранных координатах
|
||||
Vector3[] corners = new Vector3[4];
|
||||
_inventoryPanelRect.GetWorldCorners(corners);
|
||||
|
||||
// rect панели в экранных координатах
|
||||
float minX = corners[0].x;
|
||||
float maxX = corners[2].x;
|
||||
float minY = corners[0].y;
|
||||
float maxY = corners[2].y;
|
||||
|
||||
// Добавляем отступ
|
||||
float threshold = dropThreshold;
|
||||
|
||||
// Проверяем находится ли курсор за пределами панели + threshold
|
||||
bool outside = screenPosition.x < minX - threshold ||
|
||||
screenPosition.x > maxX + threshold ||
|
||||
screenPosition.y < minY - threshold ||
|
||||
screenPosition.y > maxY + threshold;
|
||||
|
||||
return outside;
|
||||
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;
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback - просто создаём объект
|
||||
var go = new GameObject($"Dropped_{item.itemName}");
|
||||
go.transform.position = dropPos;
|
||||
|
||||
var visual = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
||||
visual.transform.SetParent(go.transform);
|
||||
visual.transform.localPosition = Vector3.zero;
|
||||
visual.transform.localScale = Vector3.one * 0.3f;
|
||||
DestroyImmediate(visual.GetComponent<Collider>());
|
||||
|
||||
var worldItem = go.AddComponent<WorldItem>();
|
||||
worldItem.Setup(item, amount);
|
||||
}
|
||||
|
||||
// Очищаем слот
|
||||
slot.Clear();
|
||||
|
||||
Debug.Log($"[DragDrop] Выброшен: {item.itemName} x{amount}");
|
||||
}
|
||||
|
||||
public void OnPointerEnter(PointerEventData eventData)
|
||||
{
|
||||
if (!_isDragging && slot != null && !slot.IsEmpty)
|
||||
{
|
||||
var bg = GetComponent<Image>();
|
||||
if (bg != null)
|
||||
bg.color = new Color(0.5f, 0.5f, 0.5f, 1f);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPointerExit(PointerEventData eventData)
|
||||
{
|
||||
if (!_isDragging && slot != null)
|
||||
{
|
||||
var bg = GetComponent<Image>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
public void OnPointerEnter(PointerEventData eventData) { }
|
||||
public void OnPointerExit(PointerEventData eventData) { }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user