添加参战防御塔功能(UI)
This commit is contained in:
@@ -129,6 +129,7 @@ namespace GeometryTD.UI
|
||||
InstanceId = tower.InstanceId,
|
||||
CanDrag = false,
|
||||
EnduranceRate01 = ItemDescUtility.ResolveTowerEnduranceRate(tower, muzzleMap, bearingMap, baseMap),
|
||||
ClickActionType = RepoItemClickActionType.OpenDetail,
|
||||
ComponentSlotType = TowerCompSlotType.None,
|
||||
IconAreaContext = BuildIconAreaContext(tower)
|
||||
});
|
||||
@@ -157,6 +158,7 @@ namespace GeometryTD.UI
|
||||
InstanceId = item.InstanceId,
|
||||
CanDrag = false,
|
||||
EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item),
|
||||
ClickActionType = RepoItemClickActionType.OpenDetail,
|
||||
ComponentSlotType = TowerCompSlotType.Muzzle,
|
||||
IconAreaContext = BuildIconAreaContext(item)
|
||||
});
|
||||
@@ -184,6 +186,7 @@ namespace GeometryTD.UI
|
||||
InstanceId = item.InstanceId,
|
||||
CanDrag = false,
|
||||
EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item),
|
||||
ClickActionType = RepoItemClickActionType.OpenDetail,
|
||||
ComponentSlotType = TowerCompSlotType.Bearing,
|
||||
IconAreaContext = BuildIconAreaContext(item)
|
||||
});
|
||||
@@ -212,6 +215,7 @@ namespace GeometryTD.UI
|
||||
InstanceId = item.InstanceId,
|
||||
CanDrag = false,
|
||||
EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item),
|
||||
ClickActionType = RepoItemClickActionType.OpenDetail,
|
||||
ComponentSlotType = TowerCompSlotType.Base,
|
||||
IconAreaContext = BuildIconAreaContext(item)
|
||||
});
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class ParticipantAreaContext : UIContext
|
||||
{
|
||||
public RepoItemContext[] Items;
|
||||
public int MaxCount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dba2ecceff78486fb2a251e7c28ce9c0
|
||||
timeCreated: 1772624131
|
||||
@@ -6,5 +6,6 @@ namespace GeometryTD.UI
|
||||
{
|
||||
public CombineAreaContext CombineAreaContext;
|
||||
public CompAreaContext CompAreaContext;
|
||||
public ParticipantAreaContext ParticipantAreaContext;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public enum RepoItemClickActionType : byte
|
||||
{
|
||||
OpenDetail = 0,
|
||||
RemoveParticipant = 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
fileFormatVersion: 2`nguid: d3f0b6db2f8d4310b1f6c6f61d2075d1`nMonoImporter:`n externalObjects: {}`n serializedVersion: 2`n defaultReferences: []`n executionOrder: 0`n icon: {instanceID: 0}`n userData: `n assetBundleName: `n assetBundleVariant: `n
|
||||
@@ -9,6 +9,7 @@ namespace GeometryTD.UI
|
||||
public long InstanceId;
|
||||
public bool CanDrag;
|
||||
public float EnduranceRate01;
|
||||
public RepoItemClickActionType ClickActionType;
|
||||
public TowerCompSlotType ComponentSlotType;
|
||||
public IconAreaContext IconAreaContext;
|
||||
}
|
||||
|
||||
@@ -11,9 +11,11 @@ namespace GeometryTD.UI
|
||||
{
|
||||
public class RepoFormController : UIFormControllerCommonBase<RepoFormContext, RepoForm>
|
||||
{
|
||||
private const int MaxParticipantCount = 4;
|
||||
private RepoFormUseCase _useCase;
|
||||
private readonly Dictionary<long, RepoItemContext> _itemContextMap = new Dictionary<long, RepoItemContext>();
|
||||
private readonly Dictionary<long, ItemDescSeed> _itemDescSeedMap = new Dictionary<long, ItemDescSeed>();
|
||||
private readonly HashSet<long> _participantTowerIds = new HashSet<long>();
|
||||
|
||||
private sealed class ItemDescSeed
|
||||
{
|
||||
@@ -28,6 +30,7 @@ namespace GeometryTD.UI
|
||||
protected override void RefreshUI(RepoForm form, RepoFormContext context)
|
||||
{
|
||||
form.RefreshUI(context);
|
||||
ApplyParticipantSelection();
|
||||
}
|
||||
|
||||
protected override void SubscribeCustomEvents()
|
||||
@@ -36,6 +39,8 @@ namespace GeometryTD.UI
|
||||
GameEntry.Event.Subscribe(RepoItemDragEndedEventArgs.EventId, OnRepoItemDragEnded);
|
||||
GameEntry.Event.Subscribe(CombineSlotClickedEventArgs.EventId, OnCombineSlotClicked);
|
||||
GameEntry.Event.Subscribe(RepoCombineRequestedEventArgs.EventId, OnRepoCombineRequested);
|
||||
GameEntry.Event.Subscribe(RepoParticipantAssignRequestedEventArgs.EventId, OnRepoParticipantAssignRequested);
|
||||
GameEntry.Event.Subscribe(RepoParticipantRemoveRequestedEventArgs.EventId, OnRepoParticipantRemoveRequested);
|
||||
GameEntry.Event.Subscribe(RepoFormReturnEventArgs.EventId, OnRepoFormReturn);
|
||||
}
|
||||
|
||||
@@ -45,6 +50,8 @@ namespace GeometryTD.UI
|
||||
GameEntry.Event.Unsubscribe(RepoItemDragEndedEventArgs.EventId, OnRepoItemDragEnded);
|
||||
GameEntry.Event.Unsubscribe(CombineSlotClickedEventArgs.EventId, OnCombineSlotClicked);
|
||||
GameEntry.Event.Unsubscribe(RepoCombineRequestedEventArgs.EventId, OnRepoCombineRequested);
|
||||
GameEntry.Event.Unsubscribe(RepoParticipantAssignRequestedEventArgs.EventId, OnRepoParticipantAssignRequested);
|
||||
GameEntry.Event.Unsubscribe(RepoParticipantRemoveRequestedEventArgs.EventId, OnRepoParticipantRemoveRequested);
|
||||
GameEntry.Event.Unsubscribe(RepoFormReturnEventArgs.EventId, OnRepoFormReturn);
|
||||
}
|
||||
|
||||
@@ -99,12 +106,14 @@ namespace GeometryTD.UI
|
||||
_itemDescSeedMap.Clear();
|
||||
if (rawData?.Inventory == null)
|
||||
{
|
||||
_participantTowerIds.Clear();
|
||||
return null;
|
||||
}
|
||||
|
||||
Dictionary<long, MuzzleCompItemData> muzzleMap = BuildComponentMap(rawData.Inventory.MuzzleComponents);
|
||||
Dictionary<long, BearingCompItemData> bearingMap = BuildComponentMap(rawData.Inventory.BearingComponents);
|
||||
Dictionary<long, BaseCompItemData> baseMap = BuildComponentMap(rawData.Inventory.BaseComponents);
|
||||
Dictionary<long, TowerItemData> towerMap = BuildTowerMap(rawData.Inventory.Towers);
|
||||
List<RepoItemContext> items = new List<RepoItemContext>();
|
||||
|
||||
if (rawData.Inventory.Towers != null)
|
||||
@@ -121,6 +130,7 @@ namespace GeometryTD.UI
|
||||
InstanceId = tower.InstanceId,
|
||||
CanDrag = true,
|
||||
EnduranceRate01 = ItemDescUtility.ResolveTowerEnduranceRate(tower, muzzleMap, bearingMap, baseMap),
|
||||
ClickActionType = RepoItemClickActionType.OpenDetail,
|
||||
ComponentSlotType = TowerCompSlotType.None,
|
||||
IconAreaContext = BuildIconAreaContext(tower)
|
||||
});
|
||||
@@ -147,6 +157,7 @@ namespace GeometryTD.UI
|
||||
InstanceId = item.InstanceId,
|
||||
CanDrag = true,
|
||||
EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item),
|
||||
ClickActionType = RepoItemClickActionType.OpenDetail,
|
||||
ComponentSlotType = TowerCompSlotType.Muzzle,
|
||||
IconAreaContext = BuildIconAreaContext(item)
|
||||
});
|
||||
@@ -173,6 +184,7 @@ namespace GeometryTD.UI
|
||||
InstanceId = item.InstanceId,
|
||||
CanDrag = true,
|
||||
EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item),
|
||||
ClickActionType = RepoItemClickActionType.OpenDetail,
|
||||
ComponentSlotType = TowerCompSlotType.Bearing,
|
||||
IconAreaContext = BuildIconAreaContext(item)
|
||||
});
|
||||
@@ -199,6 +211,7 @@ namespace GeometryTD.UI
|
||||
InstanceId = item.InstanceId,
|
||||
CanDrag = true,
|
||||
EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item),
|
||||
ClickActionType = RepoItemClickActionType.OpenDetail,
|
||||
ComponentSlotType = TowerCompSlotType.Base,
|
||||
IconAreaContext = BuildIconAreaContext(item)
|
||||
});
|
||||
@@ -211,13 +224,17 @@ namespace GeometryTD.UI
|
||||
}
|
||||
}
|
||||
|
||||
ParticipantAreaContext participantAreaContext =
|
||||
BuildParticipantAreaContext(rawData.Inventory, towerMap, muzzleMap, bearingMap, baseMap);
|
||||
|
||||
return new RepoFormContext
|
||||
{
|
||||
CombineAreaContext = new CombineAreaContext(),
|
||||
CompAreaContext = new CompAreaContext
|
||||
{
|
||||
Items = items.ToArray()
|
||||
}
|
||||
},
|
||||
ParticipantAreaContext = participantAreaContext
|
||||
};
|
||||
}
|
||||
|
||||
@@ -288,6 +305,112 @@ namespace GeometryTD.UI
|
||||
return map;
|
||||
}
|
||||
|
||||
private static Dictionary<long, TowerItemData> BuildTowerMap(IReadOnlyList<TowerItemData> towers)
|
||||
{
|
||||
Dictionary<long, TowerItemData> map = new Dictionary<long, TowerItemData>();
|
||||
if (towers == null)
|
||||
{
|
||||
return map;
|
||||
}
|
||||
|
||||
for (int i = 0; i < towers.Count; i++)
|
||||
{
|
||||
TowerItemData tower = towers[i];
|
||||
if (tower == null || tower.InstanceId <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
map[tower.InstanceId] = tower;
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
private ParticipantAreaContext BuildParticipantAreaContext(
|
||||
BackpackInventoryData inventory,
|
||||
IReadOnlyDictionary<long, TowerItemData> towerMap,
|
||||
IReadOnlyDictionary<long, MuzzleCompItemData> muzzleMap,
|
||||
IReadOnlyDictionary<long, BearingCompItemData> bearingMap,
|
||||
IReadOnlyDictionary<long, BaseCompItemData> baseMap)
|
||||
{
|
||||
_participantTowerIds.Clear();
|
||||
List<RepoItemContext> participantItems = new List<RepoItemContext>();
|
||||
if (inventory?.ParticipantTowerInstanceIds != null && towerMap != null)
|
||||
{
|
||||
for (int i = 0; i < inventory.ParticipantTowerInstanceIds.Count; i++)
|
||||
{
|
||||
long towerId = inventory.ParticipantTowerInstanceIds[i];
|
||||
if (towerId <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!towerMap.TryGetValue(towerId, out TowerItemData tower) || tower == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_participantTowerIds.Add(towerId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
participantItems.Add(new RepoItemContext
|
||||
{
|
||||
InstanceId = tower.InstanceId,
|
||||
CanDrag = false,
|
||||
EnduranceRate01 = ItemDescUtility.ResolveTowerEnduranceRate(tower, muzzleMap, bearingMap, baseMap),
|
||||
ClickActionType = RepoItemClickActionType.RemoveParticipant,
|
||||
ComponentSlotType = TowerCompSlotType.None,
|
||||
IconAreaContext = BuildIconAreaContext(tower)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return new ParticipantAreaContext
|
||||
{
|
||||
Items = participantItems.ToArray(),
|
||||
MaxCount = MaxParticipantCount
|
||||
};
|
||||
}
|
||||
|
||||
private void ApplyParticipantSelection()
|
||||
{
|
||||
if (Form == null || _itemContextMap.Count <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<long, RepoItemContext> pair in _itemContextMap)
|
||||
{
|
||||
RepoItemContext itemContext = pair.Value;
|
||||
if (itemContext == null || itemContext.ComponentSlotType != TowerCompSlotType.None)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Form.SetRepoItemSelected(pair.Key, _participantTowerIds.Contains(pair.Key));
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshParticipantAreaOnly()
|
||||
{
|
||||
if (_useCase == null || Form == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RepoFormContext latestContext = BuildContext(_useCase.CreateInitialModel());
|
||||
if (latestContext?.ParticipantAreaContext == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Form.RefreshParticipantArea(latestContext.ParticipantAreaContext);
|
||||
ApplyParticipantSelection();
|
||||
}
|
||||
|
||||
private static IconAreaContext BuildIconAreaContext(TowerItemData tower)
|
||||
{
|
||||
if (tower == null)
|
||||
@@ -447,9 +570,60 @@ namespace GeometryTD.UI
|
||||
if (latestContext != null)
|
||||
{
|
||||
Form.RefreshUI(latestContext);
|
||||
ApplyParticipantSelection();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRepoParticipantAssignRequested(object sender, GameEventArgs e)
|
||||
{
|
||||
if (!IsEventFromCurrentForm(sender))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(e is RepoParticipantAssignRequestedEventArgs args))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_useCase == null || Form == null || args.TowerItemId <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_useCase.TryAddParticipantTower(args.TowerItemId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RefreshParticipantAreaOnly();
|
||||
}
|
||||
|
||||
private void OnRepoParticipantRemoveRequested(object sender, GameEventArgs e)
|
||||
{
|
||||
if (!IsEventFromCurrentForm(sender))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(e is RepoParticipantRemoveRequestedEventArgs args))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_useCase == null || Form == null || args.TowerItemId <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_useCase.TryRemoveParticipantTower(args.TowerItemId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RefreshParticipantAreaOnly();
|
||||
}
|
||||
|
||||
private bool IsEventFromCurrentForm(object sender)
|
||||
{
|
||||
if (Form == null)
|
||||
|
||||
@@ -4,11 +4,14 @@ namespace GeometryTD.UI
|
||||
{
|
||||
public class RepoFormUseCase : IUIUseCase
|
||||
{
|
||||
private const int MaxParticipantCount = 4;
|
||||
private BackpackInventoryData _fallbackInventory;
|
||||
|
||||
public RepoFormRawData CreateInitialModel()
|
||||
{
|
||||
BackpackInventoryData sample = GameEntry.PlayerInventory != null
|
||||
? GameEntry.PlayerInventory.GetInventorySnapshot()
|
||||
: SampleInventory();
|
||||
: GetOrCreateFallbackInventory();
|
||||
return new RepoFormRawData
|
||||
{
|
||||
Inventory = sample
|
||||
@@ -29,6 +32,169 @@ namespace GeometryTD.UI
|
||||
out _);
|
||||
}
|
||||
|
||||
public bool TryAddParticipantTower(long towerItemId)
|
||||
{
|
||||
if (GameEntry.PlayerInventory == null)
|
||||
{
|
||||
BackpackInventoryData fallbackInventory = GetOrCreateFallbackInventory();
|
||||
return TryAddParticipantTowerInternal(fallbackInventory, towerItemId, MaxParticipantCount);
|
||||
}
|
||||
|
||||
return GameEntry.PlayerInventory.TryAddParticipantTower(towerItemId, 4);
|
||||
}
|
||||
|
||||
public bool TryRemoveParticipantTower(long towerItemId)
|
||||
{
|
||||
if (GameEntry.PlayerInventory == null)
|
||||
{
|
||||
BackpackInventoryData fallbackInventory = GetOrCreateFallbackInventory();
|
||||
return TryRemoveParticipantTowerInternal(fallbackInventory, towerItemId);
|
||||
}
|
||||
|
||||
return GameEntry.PlayerInventory.TryRemoveParticipantTower(towerItemId);
|
||||
}
|
||||
|
||||
private BackpackInventoryData GetOrCreateFallbackInventory()
|
||||
{
|
||||
_fallbackInventory ??= SampleInventory();
|
||||
NormalizeParticipantState(_fallbackInventory);
|
||||
return _fallbackInventory;
|
||||
}
|
||||
|
||||
private static bool TryAddParticipantTowerInternal(
|
||||
BackpackInventoryData inventory,
|
||||
long towerItemId,
|
||||
int maxCount)
|
||||
{
|
||||
if (inventory == null || towerItemId <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
NormalizeParticipantState(inventory);
|
||||
if (!TryGetTowerById(inventory, towerItemId, out TowerItemData tower))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
inventory.ParticipantTowerInstanceIds ??= new System.Collections.Generic.List<long>();
|
||||
if (inventory.ParticipantTowerInstanceIds.Contains(towerItemId))
|
||||
{
|
||||
tower.IsParticipatingInCombat = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (inventory.ParticipantTowerInstanceIds.Count >= UnityEngine.Mathf.Max(1, maxCount))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
inventory.ParticipantTowerInstanceIds.Add(towerItemId);
|
||||
tower.IsParticipatingInCombat = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool TryRemoveParticipantTowerInternal(BackpackInventoryData inventory, long towerItemId)
|
||||
{
|
||||
if (inventory == null || towerItemId <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
NormalizeParticipantState(inventory);
|
||||
if (inventory.ParticipantTowerInstanceIds == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool removed = inventory.ParticipantTowerInstanceIds.Remove(towerItemId);
|
||||
if (!removed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TryGetTowerById(inventory, towerItemId, out TowerItemData tower))
|
||||
{
|
||||
tower.IsParticipatingInCombat = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool TryGetTowerById(BackpackInventoryData inventory, long towerItemId, out TowerItemData tower)
|
||||
{
|
||||
tower = null;
|
||||
if (inventory?.Towers == null || towerItemId <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < inventory.Towers.Count; i++)
|
||||
{
|
||||
TowerItemData candidate = inventory.Towers[i];
|
||||
if (candidate != null && candidate.InstanceId == towerItemId)
|
||||
{
|
||||
tower = candidate;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void NormalizeParticipantState(BackpackInventoryData inventory)
|
||||
{
|
||||
if (inventory == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
inventory.ParticipantTowerInstanceIds ??= new System.Collections.Generic.List<long>();
|
||||
System.Collections.Generic.Dictionary<long, TowerItemData> towerMap =
|
||||
new System.Collections.Generic.Dictionary<long, TowerItemData>();
|
||||
if (inventory.Towers != null)
|
||||
{
|
||||
for (int i = 0; i < inventory.Towers.Count; i++)
|
||||
{
|
||||
TowerItemData tower = inventory.Towers[i];
|
||||
if (tower == null || tower.InstanceId <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
tower.IsParticipatingInCombat = false;
|
||||
towerMap[tower.InstanceId] = tower;
|
||||
}
|
||||
}
|
||||
|
||||
System.Collections.Generic.HashSet<long> uniqueIds = new System.Collections.Generic.HashSet<long>();
|
||||
System.Collections.Generic.List<long> normalizedIds =
|
||||
new System.Collections.Generic.List<long>(inventory.ParticipantTowerInstanceIds.Count);
|
||||
for (int i = 0; i < inventory.ParticipantTowerInstanceIds.Count; i++)
|
||||
{
|
||||
if (normalizedIds.Count >= MaxParticipantCount)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
long towerId = inventory.ParticipantTowerInstanceIds[i];
|
||||
if (towerId <= 0 || !uniqueIds.Add(towerId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!towerMap.TryGetValue(towerId, out TowerItemData tower))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
tower.IsParticipatingInCombat = true;
|
||||
normalizedIds.Add(towerId);
|
||||
}
|
||||
|
||||
inventory.ParticipantTowerInstanceIds = normalizedIds;
|
||||
}
|
||||
|
||||
public static BackpackInventoryData SampleInventory()
|
||||
{
|
||||
BackpackInventoryData inventory = new BackpackInventoryData
|
||||
@@ -167,6 +333,7 @@ namespace GeometryTD.UI
|
||||
InstanceId = 90001,
|
||||
Name = "测试防御塔-A",
|
||||
Rarity = RarityType.Green,
|
||||
IsParticipatingInCombat = true,
|
||||
MuzzleComponentInstanceId = muzzle.InstanceId,
|
||||
BearingComponentInstanceId = bearing.InstanceId,
|
||||
BaseComponentInstanceId = baseComp.InstanceId,
|
||||
@@ -189,6 +356,7 @@ namespace GeometryTD.UI
|
||||
InstanceId = 90002,
|
||||
Name = "测试防御塔-B",
|
||||
Rarity = RarityType.Blue,
|
||||
IsParticipatingInCombat = false,
|
||||
MuzzleComponentInstanceId = 0,
|
||||
BearingComponentInstanceId = 0,
|
||||
BaseComponentInstanceId = 0,
|
||||
@@ -205,6 +373,8 @@ namespace GeometryTD.UI
|
||||
}
|
||||
});
|
||||
|
||||
inventory.ParticipantTowerInstanceIds.Add(90001);
|
||||
|
||||
return inventory;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>();
|
||||
|
||||
Reference in New Issue
Block a user