geometry-tower-defense/Assets/GameMain/Scripts/UI/Game/View/RepoItem.cs

382 lines
11 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, IRepoDragItemView
{
[SerializeField] private Image _bgImage;
[SerializeField] private IconArea _iconArea;
private static readonly Color SelectedColor = new Color32(255, 216, 102, 255);
private static readonly Color DisabledSellColor = new Color32(96, 96, 96, 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<CanvasGroup>();
if (_canvasGroup == null)
{
_canvasGroup = gameObject.AddComponent<CanvasGroup>();
}
}
private void OnDisable()
{
ResetDragState();
}
public virtual void OnInit(RepoItemContext context)
{
if (context == null)
{
OnReset();
return;
}
_context = context;
_iconArea.OnInit(context.IconAreaContext);
SetSelected(context.IsSellSelected);
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;
}
if (_context != null && _context.IsSellMode && !_context.IsSellable)
{
_bgImage.color = DisabledSellColor;
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, ResolveScreenPosition()));
}
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 (_context.IsSellMode)
{
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 Vector2 ResolveScreenPosition()
{
RectTransform rectTransform = transform as RectTransform;
if (rectTransform == null)
{
return Vector2.zero;
}
Canvas canvas = GetComponentInParent<Canvas>();
Canvas rootCanvas = canvas != null ? canvas.rootCanvas : null;
Camera uiCamera = null;
if (rootCanvas != null && rootCanvas.renderMode != RenderMode.ScreenSpaceOverlay)
{
uiCamera = rootCanvas.worldCamera != null ? rootCanvas.worldCamera : Camera.main;
}
return RectTransformUtility.WorldToScreenPoint(uiCamera, rectTransform.position);
}
private RectTransform ResolveDragRoot()
{
Canvas canvas = GetComponentInParent<Canvas>();
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<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;
}
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;
}
}
}
}