添加参战防御塔功能(UI)

This commit is contained in:
SepComet
2026-03-04 20:36:05 +08:00
parent 298345fa17
commit a62309e8c1
25 changed files with 1160 additions and 20 deletions
@@ -0,0 +1,177 @@
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 RepoItem _itemTemplate;
[SerializeField] private int _instancePoolCapacity = 8;
private readonly List<RepoItem> _activeItems = new List<RepoItem>();
private readonly HashSet<long> _boundItemIds = new HashSet<long>();
private IObjectPool<RepoItemObject> _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?.Items == null || context.Items.Length <= 0)
{
return;
}
for (int i = 0; i < context.Items.Length; i++)
{
RepoItemContext itemContext = context.Items[i];
if (itemContext == null || itemContext.InstanceId <= 0)
{
continue;
}
RepoItem 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--)
{
RepoItem 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(RepoItemContext itemContext)
{
if (itemContext == null || itemContext.InstanceId <= 0)
{
return false;
}
if (itemContext.ComponentSlotType != TowerCompSlotType.None)
{
return false;
}
if (_boundItemIds.Contains(itemContext.InstanceId))
{
return false;
}
if (_boundItemIds.Count >= _maxCount)
{
return false;
}
return true;
}
public void OnDrop(PointerEventData eventData)
{
if (eventData == null)
{
return;
}
GameObject pointerDrag = eventData.pointerDrag;
if (pointerDrag == null)
{
return;
}
RepoItem repoItem = pointerDrag.GetComponent<RepoItem>() ?? pointerDrag.GetComponentInParent<RepoItem>();
if (repoItem == null)
{
return;
}
RepoItemContext itemContext = repoItem.Context;
bool assigned = CanAssign(itemContext);
repoItem.SetDropResult(assigned);
if (!assigned)
{
return;
}
GameEntry.Event.Fire(this, RepoParticipantAssignRequestedEventArgs.Create(itemContext.InstanceId));
}
private void EnsurePool()
{
if (_itemPool != null)
{
return;
}
_poolName = $"ParticipantRepoItemPool_{GetInstanceID()}";
_itemPool = GameEntry.ObjectPool.CreateSingleSpawnObjectPool<RepoItemObject>(_poolName, _instancePoolCapacity);
}
private RepoItem CreateOrSpawnItem()
{
if (_itemPool == null)
{
return null;
}
RepoItemObject itemObject = _itemPool.Spawn();
RepoItem item = itemObject != null ? (RepoItem)itemObject.Target : null;
if (item == null)
{
if (_itemTemplate == null)
{
Log.Warning("ParticipantArea requires an item template.");
return null;
}
item = Instantiate(_itemTemplate);
_itemPool.Register(RepoItemObject.Create(item), true);
}
if (_content != null)
{
item.transform.SetParent(_content, false);
}
return item;
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 23b62a700198440baabc75e28f901578
timeCreated: 1772624093
@@ -7,7 +7,10 @@ namespace GeometryTD.UI
public class RepoForm : UGuiForm
{
[SerializeField] private CombineArea _combineArea;
[SerializeField] private CompArea _compArea;
[SerializeField] private ParticipantArea _participantArea;
public void RefreshUI(RepoFormContext context)
{
@@ -18,6 +21,7 @@ namespace GeometryTD.UI
_combineArea?.OnInit(context.CombineAreaContext);
_compArea?.OnInit(context.CompAreaContext);
_participantArea?.OnInit(context.ParticipantAreaContext);
}
public bool TryAssignItemToCombineArea(RepoItemContext itemContext)
@@ -46,6 +50,11 @@ namespace GeometryTD.UI
_compArea?.SetItemSelected(itemId, isSelected);
}
public void RefreshParticipantArea(ParticipantAreaContext context)
{
_participantArea?.OnInit(context);
}
protected override void OnOpen(object userData)
{
base.OnOpen(userData);
@@ -62,6 +71,7 @@ namespace GeometryTD.UI
{
_combineArea?.OnReset();
_compArea?.OnReset();
_participantArea?.OnReset();
base.OnClose(isShutdown, userData);
}
@@ -70,4 +80,4 @@ namespace GeometryTD.UI
GameEntry.Event.Fire(this, RepoFormReturnEventArgs.Create());
}
}
}
}
@@ -108,6 +108,12 @@ namespace GeometryTD.UI
return;
}
if (_context.ClickActionType == RepoItemClickActionType.RemoveParticipant)
{
GameEntry.Event.Fire(this, RepoParticipantRemoveRequestedEventArgs.Create(_context.InstanceId));
return;
}
StartPendingOpenDetail();
}
@@ -195,7 +201,12 @@ namespace GeometryTD.UI
private bool CanStartDrag(PointerEventData eventData)
{
if (_context == null || _isSelected || _isDragging)
if (_context == null || _isDragging)
{
return false;
}
if (_isSelected && _context.ComponentSlotType != TowerCompSlotType.None)
{
return false;
}
@@ -205,11 +216,6 @@ namespace GeometryTD.UI
return false;
}
if (_context.ComponentSlotType == TowerCompSlotType.None)
{
return false;
}
if (eventData == null || eventData.button != PointerEventData.InputButton.Left)
{
return false;
@@ -292,12 +298,25 @@ namespace GeometryTD.UI
{
DestroyDragGhost();
if (_dragRoot == null || _iconArea == null)
if (_dragRoot == null)
{
return false;
}
Sprite iconSprite = _iconArea.CurrentIconSprite;
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;
@@ -312,7 +331,6 @@ namespace GeometryTD.UI
_dragGhostRect.anchorMax = new Vector2(0.5f, 0.5f);
_dragGhostRect.pivot = new Vector2(0.5f, 0.5f);
Vector2 iconSize = _iconArea.CurrentIconSize;
if (iconSize.x <= 0f || iconSize.y <= 0f)
{
iconSize = DefaultDragGhostSize;
@@ -322,8 +340,8 @@ namespace GeometryTD.UI
Image ghostImage = _dragGhostObject.GetComponent<Image>();
ghostImage.raycastTarget = false;
ghostImage.sprite = iconSprite;
ghostImage.color = _iconArea.CurrentIconColor;
ghostImage.material = _iconArea.CurrentIconMaterial;
ghostImage.color = iconColor;
ghostImage.material = iconMaterial;
ghostImage.preserveAspect = true;
CanvasGroup ghostCanvasGroup = _dragGhostObject.GetComponent<CanvasGroup>();