332 lines
9.2 KiB
C#
332 lines
9.2 KiB
C#
using GeometryTD.CustomEvent;
|
|
using GeometryTD.Definition;
|
|
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
using UnityEngine.UI;
|
|
|
|
namespace GeometryTD.UI
|
|
{
|
|
public class RepoItem : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
|
|
{
|
|
[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;
|
|
private GameObject _dragGhostObject;
|
|
private RectTransform _dragGhostRect;
|
|
private bool _isSelected;
|
|
private bool _isDragging;
|
|
private bool _dropHandled;
|
|
private bool _dropAssigned;
|
|
|
|
public RepoItemContext Context => _context;
|
|
|
|
private void Awake()
|
|
{
|
|
_canvasGroup = GetComponent<CanvasGroup>();
|
|
if (_canvasGroup == null)
|
|
{
|
|
_canvasGroup = gameObject.AddComponent<CanvasGroup>();
|
|
}
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
ResetDragState();
|
|
}
|
|
|
|
public void OnInit(RepoItemContext context)
|
|
{
|
|
if (context == null)
|
|
{
|
|
OnReset();
|
|
return;
|
|
}
|
|
|
|
_context = context;
|
|
|
|
_iconArea.OnInit(context.IconAreaContext);
|
|
|
|
SetSelected(false);
|
|
ResetDragState();
|
|
}
|
|
|
|
public 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<Canvas>();
|
|
if (canvas == null || canvas.rootCanvas == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return canvas.rootCanvas.transform as RectTransform;
|
|
}
|
|
|
|
private 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;
|
|
|
|
// Towers may not have an icon sprite; fall back to background sprite so drag still works.
|
|
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<RectTransform>();
|
|
_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<Image>();
|
|
ghostImage.raycastTarget = false;
|
|
ghostImage.sprite = iconSprite;
|
|
ghostImage.color = iconColor;
|
|
ghostImage.material = iconMaterial;
|
|
ghostImage.preserveAspect = true;
|
|
|
|
CanvasGroup ghostCanvasGroup = _dragGhostObject.GetComponent<CanvasGroup>();
|
|
ghostCanvasGroup.blocksRaycasts = false;
|
|
ghostCanvasGroup.interactable = false;
|
|
|
|
_dragGhostObject.transform.SetAsLastSibling();
|
|
return true;
|
|
}
|
|
|
|
private 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;
|
|
}
|
|
}
|
|
|
|
private 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;
|
|
}
|
|
}
|
|
}
|
|
}
|