using GeometryTD.CustomEvent; using GeometryTD.Definition; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; namespace GeometryTD.UI { public class RepoItem : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler, IRepoDragItemView { [SerializeField] private Image _bgImage; [SerializeField] private IconArea _iconArea; private static readonly Color SelectedColor = new Color32(255, 216, 102, 255); private static readonly Color EmptyEnduranceColor = new Color(0.8f, 0f, 0f, 1f); private static readonly Color FullEnduranceColor = new Color(0f, 0.8f, 0f, 1f); private static readonly Vector2 DefaultDragGhostSize = new Vector2(64f, 64f); [SerializeField] private RepoItemContext _context; private CanvasGroup _canvasGroup; private RectTransform _dragRoot; protected GameObject _dragGhostObject; protected RectTransform _dragGhostRect; private bool _isSelected; private bool _isDragging; private bool _dropHandled; private bool _dropAssigned; public RepoItemContext Context => _context; public long InstanceId => _context != null ? _context.InstanceId : 0; bool IRepoDragItemView.CanDrag => _context != null && _context.CanDrag; public TowerCompSlotType ComponentSlotType => _context != null ? _context.ComponentSlotType : TowerCompSlotType.None; public RepoItemClickActionType ClickActionType => _context != null ? _context.ClickActionType : RepoItemClickActionType.OpenDetail; public RepoItemContext ComponentContext => _context; protected IconArea IconArea => _iconArea; protected Image BackgroundImage => _bgImage; protected RectTransform DragRoot => _dragRoot; private void Awake() { _canvasGroup = GetComponent(); if (_canvasGroup == null) { _canvasGroup = gameObject.AddComponent(); } } private void OnDisable() { ResetDragState(); } public virtual void OnInit(RepoItemContext context) { if (context == null) { OnReset(); return; } _context = context; _iconArea.OnInit(context.IconAreaContext); SetSelected(false); ResetDragState(); } public virtual void OnReset() { _context = null; _iconArea.OnReset(); SetSelected(false); ResetDragState(); } public void SetSelected(bool isSelected) { _isSelected = isSelected; RefreshBackgroundColor(); } private void RefreshBackgroundColor() { if (_bgImage == null) { return; } if (_isSelected) { _bgImage.color = SelectedColor; return; } float enduranceRate = _context != null ? Mathf.Clamp01(_context.EnduranceRate01) : 1f; _bgImage.color = Color.Lerp(EmptyEnduranceColor, FullEnduranceColor, enduranceRate); } public void OnClick() { if (_context == null) { return; } if (_isDragging) { return; } GameEntry.Event.Fire(this, RepoItemClickedEventArgs.Create(_context.InstanceId, transform.position)); } public void OnBeginDrag(PointerEventData eventData) { if (!CanStartDrag(eventData)) { return; } _dragRoot = ResolveDragRoot(); if (_dragRoot == null) { return; } _isDragging = true; _dropHandled = false; _dropAssigned = false; CloseItemDescFormIfOpen(); if (!CreateDragGhost()) { _isDragging = false; _dragRoot = null; return; } if (_canvasGroup != null) { _canvasGroup.blocksRaycasts = false; } SetSelected(true); UpdateDragGhostPosition(eventData); } public void OnDrag(PointerEventData eventData) { if (!_isDragging) { return; } UpdateDragGhostPosition(eventData); } public void OnEndDrag(PointerEventData eventData) { if (!_isDragging) { return; } bool assigned = _dropHandled && _dropAssigned; _isDragging = false; if (_canvasGroup != null) { _canvasGroup.blocksRaycasts = true; } DestroyDragGhost(); _dragRoot = null; if (_context == null) { return; } GameEntry.Event.Fire(this, RepoItemDragEndedEventArgs.Create(_context.InstanceId, assigned)); } public void SetDropResult(bool assigned) { if (!_isDragging) { return; } _dropHandled = true; _dropAssigned = assigned; } private bool CanStartDrag(PointerEventData eventData) { if (_context == null || _isDragging) { return false; } if (_isSelected && _context.ComponentSlotType != TowerCompSlotType.None) { return false; } if (!_context.CanDrag) { return false; } if (eventData == null || eventData.button != PointerEventData.InputButton.Left) { return false; } return true; } private static void CloseItemDescFormIfOpen() { var itemDescForm = GameEntry.UI.GetUIForm(UIFormType.ItemDescForm); if (itemDescForm != null) { GameEntry.UI.CloseUIForm(itemDescForm); } } private RectTransform ResolveDragRoot() { Canvas canvas = GetComponentInParent(); if (canvas == null || canvas.rootCanvas == null) { return null; } return canvas.rootCanvas.transform as RectTransform; } protected virtual bool CreateDragGhost() { DestroyDragGhost(); if (_dragRoot == null) { return false; } Sprite iconSprite = _iconArea != null ? _iconArea.CurrentIconSprite : null; Color iconColor = _iconArea != null ? _iconArea.CurrentIconColor : Color.white; Material iconMaterial = _iconArea != null ? _iconArea.CurrentIconMaterial : null; Vector2 iconSize = _iconArea != null ? _iconArea.CurrentIconSize : Vector2.zero; if (iconSprite == null && _bgImage != null) { iconSprite = _bgImage.sprite; iconColor = _bgImage.color; iconMaterial = _bgImage.material; iconSize = _bgImage.rectTransform.rect.size; } if (iconSprite == null) { return false; } _dragGhostObject = new GameObject("RepoItemDragGhost", typeof(RectTransform), typeof(CanvasGroup), typeof(Image)); _dragGhostObject.layer = gameObject.layer; _dragGhostRect = _dragGhostObject.GetComponent(); _dragGhostRect.SetParent(_dragRoot, false); _dragGhostRect.anchorMin = new Vector2(0.5f, 0.5f); _dragGhostRect.anchorMax = new Vector2(0.5f, 0.5f); _dragGhostRect.pivot = new Vector2(0.5f, 0.5f); if (iconSize.x <= 0f || iconSize.y <= 0f) { iconSize = DefaultDragGhostSize; } _dragGhostRect.sizeDelta = iconSize; Image ghostImage = _dragGhostObject.GetComponent(); ghostImage.raycastTarget = false; ghostImage.sprite = iconSprite; ghostImage.color = iconColor; ghostImage.material = iconMaterial; ghostImage.preserveAspect = true; CanvasGroup ghostCanvasGroup = _dragGhostObject.GetComponent(); ghostCanvasGroup.blocksRaycasts = false; ghostCanvasGroup.interactable = false; _dragGhostObject.transform.SetAsLastSibling(); return true; } protected virtual void UpdateDragGhostPosition(PointerEventData eventData) { if (_dragGhostRect == null || _dragRoot == null || eventData == null) { return; } if (RectTransformUtility.ScreenPointToLocalPointInRectangle(_dragRoot, eventData.position, eventData.pressEventCamera, out Vector2 localPoint)) { _dragGhostRect.anchoredPosition = localPoint; } } protected virtual void DestroyDragGhost() { if (_dragGhostObject != null) { Destroy(_dragGhostObject); _dragGhostObject = null; _dragGhostRect = null; } } private void ResetDragState() { _isDragging = false; _dropHandled = false; _dropAssigned = false; _dragRoot = null; DestroyDragGhost(); if (_canvasGroup != null) { _canvasGroup.blocksRaycasts = true; } } } }