init
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
using GeometryTD.CustomEvent;
|
||||
using GeometryTD.Definition;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class CombineArea : MonoBehaviour, IDropHandler
|
||||
{
|
||||
[SerializeField] private CombineSlotItem[] _slots;
|
||||
private bool _isInteractionEnabled = true;
|
||||
|
||||
public void OnInit(CombineAreaContext context)
|
||||
{
|
||||
if (_slots == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _slots.Length; i++)
|
||||
{
|
||||
if (_slots[i] != null)
|
||||
{
|
||||
_slots[i].OnInit(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnReset()
|
||||
{
|
||||
if (_slots == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var slot in _slots)
|
||||
{
|
||||
if (slot != null)
|
||||
{
|
||||
slot.OnReset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnCombineClick()
|
||||
{
|
||||
if (!_isInteractionEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryGetBoundItemId(TowerCompSlotType.Muzzle, out long muzzleItemId) ||
|
||||
!TryGetBoundItemId(TowerCompSlotType.Bearing, out long bearingItemId) ||
|
||||
!TryGetBoundItemId(TowerCompSlotType.Base, out long baseItemId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameEntry.Event.Fire(this, RepoCombineRequestedEventArgs.Create(muzzleItemId, bearingItemId, baseItemId));
|
||||
}
|
||||
|
||||
public bool TryAssignItem(RepoItemContext itemContext)
|
||||
{
|
||||
if (!_isInteractionEnabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemContext == null || itemContext.ComponentSlotType == TowerCompSlotType.None)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CombineSlotItem targetSlot = FindSlot(itemContext.ComponentSlotType);
|
||||
if (targetSlot == null || targetSlot.HasItem)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
targetSlot.BindItem(itemContext);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryClearSlot(int slotIndex, out long removedItemId)
|
||||
{
|
||||
removedItemId = 0;
|
||||
if (_slots == null || slotIndex < 0 || slotIndex >= _slots.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CombineSlotItem slot = _slots[slotIndex];
|
||||
if (slot == null || !slot.HasItem)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
removedItemId = slot.BoundItemId;
|
||||
slot.ClearSlot();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnDrop(PointerEventData eventData)
|
||||
{
|
||||
if (!_isInteractionEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (eventData == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject pointerDrag = eventData.pointerDrag;
|
||||
if (pointerDrag == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IRepoDragItemView dragItem = pointerDrag.GetComponent<IRepoDragItemView>() ??
|
||||
pointerDrag.GetComponentInParent<IRepoDragItemView>();
|
||||
if (dragItem == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool assigned = TryAssignItem(dragItem.ComponentContext);
|
||||
dragItem.SetDropResult(assigned);
|
||||
}
|
||||
|
||||
public void SetInteractionEnabled(bool enabled)
|
||||
{
|
||||
_isInteractionEnabled = enabled;
|
||||
}
|
||||
|
||||
private CombineSlotItem FindSlot(TowerCompSlotType slotType)
|
||||
{
|
||||
if (_slots == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _slots.Length; i++)
|
||||
{
|
||||
CombineSlotItem slot = _slots[i];
|
||||
if (slot != null && slot.AcceptSlotType == slotType)
|
||||
{
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool TryGetBoundItemId(TowerCompSlotType slotType, out long boundItemId)
|
||||
{
|
||||
boundItemId = 0;
|
||||
CombineSlotItem slot = FindSlot(slotType);
|
||||
if (slot == null || !slot.HasItem || slot.BoundItemId <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
boundItemId = slot.BoundItemId;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using GeometryTD.CustomEvent;
|
||||
using GeometryTD.Definition;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class CombineSlotItem : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private TowerCompSlotType _acceptSlotType = TowerCompSlotType.None;
|
||||
|
||||
[SerializeField] private IconArea _iconArea;
|
||||
|
||||
[SerializeField] private CommonButton _button;
|
||||
|
||||
private long _boundItemId;
|
||||
|
||||
private int _slotIndex = -1;
|
||||
|
||||
public TowerCompSlotType AcceptSlotType => _acceptSlotType;
|
||||
|
||||
public bool HasItem => _boundItemId > 0;
|
||||
|
||||
public int SlotIndex => _slotIndex;
|
||||
|
||||
public long BoundItemId => _boundItemId;
|
||||
|
||||
public void OnInit(int slotIndex)
|
||||
{
|
||||
_slotIndex = slotIndex;
|
||||
ClearSlot();
|
||||
_iconArea.OnReset();
|
||||
}
|
||||
|
||||
public void BindItem(RepoItemContext itemContext)
|
||||
{
|
||||
_boundItemId = itemContext?.InstanceId ?? 0;
|
||||
_button.Interactive = true;
|
||||
|
||||
if (itemContext != null)
|
||||
{
|
||||
_iconArea.OnInit(itemContext.IconAreaContext);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearSlot()
|
||||
{
|
||||
_boundItemId = 0;
|
||||
_button.Interactive = false;
|
||||
_iconArea.OnReset();
|
||||
}
|
||||
|
||||
public void OnReset()
|
||||
{
|
||||
_slotIndex = -1;
|
||||
ClearSlot();
|
||||
_iconArea.OnReset();
|
||||
}
|
||||
|
||||
public void OnClick()
|
||||
{
|
||||
if (_slotIndex < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameEntry.Event.Fire(this, CombineSlotClickedEventArgs.Create(_slotIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
using System.Collections.Generic;
|
||||
using GameFramework.ObjectPool;
|
||||
using GeometryTD.PoolObjectBase;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class CompArea : MonoBehaviour
|
||||
{
|
||||
[FormerlySerializedAs("m_Content")] [SerializeField] private Transform _content;
|
||||
[FormerlySerializedAs("m_ItemTemplate")] [SerializeField] private RepoItem _itemTemplate;
|
||||
[SerializeField] private TowerRepoItem _towerItemTemplate;
|
||||
[FormerlySerializedAs("m_InstancePoolCapacity")] [SerializeField] private int _instancePoolCapacity = 64;
|
||||
|
||||
private readonly List<RepoItem> _activeComponentItems = new List<RepoItem>();
|
||||
private readonly List<TowerRepoItem> _activeTowerItems = new List<TowerRepoItem>();
|
||||
private readonly Dictionary<long, RepoItem> _componentItemMap = new Dictionary<long, RepoItem>();
|
||||
private readonly Dictionary<long, TowerRepoItem> _towerItemMap = new Dictionary<long, TowerRepoItem>();
|
||||
private IObjectPool<RepoItemObject> _componentItemPool;
|
||||
private IObjectPool<TowerRepoItemObject> _towerItemPool;
|
||||
private string _componentPoolName;
|
||||
private string _towerPoolName;
|
||||
|
||||
public void OnInit(CompAreaContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
OnReset();
|
||||
return;
|
||||
}
|
||||
|
||||
EnsurePool();
|
||||
OnReset();
|
||||
|
||||
if (context.ComponentItems != null)
|
||||
{
|
||||
foreach (RepoItemContext itemContext in context.ComponentItems)
|
||||
{
|
||||
RepoItem item = CreateOrSpawnComponentItem();
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
item.gameObject.SetActive(true);
|
||||
item.OnInit(itemContext);
|
||||
_activeComponentItems.Add(item);
|
||||
_componentItemMap[itemContext.InstanceId] = item;
|
||||
}
|
||||
}
|
||||
|
||||
if (context.TowerItems != null)
|
||||
{
|
||||
foreach (TowerRepoItemContext itemContext in context.TowerItems)
|
||||
{
|
||||
TowerRepoItem item = CreateOrSpawnTowerItem();
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
item.gameObject.SetActive(true);
|
||||
item.OnInit(itemContext);
|
||||
_activeTowerItems.Add(item);
|
||||
_towerItemMap[itemContext.InstanceId] = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnReset()
|
||||
{
|
||||
for (int i = _activeComponentItems.Count - 1; i >= 0; i--)
|
||||
{
|
||||
RepoItem item = _activeComponentItems[i];
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
item.OnReset();
|
||||
item.gameObject.SetActive(false);
|
||||
_componentItemPool?.Unspawn(item);
|
||||
}
|
||||
|
||||
for (int i = _activeTowerItems.Count - 1; i >= 0; i--)
|
||||
{
|
||||
TowerRepoItem item = _activeTowerItems[i];
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
item.OnReset();
|
||||
item.gameObject.SetActive(false);
|
||||
_towerItemPool?.Unspawn(item);
|
||||
}
|
||||
|
||||
_activeComponentItems.Clear();
|
||||
_activeTowerItems.Clear();
|
||||
_componentItemMap.Clear();
|
||||
_towerItemMap.Clear();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
OnReset();
|
||||
_componentItemPool?.ReleaseAllUnused();
|
||||
_towerItemPool?.ReleaseAllUnused();
|
||||
}
|
||||
|
||||
private void EnsurePool()
|
||||
{
|
||||
if (_componentItemPool == null)
|
||||
{
|
||||
_componentPoolName = $"RepoItemPool_{GetInstanceID()}";
|
||||
_componentItemPool =
|
||||
GameEntry.ObjectPool.CreateSingleSpawnObjectPool<RepoItemObject>(_componentPoolName,
|
||||
_instancePoolCapacity);
|
||||
}
|
||||
|
||||
if (_towerItemPool == null)
|
||||
{
|
||||
_towerPoolName = $"TowerRepoItemPool_{GetInstanceID()}";
|
||||
_towerItemPool =
|
||||
GameEntry.ObjectPool.CreateSingleSpawnObjectPool<TowerRepoItemObject>(_towerPoolName,
|
||||
_instancePoolCapacity);
|
||||
}
|
||||
}
|
||||
|
||||
private RepoItem CreateOrSpawnComponentItem()
|
||||
{
|
||||
if (_componentItemPool == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
RepoItemObject itemObject = _componentItemPool.Spawn();
|
||||
RepoItem item = itemObject != null ? (RepoItem)itemObject.Target : null;
|
||||
if (item == null)
|
||||
{
|
||||
if (_itemTemplate == null)
|
||||
{
|
||||
Log.Warning("CompArea requires a component item template.");
|
||||
return null;
|
||||
}
|
||||
|
||||
item = Instantiate(_itemTemplate);
|
||||
_componentItemPool.Register(RepoItemObject.Create(item), true);
|
||||
}
|
||||
|
||||
if (_content != null)
|
||||
{
|
||||
item.transform.SetParent(_content, false);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
private TowerRepoItem CreateOrSpawnTowerItem()
|
||||
{
|
||||
if (_towerItemPool == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
TowerRepoItemObject itemObject = _towerItemPool.Spawn();
|
||||
TowerRepoItem item = itemObject != null ? (TowerRepoItem)itemObject.Target : null;
|
||||
if (item == null)
|
||||
{
|
||||
if (_towerItemTemplate == null)
|
||||
{
|
||||
Log.Warning("CompArea requires a tower item template.");
|
||||
return null;
|
||||
}
|
||||
|
||||
item = Instantiate(_towerItemTemplate);
|
||||
_towerItemPool.Register(TowerRepoItemObject.Create(item), true);
|
||||
}
|
||||
|
||||
if (_content != null)
|
||||
{
|
||||
item.transform.SetParent(_content, false);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public void SetItemSelected(long itemId, bool isSelected)
|
||||
{
|
||||
if (_componentItemMap.TryGetValue(itemId, out RepoItem componentItem))
|
||||
{
|
||||
componentItem.SetSelected(isSelected);
|
||||
}
|
||||
|
||||
if (_towerItemMap.TryGetValue(itemId, out TowerRepoItem towerItem))
|
||||
{
|
||||
towerItem.SetSelected(isSelected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class EventForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private TMP_Text _titleText;
|
||||
[SerializeField] private TMP_Text _descriptionText;
|
||||
[SerializeField] private EventOptionItem[] _optionItems;
|
||||
|
||||
private EventFormContext _context;
|
||||
|
||||
public void RefreshUI(EventFormContext context)
|
||||
{
|
||||
_context = context;
|
||||
|
||||
if (_titleText != null)
|
||||
{
|
||||
_titleText.text = context?.Title ?? string.Empty;
|
||||
}
|
||||
|
||||
if (_descriptionText != null)
|
||||
{
|
||||
_descriptionText.text = context?.Description ?? string.Empty;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _optionItems.Length; i++)
|
||||
{
|
||||
EventOptionItemContext optionContext = null;
|
||||
if (context?.OptionItems != null && i < context.OptionItems.Length)
|
||||
{
|
||||
optionContext = context.OptionItems[i];
|
||||
}
|
||||
|
||||
if (_optionItems[i] != null)
|
||||
{
|
||||
_optionItems[i].OnInit(optionContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnOpen(object userData)
|
||||
{
|
||||
base.OnOpen(userData);
|
||||
|
||||
if (userData is EventFormContext context)
|
||||
{
|
||||
RefreshUI(context);
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Warning("EventForm requires EventFormContext as userData.");
|
||||
}
|
||||
|
||||
protected override void OnClose(bool isShutdown, object userData)
|
||||
{
|
||||
_context = null;
|
||||
|
||||
if (_titleText != null)
|
||||
{
|
||||
_titleText.text = string.Empty;
|
||||
}
|
||||
|
||||
if (_descriptionText != null)
|
||||
{
|
||||
_descriptionText.text = string.Empty;
|
||||
}
|
||||
|
||||
foreach (var item in _optionItems)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
item.OnReset();
|
||||
}
|
||||
}
|
||||
|
||||
base.OnClose(isShutdown, userData);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using GeometryTD.CustomEvent;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class EventOptionItem : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private TMP_Text _optionText;
|
||||
|
||||
private static readonly Color SelectableTextColor = Color.white;
|
||||
private static readonly Color BlockedTextColor = new Color(0.75f, 0.75f, 0.75f, 1f);
|
||||
|
||||
private int _optionIndex;
|
||||
private bool _isSelectable;
|
||||
private CommonButton _commonButton;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_commonButton = GetComponent<CommonButton>();
|
||||
}
|
||||
|
||||
public void OnInit(EventOptionItemContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
OnReset();
|
||||
gameObject.SetActive(false);
|
||||
return;
|
||||
}
|
||||
|
||||
_optionIndex = context.OptionIndex;
|
||||
_isSelectable = context.IsSelectable;
|
||||
if (_optionText != null)
|
||||
{
|
||||
_optionText.text = BuildDisplayText(context);
|
||||
_optionText.color = _isSelectable ? SelectableTextColor : BlockedTextColor;
|
||||
}
|
||||
|
||||
if (_commonButton != null)
|
||||
{
|
||||
_commonButton.Interactive = _isSelectable;
|
||||
}
|
||||
|
||||
gameObject.SetActive(!string.IsNullOrEmpty(context.OptionText));
|
||||
}
|
||||
|
||||
public void OnReset()
|
||||
{
|
||||
_optionIndex = -1;
|
||||
_isSelectable = false;
|
||||
if (_optionText != null)
|
||||
{
|
||||
_optionText.text = string.Empty;
|
||||
_optionText.color = SelectableTextColor;
|
||||
}
|
||||
|
||||
if (_commonButton != null)
|
||||
{
|
||||
_commonButton.Interactive = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnClick()
|
||||
{
|
||||
if (_optionIndex < 0 || !_isSelectable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameEntry.Event.Fire(this, EventOptionItemSelectedEventArgs.Create(_optionIndex));
|
||||
}
|
||||
|
||||
private static string BuildDisplayText(EventOptionItemContext context)
|
||||
{
|
||||
string optionText = context.OptionText ?? string.Empty;
|
||||
if (context.IsSelectable || string.IsNullOrEmpty(context.BlockedReason))
|
||||
{
|
||||
return optionText;
|
||||
}
|
||||
|
||||
return $"{optionText}\n<size=75%>{context.BlockedReason}</size>";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using GeometryTD.Definition;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public interface IRepoDragItemView
|
||||
{
|
||||
long InstanceId { get; }
|
||||
|
||||
bool CanDrag { get; }
|
||||
|
||||
TowerCompSlotType ComponentSlotType { get; }
|
||||
|
||||
RepoItemClickActionType ClickActionType { get; }
|
||||
|
||||
RepoItemContext ComponentContext { get; }
|
||||
|
||||
void SetDropResult(bool assigned);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using GeometryTD.CustomEvent;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class MainForm : UGuiForm
|
||||
{
|
||||
private MainFormContext _context;
|
||||
|
||||
public void RefreshUI(MainFormContext context)
|
||||
{
|
||||
_context = context;
|
||||
if (_context == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnReturnButtonClick()
|
||||
{
|
||||
GameEntry.Event.Fire(this, ReturnButtonClickedEventArgs.Create());
|
||||
}
|
||||
|
||||
public void OnRepoButtonClick()
|
||||
{
|
||||
GameEntry.Event.Fire(this, RepoButtonClickedEventArgs.Create());
|
||||
}
|
||||
|
||||
protected override void OnOpen(object userData)
|
||||
{
|
||||
base.OnOpen(userData);
|
||||
|
||||
if (userData is MainFormContext context)
|
||||
{
|
||||
RefreshUI(context);
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Warning("MainForm requires MainFormContext as userData.");
|
||||
}
|
||||
|
||||
protected override void OnClose(bool isShutdown, object userData)
|
||||
{
|
||||
_context = null;
|
||||
|
||||
base.OnClose(isShutdown, userData);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using GeometryTD.CustomEvent;
|
||||
using GeometryTD.Procedure;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class NodeItem : MonoBehaviour
|
||||
{
|
||||
private const string CombatIconAssetName = "Combat";
|
||||
private const string EventIconAssetName = "Event";
|
||||
private const string ShopIconAssetName = "Shop";
|
||||
private const string BossIconAssetName = "BossCombat";
|
||||
|
||||
[SerializeField] private Image _icon;
|
||||
[SerializeField] private Image _bg;
|
||||
[SerializeField] private CommonButton _button;
|
||||
|
||||
[SerializeField] private Color _lockedColor = Color.gray;
|
||||
[SerializeField] private Color _activeColor = Color.cyan;
|
||||
[SerializeField] private Color _passedColor = Color.green;
|
||||
[SerializeField] private Color _exceptionColor = Color.red;
|
||||
[SerializeField] private Color _defaultIconColor = Color.white;
|
||||
[SerializeField] private Color _lockedIconColor = Color.gray;
|
||||
|
||||
private NodeItemContext _context;
|
||||
private string _requestedIconAssetName;
|
||||
|
||||
public void RefreshUI(NodeItemContext context)
|
||||
{
|
||||
_context = context;
|
||||
|
||||
if (_button != null)
|
||||
{
|
||||
_button.Interactive = context != null && context.CanClick;
|
||||
}
|
||||
|
||||
Color targetColor = _lockedColor;
|
||||
if (context == null)
|
||||
{
|
||||
targetColor = _lockedColor;
|
||||
}
|
||||
else if (context.IsCompleted)
|
||||
{
|
||||
targetColor = _passedColor;
|
||||
}
|
||||
else if (context.IsException)
|
||||
{
|
||||
targetColor = _exceptionColor;
|
||||
}
|
||||
else if (context.IsCurrent)
|
||||
{
|
||||
targetColor = _activeColor;
|
||||
}
|
||||
|
||||
if (_bg != null)
|
||||
{
|
||||
_bg.color = targetColor;
|
||||
}
|
||||
|
||||
if (_icon != null)
|
||||
{
|
||||
RefreshIcon(context != null ? context.NodeType : RunNodeType.None);
|
||||
_icon.color = context != null && !context.IsLocked ? _defaultIconColor : _lockedIconColor;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnClick()
|
||||
{
|
||||
if (_context == null || !_context.CanClick)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameEntry.Event.Fire(this, NodeMapNodeClickEventArgs.Create(_context.SequenceIndex));
|
||||
}
|
||||
|
||||
private void RefreshIcon(RunNodeType nodeType)
|
||||
{
|
||||
if (_icon == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string assetName = ResolveIconAssetName(nodeType);
|
||||
_requestedIconAssetName = assetName;
|
||||
if (string.IsNullOrWhiteSpace(assetName) || GameEntry.SpriteCache == null)
|
||||
{
|
||||
_icon.sprite = null;
|
||||
return;
|
||||
}
|
||||
|
||||
GameEntry.SpriteCache.GetSprite(assetName, sprite =>
|
||||
{
|
||||
if (_icon == null || _requestedIconAssetName != assetName)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_icon.sprite = sprite;
|
||||
});
|
||||
}
|
||||
|
||||
private static string ResolveIconAssetName(RunNodeType nodeType)
|
||||
{
|
||||
switch (nodeType)
|
||||
{
|
||||
case RunNodeType.Combat:
|
||||
return CombatIconAssetName;
|
||||
case RunNodeType.Event:
|
||||
return EventIconAssetName;
|
||||
case RunNodeType.Shop:
|
||||
return ShopIconAssetName;
|
||||
case RunNodeType.BossCombat:
|
||||
return BossIconAssetName;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class NodeMapForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private TMP_Text _titleText;
|
||||
[SerializeField] private TMP_Text _progressText;
|
||||
[SerializeField] private TMP_Text _currentNodeText;
|
||||
[SerializeField] private NodeItem[] _nodeItems;
|
||||
|
||||
private NodeMapFormContext _context;
|
||||
|
||||
public void RefreshUI(NodeMapFormContext context)
|
||||
{
|
||||
_context = context;
|
||||
if (_titleText != null)
|
||||
{
|
||||
_titleText.text = context?.Title ?? string.Empty;
|
||||
}
|
||||
|
||||
if (_progressText != null)
|
||||
{
|
||||
_progressText.text = context?.ProgressText ?? string.Empty;
|
||||
}
|
||||
|
||||
if (_currentNodeText != null)
|
||||
{
|
||||
_currentNodeText.text = context?.CurrentNodeText ?? string.Empty;
|
||||
}
|
||||
|
||||
if (_nodeItems == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _nodeItems.Length; i++)
|
||||
{
|
||||
NodeItemContext itemContext =
|
||||
context?.NodeItems != null && i < context.NodeItems.Length ? context.NodeItems[i] : null;
|
||||
_nodeItems[i]?.RefreshUI(itemContext);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnOpen(object userData)
|
||||
{
|
||||
base.OnOpen(userData);
|
||||
|
||||
if (userData is NodeMapFormContext context)
|
||||
{
|
||||
RefreshUI(context);
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Warning("NodeMapForm requires NodeMapFormContext as userData.");
|
||||
}
|
||||
|
||||
protected override void OnClose(bool isShutdown, object userData)
|
||||
{
|
||||
_context = null;
|
||||
if (_titleText != null)
|
||||
{
|
||||
_titleText.text = string.Empty;
|
||||
}
|
||||
|
||||
if (_progressText != null)
|
||||
{
|
||||
_progressText.text = string.Empty;
|
||||
}
|
||||
|
||||
if (_currentNodeText != null)
|
||||
{
|
||||
_currentNodeText.text = string.Empty;
|
||||
}
|
||||
|
||||
if (_nodeItems != null)
|
||||
{
|
||||
for (int i = 0; i < _nodeItems.Length; i++)
|
||||
{
|
||||
_nodeItems[i]?.RefreshUI(null);
|
||||
}
|
||||
}
|
||||
|
||||
base.OnClose(isShutdown, userData);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
using System.Collections.Generic;
|
||||
using GameFramework.ObjectPool;
|
||||
using GeometryTD.CustomEvent;
|
||||
using GeometryTD.Definition;
|
||||
using GeometryTD.PoolObjectBase;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class ParticipantArea : MonoBehaviour, IDropHandler
|
||||
{
|
||||
[SerializeField] private Transform _content;
|
||||
[SerializeField] private TowerRepoItem _towerItemTemplate;
|
||||
[SerializeField] private int _instancePoolCapacity = 8;
|
||||
private bool _isInteractionEnabled = true;
|
||||
|
||||
private readonly List<TowerRepoItem> _activeItems = new List<TowerRepoItem>();
|
||||
private readonly HashSet<long> _boundItemIds = new HashSet<long>();
|
||||
private IObjectPool<TowerRepoItemObject> _itemPool;
|
||||
private string _poolName;
|
||||
private int _maxCount = 4;
|
||||
|
||||
public void OnInit(ParticipantAreaContext context)
|
||||
{
|
||||
OnReset();
|
||||
EnsurePool();
|
||||
|
||||
_maxCount = Mathf.Max(1, context != null ? context.MaxCount : 4);
|
||||
if (context?.TowerItems == null || context.TowerItems.Length <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < context.TowerItems.Length; i++)
|
||||
{
|
||||
TowerRepoItemContext itemContext = context.TowerItems[i];
|
||||
if (itemContext == null || itemContext.InstanceId <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
TowerRepoItem item = CreateOrSpawnItem();
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
item.gameObject.SetActive(true);
|
||||
item.OnInit(itemContext);
|
||||
_activeItems.Add(item);
|
||||
_boundItemIds.Add(itemContext.InstanceId);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnReset()
|
||||
{
|
||||
for (int i = _activeItems.Count - 1; i >= 0; i--)
|
||||
{
|
||||
TowerRepoItem item = _activeItems[i];
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
item.OnReset();
|
||||
item.gameObject.SetActive(false);
|
||||
_itemPool?.Unspawn(item);
|
||||
}
|
||||
|
||||
_activeItems.Clear();
|
||||
_boundItemIds.Clear();
|
||||
_maxCount = 4;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
OnReset();
|
||||
_itemPool?.ReleaseAllUnused();
|
||||
}
|
||||
|
||||
public bool CanAssign(IRepoDragItemView dragItem)
|
||||
{
|
||||
if (!_isInteractionEnabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dragItem == null || dragItem.InstanceId <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dragItem.ComponentSlotType != TowerCompSlotType.None)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_boundItemIds.Contains(dragItem.InstanceId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_boundItemIds.Count >= _maxCount)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnDrop(PointerEventData eventData)
|
||||
{
|
||||
if (!_isInteractionEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (eventData == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject pointerDrag = eventData.pointerDrag;
|
||||
if (pointerDrag == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IRepoDragItemView dragItem = pointerDrag.GetComponent<IRepoDragItemView>() ??
|
||||
pointerDrag.GetComponentInParent<IRepoDragItemView>();
|
||||
if (dragItem == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool assigned = CanAssign(dragItem);
|
||||
dragItem.SetDropResult(assigned);
|
||||
if (!assigned)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameEntry.Event.Fire(this, RepoParticipantAssignRequestedEventArgs.Create(dragItem.InstanceId));
|
||||
}
|
||||
|
||||
public void SetInteractionEnabled(bool enabled)
|
||||
{
|
||||
_isInteractionEnabled = enabled;
|
||||
}
|
||||
|
||||
private void EnsurePool()
|
||||
{
|
||||
if (_itemPool != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_poolName = $"ParticipantTowerRepoItemPool_{GetInstanceID()}";
|
||||
_itemPool =
|
||||
GameEntry.ObjectPool.CreateSingleSpawnObjectPool<TowerRepoItemObject>(_poolName, _instancePoolCapacity);
|
||||
}
|
||||
|
||||
private TowerRepoItem CreateOrSpawnItem()
|
||||
{
|
||||
if (_itemPool == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
TowerRepoItemObject itemObject = _itemPool.Spawn();
|
||||
TowerRepoItem item = itemObject != null ? (TowerRepoItem)itemObject.Target : null;
|
||||
if (item == null)
|
||||
{
|
||||
if (_towerItemTemplate == null)
|
||||
{
|
||||
Log.Warning("ParticipantArea requires a tower item template.");
|
||||
return null;
|
||||
}
|
||||
|
||||
item = Instantiate(_towerItemTemplate);
|
||||
_itemPool.Register(TowerRepoItemObject.Create(item), true);
|
||||
}
|
||||
|
||||
if (_content != null)
|
||||
{
|
||||
item.transform.SetParent(_content, false);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
using GeometryTD.CustomEvent;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class RepoForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private CombineArea _combineArea;
|
||||
[SerializeField] private CompArea _compArea;
|
||||
[SerializeField] private SellArea _sellArea;
|
||||
[SerializeField] private ParticipantArea _participantArea;
|
||||
[SerializeField] private TMP_Text _goldText;
|
||||
[SerializeField] private CommonButton _sellModeButton;
|
||||
[SerializeField] private TMP_Text _sellModeButtonText;
|
||||
|
||||
public void RefreshUI(RepoFormContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RefreshGoldText(context.GoldText);
|
||||
RefreshStateUI(context);
|
||||
|
||||
_combineArea?.OnInit(context.CombineAreaContext);
|
||||
_compArea?.OnInit(context.CompAreaContext);
|
||||
_sellArea?.OnInit(context.SellAreaContext);
|
||||
_participantArea?.OnInit(context.ParticipantAreaContext);
|
||||
|
||||
if (_combineArea != null)
|
||||
{
|
||||
_combineArea.gameObject.SetActive(context.ShowCombineArea);
|
||||
_combineArea.SetInteractionEnabled(context.State == RepoFormState.Assemble);
|
||||
}
|
||||
|
||||
if (_sellArea != null)
|
||||
{
|
||||
_sellArea.gameObject.SetActive(context.ShowSellArea);
|
||||
}
|
||||
|
||||
_participantArea?.SetInteractionEnabled(context.State == RepoFormState.Assemble);
|
||||
}
|
||||
|
||||
public void RefreshGoldText(string goldText)
|
||||
{
|
||||
if (_goldText != null)
|
||||
{
|
||||
_goldText.text = goldText ?? string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryAssignItemToCombineArea(RepoItemContext itemContext)
|
||||
{
|
||||
if (_combineArea == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _combineArea.TryAssignItem(itemContext);
|
||||
}
|
||||
|
||||
public bool TryClearCombineSlot(int slotIndex, out long removedItemId)
|
||||
{
|
||||
removedItemId = 0;
|
||||
if (_combineArea == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _combineArea.TryClearSlot(slotIndex, out removedItemId);
|
||||
}
|
||||
|
||||
public void SetRepoItemSelected(long itemId, bool isSelected)
|
||||
{
|
||||
_compArea?.SetItemSelected(itemId, isSelected);
|
||||
}
|
||||
|
||||
public void RefreshParticipantArea(ParticipantAreaContext context)
|
||||
{
|
||||
_participantArea?.OnInit(context);
|
||||
}
|
||||
|
||||
protected override void OnOpen(object userData)
|
||||
{
|
||||
base.OnOpen(userData);
|
||||
if (userData is RepoFormContext context)
|
||||
{
|
||||
RefreshUI(context);
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Warning("RepoForm requires RepoFormContext as userData.");
|
||||
}
|
||||
|
||||
protected override void OnClose(bool isShutdown, object userData)
|
||||
{
|
||||
if (_goldText != null)
|
||||
{
|
||||
_goldText.text = string.Empty;
|
||||
}
|
||||
|
||||
_combineArea?.OnReset();
|
||||
_compArea?.OnReset();
|
||||
_sellArea?.OnReset();
|
||||
_participantArea?.OnReset();
|
||||
base.OnClose(isShutdown, userData);
|
||||
}
|
||||
|
||||
public void OnReturnButtonClick()
|
||||
{
|
||||
GameEntry.Event.Fire(this, RepoFormReturnEventArgs.Create());
|
||||
}
|
||||
|
||||
public void OnSellModeButtonClick()
|
||||
{
|
||||
GameEntry.Event.Fire(this, RepoSellModeToggleRequestedEventArgs.Create());
|
||||
}
|
||||
|
||||
private void RefreshStateUI(RepoFormContext context)
|
||||
{
|
||||
if (_sellModeButton != null)
|
||||
{
|
||||
_sellModeButton.gameObject.SetActive(context != null && context.ShowSellModeButton);
|
||||
}
|
||||
|
||||
if (_sellModeButtonText != null)
|
||||
{
|
||||
_sellModeButtonText.text = context?.SellModeButtonText ?? "出售模式";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,381 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
using System.Collections.Generic;
|
||||
using GeometryTD.CustomEvent;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class SellArea : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Transform _content;
|
||||
[SerializeField] private RepoItem _itemTemplate;
|
||||
[SerializeField] private TowerRepoItem _towerItemTemplate;
|
||||
[SerializeField] private TMP_Text _totalPrice;
|
||||
|
||||
private readonly List<RepoItem> _activeComponentItems = new List<RepoItem>();
|
||||
private readonly List<TowerRepoItem> _activeTowerItems = new List<TowerRepoItem>();
|
||||
private SellAreaContext _context;
|
||||
|
||||
public void OnInit(SellAreaContext context)
|
||||
{
|
||||
OnReset();
|
||||
_context = context;
|
||||
|
||||
if (_totalPrice != null)
|
||||
{
|
||||
_totalPrice.text = context?.TotalPriceText ?? string.Empty;
|
||||
}
|
||||
|
||||
if (context == null || _content == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.ComponentItems != null)
|
||||
{
|
||||
foreach (RepoItemContext itemContext in context.ComponentItems)
|
||||
{
|
||||
if (itemContext == null || _itemTemplate == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
RepoItem item = Instantiate(_itemTemplate, _content);
|
||||
item.gameObject.SetActive(true);
|
||||
item.OnInit(itemContext);
|
||||
_activeComponentItems.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
if (context.TowerItems != null)
|
||||
{
|
||||
foreach (TowerRepoItemContext itemContext in context.TowerItems)
|
||||
{
|
||||
if (itemContext == null || _towerItemTemplate == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
TowerRepoItem item = Instantiate(_towerItemTemplate, _content);
|
||||
item.gameObject.SetActive(true);
|
||||
item.OnInit(itemContext);
|
||||
_activeTowerItems.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnReset()
|
||||
{
|
||||
for (int i = _activeComponentItems.Count - 1; i >= 0; i--)
|
||||
{
|
||||
RepoItem item = _activeComponentItems[i];
|
||||
if (item != null)
|
||||
{
|
||||
Destroy(item.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = _activeTowerItems.Count - 1; i >= 0; i--)
|
||||
{
|
||||
TowerRepoItem item = _activeTowerItems[i];
|
||||
if (item != null)
|
||||
{
|
||||
Destroy(item.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
_activeComponentItems.Clear();
|
||||
_activeTowerItems.Clear();
|
||||
_context = null;
|
||||
|
||||
if (_totalPrice != null)
|
||||
{
|
||||
_totalPrice.text = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnCancelButtonClick()
|
||||
{
|
||||
GameEntry.Event.Fire(this, RepoSellCancelRequestedEventArgs.Create());
|
||||
}
|
||||
|
||||
public void OnConfirmButtonClick()
|
||||
{
|
||||
if (_context == null || !_context.CanConfirmSell)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameEntry.Event.Fire(this, RepoSellConfirmRequestedEventArgs.Create());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class TowerRepoItem : RepoItem
|
||||
{
|
||||
private static readonly Vector2 DefaultTowerDragGhostSize = new Vector2(64f, 64f);
|
||||
|
||||
public new TowerRepoItemContext Context => base.Context as TowerRepoItemContext;
|
||||
|
||||
public void OnInit(TowerRepoItemContext context)
|
||||
{
|
||||
base.OnInit(context);
|
||||
}
|
||||
|
||||
protected override bool CreateDragGhost()
|
||||
{
|
||||
DestroyDragGhost();
|
||||
|
||||
if (DragRoot == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TowerIconArea towerIconArea = IconArea as TowerIconArea;
|
||||
if (towerIconArea == null)
|
||||
{
|
||||
return base.CreateDragGhost();
|
||||
}
|
||||
|
||||
_dragGhostObject = new GameObject("TowerRepoItemDragGhost", typeof(RectTransform), typeof(CanvasGroup));
|
||||
_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);
|
||||
|
||||
Vector2 iconSize = IconArea != null ? IconArea.CurrentIconSize : Vector2.zero;
|
||||
if (iconSize.x <= 0f || iconSize.y <= 0f)
|
||||
{
|
||||
iconSize = BackgroundImage != null ? BackgroundImage.rectTransform.rect.size : DefaultTowerDragGhostSize;
|
||||
}
|
||||
|
||||
if (iconSize.x <= 0f || iconSize.y <= 0f)
|
||||
{
|
||||
iconSize = DefaultTowerDragGhostSize;
|
||||
}
|
||||
|
||||
_dragGhostRect.sizeDelta = iconSize;
|
||||
|
||||
bool hasAnyLayer = false;
|
||||
hasAnyLayer |= TryCreateLayer("Base", towerIconArea.BaseIconSprite, towerIconArea.BaseIconColor,
|
||||
towerIconArea.BaseIconMaterial, _dragGhostRect, 0);
|
||||
hasAnyLayer |= TryCreateLayer("Bearing", towerIconArea.BearingIconSprite, towerIconArea.BearingIconColor,
|
||||
towerIconArea.BearingIconMaterial, _dragGhostRect, 1);
|
||||
hasAnyLayer |= TryCreateLayer("Muzzle", towerIconArea.MuzzleIconSprite, towerIconArea.MuzzleIconColor,
|
||||
towerIconArea.MuzzleIconMaterial, _dragGhostRect, 2);
|
||||
|
||||
if (!hasAnyLayer)
|
||||
{
|
||||
DestroyDragGhost();
|
||||
return base.CreateDragGhost();
|
||||
}
|
||||
|
||||
CanvasGroup ghostCanvasGroup = _dragGhostObject.GetComponent<CanvasGroup>();
|
||||
ghostCanvasGroup.blocksRaycasts = false;
|
||||
ghostCanvasGroup.interactable = false;
|
||||
|
||||
_dragGhostObject.transform.SetAsLastSibling();
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool TryCreateLayer(
|
||||
string layerName,
|
||||
Sprite sprite,
|
||||
Color color,
|
||||
Material material,
|
||||
RectTransform parent,
|
||||
int siblingIndex)
|
||||
{
|
||||
if (parent == null || sprite == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
GameObject layerObject = new GameObject($"TowerGhost{layerName}", typeof(RectTransform), typeof(Image));
|
||||
layerObject.layer = parent.gameObject.layer;
|
||||
|
||||
RectTransform layerRect = layerObject.GetComponent<RectTransform>();
|
||||
layerRect.SetParent(parent, false);
|
||||
layerRect.anchorMin = Vector2.zero;
|
||||
layerRect.anchorMax = Vector2.one;
|
||||
layerRect.offsetMin = Vector2.zero;
|
||||
layerRect.offsetMax = Vector2.zero;
|
||||
layerRect.SetSiblingIndex(siblingIndex);
|
||||
|
||||
Image layerImage = layerObject.GetComponent<Image>();
|
||||
layerImage.raycastTarget = false;
|
||||
layerImage.sprite = sprite;
|
||||
layerImage.color = color;
|
||||
layerImage.material = material;
|
||||
layerImage.preserveAspect = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user