补充参战防御塔进入战斗逻辑
- 将 Inventory 中参战的防御塔数据传递到 CombatSelectForm 中 - 为防御塔的图标展示添加 TowerRepoItem 与 TowerIconArea 适配防御塔的三层 Image
This commit is contained in:
@@ -10,5 +10,6 @@ namespace GeometryTD.UI
|
||||
public bool IsInteractable;
|
||||
public CombatSelectActionType ActionType;
|
||||
public int ActionIndex;
|
||||
public TowerIconAreaContext TowerIconAreaContext;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,9 +116,8 @@ namespace GeometryTD.UI
|
||||
|
||||
if (inventory.Towers != null)
|
||||
{
|
||||
for (int i = 0; i < inventory.Towers.Count; i++)
|
||||
foreach (TowerItemData tower in inventory.Towers)
|
||||
{
|
||||
var tower = inventory.Towers[i];
|
||||
if (tower == null)
|
||||
{
|
||||
continue;
|
||||
@@ -131,7 +130,7 @@ namespace GeometryTD.UI
|
||||
EnduranceRate01 = ItemDescUtility.ResolveTowerEnduranceRate(tower, muzzleMap, bearingMap, baseMap),
|
||||
ClickActionType = RepoItemClickActionType.OpenDetail,
|
||||
ComponentSlotType = TowerCompSlotType.None,
|
||||
IconAreaContext = BuildIconAreaContext(tower)
|
||||
IconAreaContext = BuildTowerIconContext(tower, muzzleMap, bearingMap, baseMap)
|
||||
});
|
||||
|
||||
AddItemDescSeed(
|
||||
@@ -145,9 +144,8 @@ namespace GeometryTD.UI
|
||||
|
||||
if (inventory.MuzzleComponents != null)
|
||||
{
|
||||
for (int i = 0; i < inventory.MuzzleComponents.Count; i++)
|
||||
foreach (MuzzleCompItemData item in inventory.MuzzleComponents)
|
||||
{
|
||||
var item = inventory.MuzzleComponents[i];
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
@@ -174,7 +172,7 @@ namespace GeometryTD.UI
|
||||
|
||||
if (inventory.BearingComponents != null)
|
||||
{
|
||||
foreach (var item in inventory.BearingComponents)
|
||||
foreach (BearingCompItemData item in inventory.BearingComponents)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
@@ -202,9 +200,8 @@ namespace GeometryTD.UI
|
||||
|
||||
if (inventory.BaseComponents != null)
|
||||
{
|
||||
for (int i = 0; i < inventory.BaseComponents.Count; i++)
|
||||
foreach (BaseCompItemData item in inventory.BaseComponents)
|
||||
{
|
||||
var item = inventory.BaseComponents[i];
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
@@ -232,6 +229,38 @@ namespace GeometryTD.UI
|
||||
return itemContexts.ToArray();
|
||||
}
|
||||
|
||||
private static TowerIconAreaContext BuildTowerIconContext(
|
||||
TowerItemData tower,
|
||||
IReadOnlyDictionary<long, MuzzleCompItemData> muzzleMap,
|
||||
IReadOnlyDictionary<long, BearingCompItemData> bearingMap,
|
||||
IReadOnlyDictionary<long, BaseCompItemData> baseMap)
|
||||
{
|
||||
if (tower == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new TowerIconAreaContext
|
||||
{
|
||||
Rarity = tower.Rarity,
|
||||
MuzzleColor = ResolveComponentColor(tower.MuzzleComponentInstanceId, muzzleMap),
|
||||
BearingColor = ResolveComponentColor(tower.BearingComponentInstanceId, bearingMap),
|
||||
BaseColor = ResolveComponentColor(tower.BaseComponentInstanceId, baseMap)
|
||||
};
|
||||
}
|
||||
|
||||
private static Color ResolveComponentColor<TComp>(long instanceId, IReadOnlyDictionary<long, TComp> componentMap)
|
||||
where TComp : TowerCompItemData
|
||||
{
|
||||
if (instanceId > 0 && componentMap != null && componentMap.TryGetValue(instanceId, out TComp comp) &&
|
||||
comp != null)
|
||||
{
|
||||
return IconColorGenerator.GenerateForComponent(comp);
|
||||
}
|
||||
|
||||
return Color.white;
|
||||
}
|
||||
|
||||
private void AddItemDescSeed(long itemId, string title, string typeText, string description, TagType[] tags)
|
||||
{
|
||||
if (itemId <= 0)
|
||||
@@ -274,9 +303,8 @@ namespace GeometryTD.UI
|
||||
return map;
|
||||
}
|
||||
|
||||
for (int i = 0; i < items.Count; i++)
|
||||
foreach (TComp item in items)
|
||||
{
|
||||
TComp item = items[i];
|
||||
if (item == null || item.InstanceId <= 0)
|
||||
{
|
||||
continue;
|
||||
@@ -288,35 +316,13 @@ namespace GeometryTD.UI
|
||||
return map;
|
||||
}
|
||||
|
||||
private static IconAreaContext BuildIconAreaContext(TowerItemData tower)
|
||||
{
|
||||
if (tower == null)
|
||||
{
|
||||
return new IconAreaContext
|
||||
{
|
||||
ComponentSlotType = TowerCompSlotType.None,
|
||||
Rarity = RarityType.None,
|
||||
Color = Color.white,
|
||||
Icon = null
|
||||
};
|
||||
}
|
||||
|
||||
return new IconAreaContext
|
||||
{
|
||||
ComponentSlotType = TowerCompSlotType.None,
|
||||
Rarity = tower.Rarity,
|
||||
Color = IconColorGenerator.GenerateForTower(tower),
|
||||
Icon = null
|
||||
};
|
||||
}
|
||||
|
||||
private static IconAreaContext BuildIconAreaContext(TowerCompItemData item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return new IconAreaContext
|
||||
{
|
||||
ComponentSlotType = TowerCompSlotType.None,
|
||||
ComponentSlotType = TowerCompSlotType.None,
|
||||
Rarity = RarityType.None,
|
||||
Color = Color.white,
|
||||
Icon = null
|
||||
@@ -332,6 +338,8 @@ namespace GeometryTD.UI
|
||||
};
|
||||
}
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
private void OnCombatFinishReturnButtonClicked(object sender, GameEventArgs e)
|
||||
{
|
||||
if (!IsEventFromCurrentForm(sender) || !(e is CombatFinishReturnEventArgs))
|
||||
@@ -370,6 +378,8 @@ namespace GeometryTD.UI
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private bool IsEventFromCurrentForm(object sender)
|
||||
{
|
||||
if (Form == null)
|
||||
@@ -392,3 +402,7 @@ namespace GeometryTD.UI
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -229,7 +229,13 @@ namespace GeometryTD.UI
|
||||
IsVisible = rawData.IsVisible,
|
||||
IsInteractable = rawData.IsInteractable,
|
||||
ActionType = rawData.ActionType,
|
||||
ActionIndex = rawData.ActionIndex
|
||||
ActionIndex = rawData.ActionIndex,
|
||||
TowerIconAreaContext = new TowerIconAreaContext()
|
||||
{
|
||||
BaseColor = rawData.BaseColor,
|
||||
BearingColor = rawData.BearingColor,
|
||||
MuzzleColor = rawData.MuzzleColor
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -284,4 +290,4 @@ namespace GeometryTD.UI
|
||||
RefreshFromUseCase();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,5 +11,9 @@ namespace GeometryTD.UI
|
||||
public bool IsInteractable;
|
||||
public CombatSelectActionType ActionType;
|
||||
public int ActionIndex;
|
||||
public bool UseTowerLayers;
|
||||
public Color BaseColor = Color.white;
|
||||
public Color BearingColor = Color.white;
|
||||
public Color MuzzleColor = Color.white;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,19 @@ namespace GeometryTD.UI
|
||||
}
|
||||
|
||||
public void SetBuildAction(int buildIndex, Func<bool> buildAction, int cost, Sprite icon = null)
|
||||
{
|
||||
SetBuildAction(buildIndex, buildAction, cost, icon, false, Color.white, Color.white, Color.white);
|
||||
}
|
||||
|
||||
public void SetBuildAction(
|
||||
int buildIndex,
|
||||
Func<bool> buildAction,
|
||||
int cost,
|
||||
Sprite icon,
|
||||
bool useTowerLayers,
|
||||
Color baseColor,
|
||||
Color bearingColor,
|
||||
Color muzzleColor)
|
||||
{
|
||||
if (buildIndex < 0 || buildIndex >= _buildOptions.Length)
|
||||
{
|
||||
@@ -54,6 +67,10 @@ namespace GeometryTD.UI
|
||||
option.Icon = icon;
|
||||
option.IsGain = false;
|
||||
option.IsVisible = true;
|
||||
option.UseTowerLayers = useTowerLayers;
|
||||
option.BaseColor = baseColor;
|
||||
option.BearingColor = bearingColor;
|
||||
option.MuzzleColor = muzzleColor;
|
||||
}
|
||||
|
||||
public void SetBuildAction(int buildIndex, Action buildAction, int cost, Sprite icon = null)
|
||||
@@ -75,6 +92,16 @@ namespace GeometryTD.UI
|
||||
icon);
|
||||
}
|
||||
|
||||
public void SetBuildVisible(int buildIndex, bool visible)
|
||||
{
|
||||
if (buildIndex < 0 || buildIndex >= _buildOptions.Length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_buildOptions[buildIndex].IsVisible = visible;
|
||||
}
|
||||
|
||||
public void SetUpgradeAction(Func<bool> upgradeAction, int cost, Sprite icon = null)
|
||||
{
|
||||
_upgradeOption.Action = upgradeAction;
|
||||
@@ -82,6 +109,7 @@ namespace GeometryTD.UI
|
||||
_upgradeOption.Icon = icon;
|
||||
_upgradeOption.IsGain = false;
|
||||
_upgradeOption.IsVisible = true;
|
||||
_upgradeOption.UseTowerLayers = false;
|
||||
}
|
||||
|
||||
public void SetUpgradeAction(Action upgradeAction, int cost, Sprite icon = null)
|
||||
@@ -109,6 +137,7 @@ namespace GeometryTD.UI
|
||||
_destroyOption.Icon = icon;
|
||||
_destroyOption.IsGain = true;
|
||||
_destroyOption.IsVisible = true;
|
||||
_destroyOption.UseTowerLayers = false;
|
||||
}
|
||||
|
||||
public void SetDestroyAction(Action destroyAction, int gain, Sprite icon = null)
|
||||
@@ -278,7 +307,11 @@ namespace GeometryTD.UI
|
||||
IsVisible = option.IsVisible,
|
||||
IsInteractable = option.Action != null && CanExecute(option, currentCoin),
|
||||
ActionType = option.ActionType,
|
||||
ActionIndex = option.ActionIndex
|
||||
ActionIndex = option.ActionIndex,
|
||||
UseTowerLayers = option.UseTowerLayers,
|
||||
BaseColor = option.BaseColor,
|
||||
BearingColor = option.BearingColor,
|
||||
MuzzleColor = option.MuzzleColor
|
||||
};
|
||||
}
|
||||
|
||||
@@ -293,6 +326,10 @@ namespace GeometryTD.UI
|
||||
public bool IsVisible = true;
|
||||
public Sprite Icon;
|
||||
public Func<bool> Action;
|
||||
public bool UseTowerLayers;
|
||||
public Color BaseColor = Color.white;
|
||||
public Color BearingColor = Color.white;
|
||||
public Color MuzzleColor = Color.white;
|
||||
|
||||
public Option(CombatSelectActionType actionType, int actionIndex, bool requiresAffordable)
|
||||
{
|
||||
|
||||
@@ -2,20 +2,23 @@ using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using GeometryTD.CustomEvent;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class TowerSelectItem : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Image _icon;
|
||||
|
||||
|
||||
[SerializeField] private TMP_Text _price;
|
||||
|
||||
|
||||
[SerializeField] private CommonButton _button;
|
||||
|
||||
|
||||
[SerializeField] private TowerIconArea _towerIconArea;
|
||||
|
||||
private TowerSelectItemContext _context;
|
||||
|
||||
private Sprite _defaultIcon;
|
||||
|
||||
private bool _hasCachedDefaultIcon;
|
||||
|
||||
public void OnInit(TowerSelectItemContext context)
|
||||
@@ -23,28 +26,45 @@ namespace GeometryTD.UI
|
||||
CacheDefaultIcon();
|
||||
_context = context;
|
||||
|
||||
if (_icon != null)
|
||||
if (context.ActionType == CombatSelectActionType.BuildTower)
|
||||
{
|
||||
if (context != null && context.Icon != null)
|
||||
_icon?.gameObject.SetActive(false);
|
||||
_towerIconArea?.OnInit(_context.TowerIconAreaContext);
|
||||
|
||||
if (_price != null)
|
||||
{
|
||||
_icon.sprite = context.Icon;
|
||||
}
|
||||
else if (_defaultIcon != null)
|
||||
{
|
||||
_icon.sprite = _defaultIcon;
|
||||
_price.text = context.PriceText ?? string.Empty;
|
||||
}
|
||||
|
||||
_icon.enabled = _icon.sprite != null;
|
||||
if (_button != null)
|
||||
{
|
||||
_button.Interactive = context.IsInteractable;
|
||||
}
|
||||
}
|
||||
|
||||
if (_price != null)
|
||||
else if (context.ActionType is CombatSelectActionType.UpgradeTower or CombatSelectActionType.DestroyTower)
|
||||
{
|
||||
_price.text = context?.PriceText ?? string.Empty;
|
||||
if (_icon != null)
|
||||
{
|
||||
_icon.sprite = _context.Icon ?? _defaultIcon;
|
||||
_icon.gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
_towerIconArea?.OnReset();
|
||||
|
||||
if (_price != null)
|
||||
{
|
||||
_price.text = context.PriceText ?? string.Empty;
|
||||
}
|
||||
|
||||
if (_button != null)
|
||||
{
|
||||
_button.Interactive = context.IsInteractable;
|
||||
}
|
||||
}
|
||||
|
||||
if (_button != null)
|
||||
else
|
||||
{
|
||||
_button.Interactive = context != null && context.IsInteractable;
|
||||
_icon?.gameObject.SetActive(false);
|
||||
_towerIconArea?.OnReset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +79,8 @@ namespace GeometryTD.UI
|
||||
_icon.enabled = _icon.sprite != null;
|
||||
}
|
||||
|
||||
_towerIconArea.OnReset();
|
||||
|
||||
if (_price != null)
|
||||
{
|
||||
_price.text = string.Empty;
|
||||
@@ -93,4 +115,4 @@ namespace GeometryTD.UI
|
||||
_hasCachedDefaultIcon = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ namespace GeometryTD.UI
|
||||
{
|
||||
public class CompAreaContext
|
||||
{
|
||||
public RepoItemContext[] Items;
|
||||
public RepoItemContext[] ComponentItems;
|
||||
public TowerRepoItemContext[] TowerItems;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ namespace GeometryTD.UI
|
||||
{
|
||||
public class ParticipantAreaContext : UIContext
|
||||
{
|
||||
public RepoItemContext[] Items;
|
||||
public TowerRepoItemContext[] TowerItems;
|
||||
public int MaxCount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
[Serializable]
|
||||
public class TowerRepoItemContext : RepoItemContext
|
||||
{
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6fb39901e8409cd4db9dbde01bee1ced
|
||||
guid: 813496ec671788a4b975fa980ce16555
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -10,8 +10,9 @@ namespace GeometryTD.UI
|
||||
{
|
||||
private RepoFormContext BuildContext(RepoFormRawData rawData)
|
||||
{
|
||||
_itemContextMap.Clear();
|
||||
_itemClickActionMap.Clear();
|
||||
_itemDescSeedMap.Clear();
|
||||
_compAreaTowerIds.Clear();
|
||||
if (rawData?.Inventory == null)
|
||||
{
|
||||
_participantTowerIds.Clear();
|
||||
@@ -22,7 +23,8 @@ namespace GeometryTD.UI
|
||||
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>();
|
||||
List<RepoItemContext> componentItems = new List<RepoItemContext>();
|
||||
List<TowerRepoItemContext> towerItems = new List<TowerRepoItemContext>();
|
||||
|
||||
if (rawData.Inventory.Towers != null)
|
||||
{
|
||||
@@ -33,15 +35,9 @@ namespace GeometryTD.UI
|
||||
continue;
|
||||
}
|
||||
|
||||
AddItemContext(items, new RepoItemContext
|
||||
{
|
||||
InstanceId = tower.InstanceId,
|
||||
CanDrag = true,
|
||||
EnduranceRate01 = ItemDescUtility.ResolveTowerEnduranceRate(tower, muzzleMap, bearingMap, baseMap),
|
||||
ClickActionType = RepoItemClickActionType.OpenDetail,
|
||||
ComponentSlotType = TowerCompSlotType.None,
|
||||
IconAreaContext = BuildIconAreaContext(tower)
|
||||
});
|
||||
TowerRepoItemContext towerContext = BuildTowerRepoItemContext(tower, muzzleMap, bearingMap, baseMap,
|
||||
RepoItemClickActionType.OpenDetail, true);
|
||||
AddTowerItemContext(towerItems, towerContext);
|
||||
AddItemDescSeed(
|
||||
tower.InstanceId,
|
||||
tower.Name,
|
||||
@@ -60,7 +56,7 @@ namespace GeometryTD.UI
|
||||
continue;
|
||||
}
|
||||
|
||||
AddItemContext(items, new RepoItemContext
|
||||
RepoItemContext componentContext = new RepoItemContext
|
||||
{
|
||||
InstanceId = item.InstanceId,
|
||||
CanDrag = true,
|
||||
@@ -68,7 +64,8 @@ namespace GeometryTD.UI
|
||||
ClickActionType = RepoItemClickActionType.OpenDetail,
|
||||
ComponentSlotType = TowerCompSlotType.Muzzle,
|
||||
IconAreaContext = BuildIconAreaContext(item)
|
||||
});
|
||||
};
|
||||
AddComponentItemContext(componentItems, componentContext);
|
||||
AddItemDescSeed(
|
||||
item.InstanceId,
|
||||
item.Name,
|
||||
@@ -87,7 +84,7 @@ namespace GeometryTD.UI
|
||||
continue;
|
||||
}
|
||||
|
||||
AddItemContext(items, new RepoItemContext
|
||||
RepoItemContext componentContext = new RepoItemContext
|
||||
{
|
||||
InstanceId = item.InstanceId,
|
||||
CanDrag = true,
|
||||
@@ -95,7 +92,8 @@ namespace GeometryTD.UI
|
||||
ClickActionType = RepoItemClickActionType.OpenDetail,
|
||||
ComponentSlotType = TowerCompSlotType.Bearing,
|
||||
IconAreaContext = BuildIconAreaContext(item)
|
||||
});
|
||||
};
|
||||
AddComponentItemContext(componentItems, componentContext);
|
||||
AddItemDescSeed(
|
||||
item.InstanceId,
|
||||
item.Name,
|
||||
@@ -114,7 +112,7 @@ namespace GeometryTD.UI
|
||||
continue;
|
||||
}
|
||||
|
||||
AddItemContext(items, new RepoItemContext
|
||||
RepoItemContext componentContext = new RepoItemContext
|
||||
{
|
||||
InstanceId = item.InstanceId,
|
||||
CanDrag = true,
|
||||
@@ -122,7 +120,8 @@ namespace GeometryTD.UI
|
||||
ClickActionType = RepoItemClickActionType.OpenDetail,
|
||||
ComponentSlotType = TowerCompSlotType.Base,
|
||||
IconAreaContext = BuildIconAreaContext(item)
|
||||
});
|
||||
};
|
||||
AddComponentItemContext(componentItems, componentContext);
|
||||
AddItemDescSeed(
|
||||
item.InstanceId,
|
||||
item.Name,
|
||||
@@ -140,13 +139,14 @@ namespace GeometryTD.UI
|
||||
CombineAreaContext = new CombineAreaContext(),
|
||||
CompAreaContext = new CompAreaContext
|
||||
{
|
||||
Items = items.ToArray()
|
||||
ComponentItems = componentItems.ToArray(),
|
||||
TowerItems = towerItems.ToArray()
|
||||
},
|
||||
ParticipantAreaContext = participantAreaContext
|
||||
};
|
||||
}
|
||||
|
||||
private void AddItemContext(List<RepoItemContext> items, RepoItemContext itemContext)
|
||||
private void AddComponentItemContext(List<RepoItemContext> items, RepoItemContext itemContext)
|
||||
{
|
||||
if (itemContext == null)
|
||||
{
|
||||
@@ -154,7 +154,19 @@ namespace GeometryTD.UI
|
||||
}
|
||||
|
||||
items.Add(itemContext);
|
||||
_itemContextMap[itemContext.InstanceId] = itemContext;
|
||||
_itemClickActionMap[itemContext.InstanceId] = itemContext.ClickActionType;
|
||||
}
|
||||
|
||||
private void AddTowerItemContext(List<TowerRepoItemContext> items, TowerRepoItemContext itemContext)
|
||||
{
|
||||
if (itemContext == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
items.Add(itemContext);
|
||||
_itemClickActionMap[itemContext.InstanceId] = itemContext.ClickActionType;
|
||||
_compAreaTowerIds.Add(itemContext.InstanceId);
|
||||
}
|
||||
|
||||
private void AddItemDescSeed(long itemId, string title, string typeText, string description, TagType[] tags)
|
||||
@@ -243,7 +255,7 @@ namespace GeometryTD.UI
|
||||
IReadOnlyDictionary<long, BaseCompItemData> baseMap)
|
||||
{
|
||||
_participantTowerIds.Clear();
|
||||
List<RepoItemContext> participantItems = new List<RepoItemContext>();
|
||||
List<TowerRepoItemContext> participantItems = new List<TowerRepoItemContext>();
|
||||
if (inventory?.ParticipantTowerInstanceIds != null && towerMap != null)
|
||||
{
|
||||
for (int i = 0; i < inventory.ParticipantTowerInstanceIds.Count; i++)
|
||||
@@ -264,41 +276,33 @@ namespace GeometryTD.UI
|
||||
continue;
|
||||
}
|
||||
|
||||
participantItems.Add(new RepoItemContext
|
||||
TowerRepoItemContext towerContext = BuildTowerRepoItemContext(tower, muzzleMap, bearingMap, baseMap,
|
||||
RepoItemClickActionType.RemoveParticipant, false);
|
||||
if (towerContext != null)
|
||||
{
|
||||
InstanceId = tower.InstanceId,
|
||||
CanDrag = false,
|
||||
EnduranceRate01 = ItemDescUtility.ResolveTowerEnduranceRate(tower, muzzleMap, bearingMap, baseMap),
|
||||
ClickActionType = RepoItemClickActionType.RemoveParticipant,
|
||||
ComponentSlotType = TowerCompSlotType.None,
|
||||
IconAreaContext = BuildIconAreaContext(tower)
|
||||
});
|
||||
participantItems.Add(towerContext);
|
||||
_itemClickActionMap[towerContext.InstanceId] = towerContext.ClickActionType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new ParticipantAreaContext
|
||||
{
|
||||
Items = participantItems.ToArray(),
|
||||
TowerItems = participantItems.ToArray(),
|
||||
MaxCount = MaxParticipantCount
|
||||
};
|
||||
}
|
||||
|
||||
private void ApplyParticipantSelection()
|
||||
{
|
||||
if (Form == null || _itemContextMap.Count <= 0)
|
||||
if (Form == null || _compAreaTowerIds.Count <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<long, RepoItemContext> pair in _itemContextMap)
|
||||
foreach (long towerId in _compAreaTowerIds)
|
||||
{
|
||||
RepoItemContext itemContext = pair.Value;
|
||||
if (itemContext == null || itemContext.ComponentSlotType != TowerCompSlotType.None)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Form.SetRepoItemSelected(pair.Key, _participantTowerIds.Contains(pair.Key));
|
||||
Form.SetRepoItemSelected(towerId, _participantTowerIds.Contains(towerId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,25 +323,33 @@ namespace GeometryTD.UI
|
||||
ApplyParticipantSelection();
|
||||
}
|
||||
|
||||
private static IconAreaContext BuildIconAreaContext(TowerItemData tower)
|
||||
private static TowerRepoItemContext BuildTowerRepoItemContext(
|
||||
TowerItemData tower,
|
||||
IReadOnlyDictionary<long, MuzzleCompItemData> muzzleMap,
|
||||
IReadOnlyDictionary<long, BearingCompItemData> bearingMap,
|
||||
IReadOnlyDictionary<long, BaseCompItemData> baseMap,
|
||||
RepoItemClickActionType clickActionType,
|
||||
bool canDrag)
|
||||
{
|
||||
if (tower == null)
|
||||
{
|
||||
return new IconAreaContext
|
||||
{
|
||||
ComponentSlotType = TowerCompSlotType.None,
|
||||
Rarity = RarityType.None,
|
||||
Color = Color.white,
|
||||
Icon = null
|
||||
};
|
||||
return null;
|
||||
}
|
||||
|
||||
return new IconAreaContext
|
||||
return new TowerRepoItemContext
|
||||
{
|
||||
InstanceId = tower.InstanceId,
|
||||
CanDrag = canDrag,
|
||||
EnduranceRate01 = ItemDescUtility.ResolveTowerEnduranceRate(tower, muzzleMap, bearingMap, baseMap),
|
||||
ClickActionType = clickActionType,
|
||||
ComponentSlotType = TowerCompSlotType.None,
|
||||
Rarity = tower.Rarity,
|
||||
Color = IconColorGenerator.GenerateForTower(tower),
|
||||
Icon = null
|
||||
IconAreaContext = new TowerIconAreaContext
|
||||
{
|
||||
Rarity = tower.Rarity,
|
||||
MuzzleColor = ResolveComponentColor(tower.MuzzleComponentInstanceId, muzzleMap),
|
||||
BearingColor = ResolveComponentColor(tower.BearingComponentInstanceId, bearingMap),
|
||||
BaseColor = ResolveComponentColor(tower.BaseComponentInstanceId, baseMap)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -362,5 +374,21 @@ namespace GeometryTD.UI
|
||||
Icon = null
|
||||
};
|
||||
}
|
||||
|
||||
private static Color ResolveComponentColor<TComp>(long instanceId,
|
||||
IReadOnlyDictionary<long, TComp> componentMap)
|
||||
where TComp : TowerCompItemData
|
||||
{
|
||||
if (instanceId > 0 &&
|
||||
componentMap != null &&
|
||||
componentMap.TryGetValue(instanceId, out TComp component) &&
|
||||
component != null)
|
||||
{
|
||||
return IconColorGenerator.GenerateForComponent(component);
|
||||
}
|
||||
|
||||
return Color.white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,9 +11,11 @@ namespace GeometryTD.UI
|
||||
{
|
||||
private const int MaxParticipantCount = 4;
|
||||
private RepoFormUseCase _useCase;
|
||||
private readonly Dictionary<long, RepoItemContext> _itemContextMap = new Dictionary<long, RepoItemContext>();
|
||||
private readonly Dictionary<long, RepoItemClickActionType> _itemClickActionMap =
|
||||
new Dictionary<long, RepoItemClickActionType>();
|
||||
private readonly Dictionary<long, ItemDescSeed> _itemDescSeedMap = new Dictionary<long, ItemDescSeed>();
|
||||
private readonly HashSet<long> _participantTowerIds = new HashSet<long>();
|
||||
private readonly HashSet<long> _compAreaTowerIds = new HashSet<long>();
|
||||
|
||||
private sealed class ItemDescSeed
|
||||
{
|
||||
@@ -111,14 +113,9 @@ namespace GeometryTD.UI
|
||||
}
|
||||
|
||||
RepoItemClickActionType clickActionType = RepoItemClickActionType.OpenDetail;
|
||||
if (sender is RepoItem clickedItem && clickedItem.Context != null)
|
||||
if (_itemClickActionMap.TryGetValue(args.ItemId, out RepoItemClickActionType mappedAction))
|
||||
{
|
||||
clickActionType = clickedItem.Context.ClickActionType;
|
||||
}
|
||||
else if (_itemContextMap.TryGetValue(args.ItemId, out RepoItemContext itemContextFromMap) &&
|
||||
itemContextFromMap != null)
|
||||
{
|
||||
clickActionType = itemContextFromMap.ClickActionType;
|
||||
clickActionType = mappedAction;
|
||||
}
|
||||
|
||||
if (args.ItemId <= 0)
|
||||
@@ -170,7 +167,7 @@ namespace GeometryTD.UI
|
||||
return;
|
||||
}
|
||||
|
||||
if (Form == null || !_itemContextMap.ContainsKey(args.ItemId))
|
||||
if (Form == null || !_itemClickActionMap.ContainsKey(args.ItemId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -212,8 +209,8 @@ namespace GeometryTD.UI
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.CloseUI();
|
||||
|
||||
CloseUI();
|
||||
}
|
||||
|
||||
private void OnRepoCombineRequested(object sender, GameEventArgs e)
|
||||
@@ -258,12 +255,12 @@ namespace GeometryTD.UI
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (_useCase == null || Form == null || args.TowerItemId <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!_useCase.TryAddParticipantTower(args.TowerItemId))
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -67,11 +67,6 @@ namespace GeometryTD.UI
|
||||
InventoryParticipantUtility.NormalizeParticipantState(_fallbackInventory, MaxParticipantCount);
|
||||
return _fallbackInventory;
|
||||
}
|
||||
|
||||
public static BackpackInventoryData SampleInventory()
|
||||
{
|
||||
return InventorySeedUtility.CreateSampleInventory();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using GeometryTD.Definition;
|
||||
using GeometryTD.CustomEvent;
|
||||
using GeometryTD.Definition;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
@@ -102,19 +102,15 @@ namespace GeometryTD.UI
|
||||
return;
|
||||
}
|
||||
|
||||
RepoItem repoItem = pointerDrag.GetComponent<RepoItem>();
|
||||
if (repoItem == null)
|
||||
{
|
||||
repoItem = pointerDrag.GetComponentInParent<RepoItem>();
|
||||
}
|
||||
|
||||
if (repoItem == null)
|
||||
IRepoDragItemView dragItem = pointerDrag.GetComponent<IRepoDragItemView>() ??
|
||||
pointerDrag.GetComponentInParent<IRepoDragItemView>();
|
||||
if (dragItem == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool assigned = TryAssignItem(repoItem.Context);
|
||||
repoItem.SetDropResult(assigned);
|
||||
bool assigned = TryAssignItem(dragItem.ComponentContext);
|
||||
dragItem.SetDropResult(assigned);
|
||||
}
|
||||
|
||||
private CombineSlotItem FindSlot(TowerCompSlotType slotType)
|
||||
|
||||
@@ -11,12 +11,17 @@ namespace GeometryTD.UI
|
||||
{
|
||||
[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> _activeItems = new List<RepoItem>();
|
||||
private readonly Dictionary<long, RepoItem> _itemMap = new Dictionary<long, RepoItem>();
|
||||
private IObjectPool<RepoItemObject> _itemPool;
|
||||
private string _poolName;
|
||||
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)
|
||||
{
|
||||
@@ -29,31 +34,46 @@ namespace GeometryTD.UI
|
||||
EnsurePool();
|
||||
OnReset();
|
||||
|
||||
if (context.Items == null || context.Items.Length == 0)
|
||||
if (context.ComponentItems != null)
|
||||
{
|
||||
return;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var itemContext in context.Items)
|
||||
if (context.TowerItems != null)
|
||||
{
|
||||
RepoItem item = CreateOrSpawnItem();
|
||||
if (item == null)
|
||||
foreach (TowerRepoItemContext itemContext in context.TowerItems)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
TowerRepoItem item = CreateOrSpawnTowerItem();
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
item.gameObject.SetActive(true);
|
||||
item.OnInit(itemContext);
|
||||
_activeItems.Add(item);
|
||||
_itemMap[itemContext.InstanceId] = item;
|
||||
item.gameObject.SetActive(true);
|
||||
item.OnInit(itemContext);
|
||||
_activeTowerItems.Add(item);
|
||||
_towerItemMap[itemContext.InstanceId] = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnReset()
|
||||
{
|
||||
for (int i = _activeItems.Count - 1; i >= 0; i--)
|
||||
for (int i = _activeComponentItems.Count - 1; i >= 0; i--)
|
||||
{
|
||||
RepoItem item = _activeItems[i];
|
||||
RepoItem item = _activeComponentItems[i];
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
@@ -61,49 +81,102 @@ namespace GeometryTD.UI
|
||||
|
||||
item.OnReset();
|
||||
item.gameObject.SetActive(false);
|
||||
_itemPool?.Unspawn(item);
|
||||
_componentItemPool?.Unspawn(item);
|
||||
}
|
||||
|
||||
_activeItems.Clear();
|
||||
_itemMap.Clear();
|
||||
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();
|
||||
_itemPool?.ReleaseAllUnused();
|
||||
_componentItemPool?.ReleaseAllUnused();
|
||||
_towerItemPool?.ReleaseAllUnused();
|
||||
}
|
||||
|
||||
private void EnsurePool()
|
||||
{
|
||||
if (_itemPool != null)
|
||||
if (_componentItemPool == null)
|
||||
{
|
||||
return;
|
||||
_componentPoolName = $"RepoItemPool_{GetInstanceID()}";
|
||||
_componentItemPool =
|
||||
GameEntry.ObjectPool.CreateSingleSpawnObjectPool<RepoItemObject>(_componentPoolName,
|
||||
_instancePoolCapacity);
|
||||
}
|
||||
|
||||
_poolName = $"RepoItemPool_{GetInstanceID()}";
|
||||
_itemPool = GameEntry.ObjectPool.CreateSingleSpawnObjectPool<RepoItemObject>(_poolName, _instancePoolCapacity);
|
||||
if (_towerItemPool == null)
|
||||
{
|
||||
_towerPoolName = $"TowerRepoItemPool_{GetInstanceID()}";
|
||||
_towerItemPool =
|
||||
GameEntry.ObjectPool.CreateSingleSpawnObjectPool<TowerRepoItemObject>(_towerPoolName,
|
||||
_instancePoolCapacity);
|
||||
}
|
||||
}
|
||||
|
||||
private RepoItem CreateOrSpawnItem()
|
||||
private RepoItem CreateOrSpawnComponentItem()
|
||||
{
|
||||
if (_itemPool == null)
|
||||
if (_componentItemPool == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
RepoItemObject itemObject = _itemPool.Spawn();
|
||||
RepoItemObject itemObject = _componentItemPool.Spawn();
|
||||
RepoItem item = itemObject != null ? (RepoItem)itemObject.Target : null;
|
||||
if (item == null)
|
||||
{
|
||||
if (_itemTemplate == null)
|
||||
{
|
||||
Log.Warning("CompArea requires an item template.");
|
||||
Log.Warning("CompArea requires a component item template.");
|
||||
return null;
|
||||
}
|
||||
|
||||
item = Instantiate(_itemTemplate);
|
||||
_itemPool.Register(RepoItemObject.Create(item), true);
|
||||
_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)
|
||||
@@ -116,12 +189,15 @@ namespace GeometryTD.UI
|
||||
|
||||
public void SetItemSelected(long itemId, bool isSelected)
|
||||
{
|
||||
if (!_itemMap.TryGetValue(itemId, out RepoItem item))
|
||||
if (_componentItemMap.TryGetValue(itemId, out RepoItem componentItem))
|
||||
{
|
||||
return;
|
||||
componentItem.SetSelected(isSelected);
|
||||
}
|
||||
|
||||
item.SetSelected(isSelected);
|
||||
if (_towerItemMap.TryGetValue(itemId, out TowerRepoItem towerItem))
|
||||
{
|
||||
towerItem.SetSelected(isSelected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5cb3c8e275a9ba646a58a2656af31faa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -12,12 +12,12 @@ namespace GeometryTD.UI
|
||||
public class ParticipantArea : MonoBehaviour, IDropHandler
|
||||
{
|
||||
[SerializeField] private Transform _content;
|
||||
[SerializeField] private RepoItem _itemTemplate;
|
||||
[SerializeField] private TowerRepoItem _towerItemTemplate;
|
||||
[SerializeField] private int _instancePoolCapacity = 8;
|
||||
|
||||
private readonly List<RepoItem> _activeItems = new List<RepoItem>();
|
||||
private readonly List<TowerRepoItem> _activeItems = new List<TowerRepoItem>();
|
||||
private readonly HashSet<long> _boundItemIds = new HashSet<long>();
|
||||
private IObjectPool<RepoItemObject> _itemPool;
|
||||
private IObjectPool<TowerRepoItemObject> _itemPool;
|
||||
private string _poolName;
|
||||
private int _maxCount = 4;
|
||||
|
||||
@@ -27,20 +27,20 @@ namespace GeometryTD.UI
|
||||
EnsurePool();
|
||||
|
||||
_maxCount = Mathf.Max(1, context != null ? context.MaxCount : 4);
|
||||
if (context?.Items == null || context.Items.Length <= 0)
|
||||
if (context?.TowerItems == null || context.TowerItems.Length <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < context.Items.Length; i++)
|
||||
for (int i = 0; i < context.TowerItems.Length; i++)
|
||||
{
|
||||
RepoItemContext itemContext = context.Items[i];
|
||||
TowerRepoItemContext itemContext = context.TowerItems[i];
|
||||
if (itemContext == null || itemContext.InstanceId <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
RepoItem item = CreateOrSpawnItem();
|
||||
TowerRepoItem item = CreateOrSpawnItem();
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
@@ -57,7 +57,7 @@ namespace GeometryTD.UI
|
||||
{
|
||||
for (int i = _activeItems.Count - 1; i >= 0; i--)
|
||||
{
|
||||
RepoItem item = _activeItems[i];
|
||||
TowerRepoItem item = _activeItems[i];
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
@@ -79,19 +79,19 @@ namespace GeometryTD.UI
|
||||
_itemPool?.ReleaseAllUnused();
|
||||
}
|
||||
|
||||
public bool CanAssign(RepoItemContext itemContext)
|
||||
public bool CanAssign(IRepoDragItemView dragItem)
|
||||
{
|
||||
if (itemContext == null || itemContext.InstanceId <= 0)
|
||||
if (dragItem == null || dragItem.InstanceId <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemContext.ComponentSlotType != TowerCompSlotType.None)
|
||||
if (dragItem.ComponentSlotType != TowerCompSlotType.None)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_boundItemIds.Contains(itemContext.InstanceId))
|
||||
if (_boundItemIds.Contains(dragItem.InstanceId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -117,21 +117,21 @@ namespace GeometryTD.UI
|
||||
return;
|
||||
}
|
||||
|
||||
RepoItem repoItem = pointerDrag.GetComponent<RepoItem>() ?? pointerDrag.GetComponentInParent<RepoItem>();
|
||||
if (repoItem == null)
|
||||
IRepoDragItemView dragItem = pointerDrag.GetComponent<IRepoDragItemView>() ??
|
||||
pointerDrag.GetComponentInParent<IRepoDragItemView>();
|
||||
if (dragItem == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RepoItemContext itemContext = repoItem.Context;
|
||||
bool assigned = CanAssign(itemContext);
|
||||
repoItem.SetDropResult(assigned);
|
||||
bool assigned = CanAssign(dragItem);
|
||||
dragItem.SetDropResult(assigned);
|
||||
if (!assigned)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameEntry.Event.Fire(this, RepoParticipantAssignRequestedEventArgs.Create(itemContext.InstanceId));
|
||||
GameEntry.Event.Fire(this, RepoParticipantAssignRequestedEventArgs.Create(dragItem.InstanceId));
|
||||
}
|
||||
|
||||
private void EnsurePool()
|
||||
@@ -141,29 +141,30 @@ namespace GeometryTD.UI
|
||||
return;
|
||||
}
|
||||
|
||||
_poolName = $"ParticipantRepoItemPool_{GetInstanceID()}";
|
||||
_itemPool = GameEntry.ObjectPool.CreateSingleSpawnObjectPool<RepoItemObject>(_poolName, _instancePoolCapacity);
|
||||
_poolName = $"ParticipantTowerRepoItemPool_{GetInstanceID()}";
|
||||
_itemPool =
|
||||
GameEntry.ObjectPool.CreateSingleSpawnObjectPool<TowerRepoItemObject>(_poolName, _instancePoolCapacity);
|
||||
}
|
||||
|
||||
private RepoItem CreateOrSpawnItem()
|
||||
private TowerRepoItem CreateOrSpawnItem()
|
||||
{
|
||||
if (_itemPool == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
RepoItemObject itemObject = _itemPool.Spawn();
|
||||
RepoItem item = itemObject != null ? (RepoItem)itemObject.Target : null;
|
||||
TowerRepoItemObject itemObject = _itemPool.Spawn();
|
||||
TowerRepoItem item = itemObject != null ? (TowerRepoItem)itemObject.Target : null;
|
||||
if (item == null)
|
||||
{
|
||||
if (_itemTemplate == null)
|
||||
if (_towerItemTemplate == null)
|
||||
{
|
||||
Log.Warning("ParticipantArea requires an item template.");
|
||||
Log.Warning("ParticipantArea requires a tower item template.");
|
||||
return null;
|
||||
}
|
||||
|
||||
item = Instantiate(_itemTemplate);
|
||||
_itemPool.Register(RepoItemObject.Create(item), true);
|
||||
item = Instantiate(_towerItemTemplate);
|
||||
_itemPool.Register(TowerRepoItemObject.Create(item), true);
|
||||
}
|
||||
|
||||
if (_content != null)
|
||||
|
||||
@@ -6,10 +6,10 @@ using UnityEngine.UI;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class RepoItem : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
|
||||
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);
|
||||
@@ -20,8 +20,8 @@ namespace GeometryTD.UI
|
||||
[SerializeField] private RepoItemContext _context;
|
||||
private CanvasGroup _canvasGroup;
|
||||
private RectTransform _dragRoot;
|
||||
private GameObject _dragGhostObject;
|
||||
private RectTransform _dragGhostRect;
|
||||
protected GameObject _dragGhostObject;
|
||||
protected RectTransform _dragGhostRect;
|
||||
private bool _isSelected;
|
||||
private bool _isDragging;
|
||||
private bool _dropHandled;
|
||||
@@ -29,6 +29,24 @@ namespace GeometryTD.UI
|
||||
|
||||
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>();
|
||||
@@ -43,7 +61,7 @@ namespace GeometryTD.UI
|
||||
ResetDragState();
|
||||
}
|
||||
|
||||
public void OnInit(RepoItemContext context)
|
||||
public virtual void OnInit(RepoItemContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
@@ -52,14 +70,13 @@ namespace GeometryTD.UI
|
||||
}
|
||||
|
||||
_context = context;
|
||||
|
||||
_iconArea.OnInit(context.IconAreaContext);
|
||||
|
||||
SetSelected(false);
|
||||
ResetDragState();
|
||||
}
|
||||
|
||||
public void OnReset()
|
||||
public virtual void OnReset()
|
||||
{
|
||||
_context = null;
|
||||
_iconArea.OnReset();
|
||||
@@ -165,6 +182,7 @@ namespace GeometryTD.UI
|
||||
{
|
||||
_canvasGroup.blocksRaycasts = true;
|
||||
}
|
||||
|
||||
DestroyDragGhost();
|
||||
_dragRoot = null;
|
||||
|
||||
@@ -232,7 +250,7 @@ namespace GeometryTD.UI
|
||||
return canvas.rootCanvas.transform as RectTransform;
|
||||
}
|
||||
|
||||
private bool CreateDragGhost()
|
||||
protected virtual bool CreateDragGhost()
|
||||
{
|
||||
DestroyDragGhost();
|
||||
|
||||
@@ -246,7 +264,6 @@ namespace GeometryTD.UI
|
||||
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;
|
||||
@@ -260,7 +277,8 @@ namespace GeometryTD.UI
|
||||
return false;
|
||||
}
|
||||
|
||||
_dragGhostObject = new GameObject("RepoItemDragGhost", typeof(RectTransform), typeof(CanvasGroup), typeof(Image));
|
||||
_dragGhostObject = new GameObject("RepoItemDragGhost", typeof(RectTransform), typeof(CanvasGroup),
|
||||
typeof(Image));
|
||||
_dragGhostObject.layer = gameObject.layer;
|
||||
|
||||
_dragGhostRect = _dragGhostObject.GetComponent<RectTransform>();
|
||||
@@ -273,6 +291,7 @@ namespace GeometryTD.UI
|
||||
{
|
||||
iconSize = DefaultDragGhostSize;
|
||||
}
|
||||
|
||||
_dragGhostRect.sizeDelta = iconSize;
|
||||
|
||||
Image ghostImage = _dragGhostObject.GetComponent<Image>();
|
||||
@@ -290,7 +309,7 @@ namespace GeometryTD.UI
|
||||
return true;
|
||||
}
|
||||
|
||||
private void UpdateDragGhostPosition(PointerEventData eventData)
|
||||
protected virtual void UpdateDragGhostPosition(PointerEventData eventData)
|
||||
{
|
||||
if (_dragGhostRect == null || _dragRoot == null || eventData == null)
|
||||
{
|
||||
@@ -304,7 +323,7 @@ namespace GeometryTD.UI
|
||||
}
|
||||
}
|
||||
|
||||
private void DestroyDragGhost()
|
||||
protected virtual void DestroyDragGhost()
|
||||
{
|
||||
if (_dragGhostObject != null)
|
||||
{
|
||||
@@ -329,3 +348,4 @@ namespace GeometryTD.UI
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: caf7b65cc179a5d46828128f574ed63e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using GeometryTD.Definition;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
[Serializable]
|
||||
public class TowerIconAreaContext : IconAreaContext
|
||||
{
|
||||
public Color MuzzleColor = Color.white;
|
||||
public Color BearingColor = Color.white;
|
||||
public Color BaseColor = Color.white;
|
||||
|
||||
public TowerIconAreaContext()
|
||||
{
|
||||
ComponentSlotType = TowerCompSlotType.None;
|
||||
Color = Color.white;
|
||||
Icon = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e3576597006db5b458566429f98a6f43
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,443 +0,0 @@
|
||||
using GameFramework.DataTable;
|
||||
using GeometryTD.DataTable;
|
||||
using GeometryTD.Definition;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GeometryTD.CustomUtility
|
||||
{
|
||||
public static class IconColorGenerator
|
||||
{
|
||||
private const int StatCount = 5;
|
||||
private const float MinSaturation = 0.4f;
|
||||
private const float MinValue = 0.6f;
|
||||
private const float TinyValue = 0.0001f;
|
||||
|
||||
private static readonly float[] HueMap = { 0f, 30f, 200f, 120f, 270f };
|
||||
|
||||
private static StatRange _attackDamageRange = new StatRange(1f, 300f);
|
||||
private static StatRange _damageRandomRateRange = new StatRange(0f, 0.3f);
|
||||
private static StatRange _rotateSpeedRange = new StatRange(10f, 240f);
|
||||
private static StatRange _attackRangeRange = new StatRange(2f, 8f);
|
||||
private static StatRange _attackSpeedRange = new StatRange(0.5f, 4f);
|
||||
|
||||
private static bool s_HasMuzzleRange;
|
||||
private static bool s_HasBearingRange;
|
||||
private static bool s_HasBaseRange;
|
||||
|
||||
public static Color GenerateForComponent(TowerCompItemData item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return Color.white;
|
||||
}
|
||||
|
||||
float attackDamage = 0f;
|
||||
float damageRandomRate = 0f;
|
||||
float rotateSpeed = 0f;
|
||||
float attackRange = 0f;
|
||||
float attackSpeed = 0f;
|
||||
|
||||
if (item is MuzzleCompItemData muzzle)
|
||||
{
|
||||
attackDamage = ResolveArrayValue(muzzle.AttackDamage);
|
||||
damageRandomRate = Mathf.Max(0f, muzzle.DamageRandomRate);
|
||||
}
|
||||
else if (item is BearingCompItemData bearing)
|
||||
{
|
||||
rotateSpeed = ResolveArrayValue(bearing.RotateSpeed);
|
||||
attackRange = ResolveArrayValue(bearing.AttackRange);
|
||||
}
|
||||
else if (item is BaseCompItemData baseComp)
|
||||
{
|
||||
attackSpeed = ResolveArrayValue(baseComp.AttackSpeed);
|
||||
}
|
||||
|
||||
return GenerateColor(
|
||||
attackDamage,
|
||||
damageRandomRate,
|
||||
rotateSpeed,
|
||||
attackRange,
|
||||
attackSpeed,
|
||||
item.SlotType);
|
||||
}
|
||||
|
||||
public static Color GenerateForTower(TowerItemData tower)
|
||||
{
|
||||
if (tower?.Stats == null)
|
||||
{
|
||||
return Color.white;
|
||||
}
|
||||
|
||||
TowerStatsData stats = tower.Stats;
|
||||
return GenerateColor(
|
||||
ResolveArrayValue(stats.AttackDamage),
|
||||
stats.DamageRandomRate,
|
||||
ResolveArrayValue(stats.RotateSpeed),
|
||||
ResolveArrayValue(stats.AttackRange),
|
||||
ResolveArrayValue(stats.AttackSpeed),
|
||||
TowerCompSlotType.None);
|
||||
}
|
||||
|
||||
private static Color GenerateColor(
|
||||
float attackDamage,
|
||||
float damageRandomRate,
|
||||
float rotateSpeed,
|
||||
float attackRange,
|
||||
float attackSpeed,
|
||||
TowerCompSlotType slotType)
|
||||
{
|
||||
TryRefreshRangesFromDataTables();
|
||||
|
||||
float[] normalizedStats = new float[StatCount];
|
||||
normalizedStats[0] = Normalize(attackDamage, _attackDamageRange);
|
||||
normalizedStats[1] = Normalize(damageRandomRate, _damageRandomRateRange);
|
||||
normalizedStats[2] = Normalize(rotateSpeed, _rotateSpeedRange);
|
||||
normalizedStats[3] = Normalize(attackRange, _attackRangeRange);
|
||||
normalizedStats[4] = Normalize(attackSpeed, _attackSpeedRange);
|
||||
|
||||
FindTopTwoIndexes(normalizedStats, out int primaryIndex, out int secondaryIndex);
|
||||
|
||||
float denominator = normalizedStats[primaryIndex] + normalizedStats[secondaryIndex] + TinyValue;
|
||||
float blendWeight = normalizedStats[secondaryIndex] / denominator;
|
||||
float hue = LerpHue(HueMap[primaryIndex], HueMap[secondaryIndex], blendWeight);
|
||||
hue = NormalizeHue(hue + ResolveSlotHueOffset(slotType));
|
||||
|
||||
float purity = normalizedStats[primaryIndex] - normalizedStats[secondaryIndex];
|
||||
float saturation = Mathf.Lerp(0.45f, 0.9f, Mathf.Clamp01(purity * 1.5f));
|
||||
saturation = Mathf.Max(saturation, MinSaturation);
|
||||
|
||||
float intensity = 0f;
|
||||
for (int i = 0; i < normalizedStats.Length; i++)
|
||||
{
|
||||
intensity += normalizedStats[i];
|
||||
}
|
||||
|
||||
float value = Mathf.Lerp(0.55f, 0.95f, intensity / StatCount);
|
||||
value = Mathf.Max(value, MinValue);
|
||||
|
||||
Color color = Color.HSVToRGB(hue / 360f, saturation, value);
|
||||
color.a = 1f;
|
||||
return color;
|
||||
}
|
||||
|
||||
private static void TryRefreshRangesFromDataTables()
|
||||
{
|
||||
if (GameEntry.DataTable == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s_HasMuzzleRange &&
|
||||
TryResolveMuzzleRange(out StatRange attackDamageRange, out StatRange damageRandomRateRange))
|
||||
{
|
||||
_attackDamageRange = attackDamageRange;
|
||||
_damageRandomRateRange = damageRandomRateRange;
|
||||
s_HasMuzzleRange = true;
|
||||
}
|
||||
|
||||
if (!s_HasBearingRange &&
|
||||
TryResolveBearingRange(out StatRange rotateSpeedRange, out StatRange attackRangeRange))
|
||||
{
|
||||
_rotateSpeedRange = rotateSpeedRange;
|
||||
_attackRangeRange = attackRangeRange;
|
||||
s_HasBearingRange = true;
|
||||
}
|
||||
|
||||
if (!s_HasBaseRange && TryResolveBaseRange(out StatRange attackSpeedRange))
|
||||
{
|
||||
_attackSpeedRange = attackSpeedRange;
|
||||
s_HasBaseRange = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryResolveMuzzleRange(out StatRange attackDamageRange, out StatRange damageRandomRateRange)
|
||||
{
|
||||
attackDamageRange = _attackDamageRange;
|
||||
damageRandomRateRange = _damageRandomRateRange;
|
||||
|
||||
IDataTable<DRMuzzleComp> dataTable = GameEntry.DataTable.GetDataTable<DRMuzzleComp>();
|
||||
if (dataTable == null || dataTable.Count <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DRMuzzleComp[] rows = dataTable.GetAllDataRows();
|
||||
if (rows == null || rows.Length <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasAttackDamage = false;
|
||||
bool hasDamageRandomRate = false;
|
||||
float minAttackDamage = float.MaxValue;
|
||||
float maxAttackDamage = float.MinValue;
|
||||
float minDamageRandomRate = float.MaxValue;
|
||||
float maxDamageRandomRate = float.MinValue;
|
||||
|
||||
for (int i = 0; i < rows.Length; i++)
|
||||
{
|
||||
DRMuzzleComp row = rows[i];
|
||||
if (row == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
IncludeValues(row.AttackDamage, ref minAttackDamage, ref maxAttackDamage, ref hasAttackDamage);
|
||||
IncludeValue(Mathf.Max(0f, row.DamageRandomRate), ref minDamageRandomRate, ref maxDamageRandomRate,
|
||||
ref hasDamageRandomRate);
|
||||
}
|
||||
|
||||
if (!hasAttackDamage || !hasDamageRandomRate)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
attackDamageRange = BuildRange(minAttackDamage, maxAttackDamage, _attackDamageRange);
|
||||
damageRandomRateRange = BuildRange(minDamageRandomRate, maxDamageRandomRate, _damageRandomRateRange);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool TryResolveBearingRange(out StatRange rotateSpeedRange, out StatRange attackRangeRange)
|
||||
{
|
||||
rotateSpeedRange = _rotateSpeedRange;
|
||||
attackRangeRange = _attackRangeRange;
|
||||
|
||||
IDataTable<DRBearingComp> dataTable = GameEntry.DataTable.GetDataTable<DRBearingComp>();
|
||||
if (dataTable == null || dataTable.Count <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DRBearingComp[] rows = dataTable.GetAllDataRows();
|
||||
if (rows == null || rows.Length <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasRotateSpeed = false;
|
||||
bool hasAttackRange = false;
|
||||
float minRotateSpeed = float.MaxValue;
|
||||
float maxRotateSpeed = float.MinValue;
|
||||
float minAttackRange = float.MaxValue;
|
||||
float maxAttackRange = float.MinValue;
|
||||
|
||||
for (int i = 0; i < rows.Length; i++)
|
||||
{
|
||||
DRBearingComp row = rows[i];
|
||||
if (row == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
IncludeValues(row.RotateSpeed, ref minRotateSpeed, ref maxRotateSpeed, ref hasRotateSpeed);
|
||||
IncludeValues(row.AttackRange, ref minAttackRange, ref maxAttackRange, ref hasAttackRange);
|
||||
}
|
||||
|
||||
if (!hasRotateSpeed || !hasAttackRange)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
rotateSpeedRange = BuildRange(minRotateSpeed, maxRotateSpeed, _rotateSpeedRange);
|
||||
attackRangeRange = BuildRange(minAttackRange, maxAttackRange, _attackRangeRange);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool TryResolveBaseRange(out StatRange attackSpeedRange)
|
||||
{
|
||||
attackSpeedRange = _attackSpeedRange;
|
||||
|
||||
IDataTable<DRBaseComp> dataTable = GameEntry.DataTable.GetDataTable<DRBaseComp>();
|
||||
if (dataTable == null || dataTable.Count <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DRBaseComp[] rows = dataTable.GetAllDataRows();
|
||||
if (rows == null || rows.Length <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasAttackSpeed = false;
|
||||
float minAttackSpeed = float.MaxValue;
|
||||
float maxAttackSpeed = float.MinValue;
|
||||
|
||||
for (int i = 0; i < rows.Length; i++)
|
||||
{
|
||||
DRBaseComp row = rows[i];
|
||||
if (row == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
IncludeValues(row.AttackSpeed, ref minAttackSpeed, ref maxAttackSpeed, ref hasAttackSpeed);
|
||||
}
|
||||
|
||||
if (!hasAttackSpeed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
attackSpeedRange = BuildRange(minAttackSpeed, maxAttackSpeed, _attackSpeedRange);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void FindTopTwoIndexes(float[] values, out int primaryIndex, out int secondaryIndex)
|
||||
{
|
||||
primaryIndex = 0;
|
||||
secondaryIndex = 1;
|
||||
|
||||
if (values[secondaryIndex] > values[primaryIndex])
|
||||
{
|
||||
(primaryIndex, secondaryIndex) = (secondaryIndex, primaryIndex);
|
||||
}
|
||||
|
||||
for (int i = 2; i < values.Length; i++)
|
||||
{
|
||||
float value = values[i];
|
||||
if (value > values[primaryIndex])
|
||||
{
|
||||
secondaryIndex = primaryIndex;
|
||||
primaryIndex = i;
|
||||
}
|
||||
else if (value > values[secondaryIndex])
|
||||
{
|
||||
secondaryIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static float ResolveSlotHueOffset(TowerCompSlotType slotType)
|
||||
{
|
||||
return slotType switch
|
||||
{
|
||||
TowerCompSlotType.Bearing => 15f,
|
||||
TowerCompSlotType.Base => -15f,
|
||||
_ => 0f
|
||||
};
|
||||
}
|
||||
|
||||
private static float ResolveArrayValue(int[] values)
|
||||
{
|
||||
if (values == null || values.Length <= 0)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
return Mathf.Max(0f, values[0]);
|
||||
}
|
||||
|
||||
private static float ResolveArrayValue(float[] values)
|
||||
{
|
||||
if (values == null || values.Length <= 0)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
return Mathf.Max(0f, values[0]);
|
||||
}
|
||||
|
||||
private static void IncludeValues(int[] values, ref float min, ref float max, ref bool hasValue)
|
||||
{
|
||||
if (values == null || values.Length <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < values.Length; i++)
|
||||
{
|
||||
IncludeValue(Mathf.Max(0f, values[i]), ref min, ref max, ref hasValue);
|
||||
}
|
||||
}
|
||||
|
||||
private static void IncludeValues(float[] values, ref float min, ref float max, ref bool hasValue)
|
||||
{
|
||||
if (values == null || values.Length <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < values.Length; i++)
|
||||
{
|
||||
IncludeValue(Mathf.Max(0f, values[i]), ref min, ref max, ref hasValue);
|
||||
}
|
||||
}
|
||||
|
||||
private static void IncludeValue(float value, ref float min, ref float max, ref bool hasValue)
|
||||
{
|
||||
if (float.IsNaN(value) || float.IsInfinity(value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hasValue)
|
||||
{
|
||||
min = value;
|
||||
max = value;
|
||||
hasValue = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
min = value;
|
||||
}
|
||||
|
||||
if (value > max)
|
||||
{
|
||||
max = value;
|
||||
}
|
||||
}
|
||||
|
||||
private static float Normalize(float value, StatRange range)
|
||||
{
|
||||
float denominator = Mathf.Max(TinyValue, range.Max - range.Min);
|
||||
return Mathf.Clamp01((value - range.Min) / denominator);
|
||||
}
|
||||
|
||||
private static StatRange BuildRange(float min, float max, StatRange fallback)
|
||||
{
|
||||
if (float.IsNaN(min) || float.IsInfinity(min) || float.IsNaN(max) || float.IsInfinity(max))
|
||||
{
|
||||
return fallback;
|
||||
}
|
||||
|
||||
if (max - min < TinyValue)
|
||||
{
|
||||
return fallback;
|
||||
}
|
||||
|
||||
return new StatRange(min, max);
|
||||
}
|
||||
|
||||
private static float LerpHue(float fromDegree, float toDegree, float t)
|
||||
{
|
||||
float delta = Mathf.DeltaAngle(fromDegree, toDegree);
|
||||
return fromDegree + delta * Mathf.Clamp01(t);
|
||||
}
|
||||
|
||||
private static float NormalizeHue(float hueDegree)
|
||||
{
|
||||
float normalized = hueDegree % 360f;
|
||||
if (normalized < 0f)
|
||||
{
|
||||
normalized += 360f;
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private readonly struct StatRange
|
||||
{
|
||||
public StatRange(float min, float max)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
|
||||
public float Min { get; }
|
||||
public float Max { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using GeometryTD.Definition;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
@@ -14,15 +13,17 @@ namespace GeometryTD.UI
|
||||
|
||||
private IconAreaContext _context;
|
||||
|
||||
public Sprite CurrentIconSprite => _icon != null ? _icon.sprite : null;
|
||||
public virtual Sprite CurrentIconSprite => _icon != null ? _icon.sprite : null;
|
||||
|
||||
public Color CurrentIconColor => _icon != null ? _icon.color : Color.white;
|
||||
public virtual Color CurrentIconColor => _icon != null ? _icon.color : Color.white;
|
||||
|
||||
public Vector2 CurrentIconSize => _icon != null ? _icon.rectTransform.rect.size : Vector2.zero;
|
||||
public virtual Vector2 CurrentIconSize => _icon != null ? _icon.rectTransform.rect.size : Vector2.zero;
|
||||
|
||||
public Material CurrentIconMaterial => _icon != null ? _icon.material : null;
|
||||
public virtual Material CurrentIconMaterial => _icon != null ? _icon.material : null;
|
||||
|
||||
public void OnInit(IconAreaContext context)
|
||||
public virtual RectTransform IconRectTransform => _icon != null ? _icon.rectTransform : null;
|
||||
|
||||
public virtual void OnInit(IconAreaContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
@@ -46,9 +47,10 @@ namespace GeometryTD.UI
|
||||
|
||||
SetRarity(_context.Rarity);
|
||||
SetIconColor(_context.Color);
|
||||
SetIconVisible(true);
|
||||
}
|
||||
|
||||
public void SetIcon(Sprite sprite)
|
||||
public virtual void SetIcon(Sprite sprite)
|
||||
{
|
||||
if (_icon != null)
|
||||
{
|
||||
@@ -56,7 +58,7 @@ namespace GeometryTD.UI
|
||||
}
|
||||
}
|
||||
|
||||
public void SetRarity(RarityType rarity)
|
||||
public virtual void SetRarity(RarityType rarity)
|
||||
{
|
||||
if (_board == null)
|
||||
{
|
||||
@@ -74,7 +76,7 @@ namespace GeometryTD.UI
|
||||
};
|
||||
}
|
||||
|
||||
public void SetIconColor(Color color)
|
||||
public virtual void SetIconColor(Color color)
|
||||
{
|
||||
if (_icon == null)
|
||||
{
|
||||
@@ -84,11 +86,20 @@ namespace GeometryTD.UI
|
||||
_icon.color = color;
|
||||
}
|
||||
|
||||
public void OnReset()
|
||||
public virtual void SetIconVisible(bool visible)
|
||||
{
|
||||
if (_icon != null)
|
||||
{
|
||||
_icon.enabled = visible;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnReset()
|
||||
{
|
||||
SetIcon(null);
|
||||
SetRarity(RarityType.None);
|
||||
SetIconColor(Color.clear);
|
||||
SetIconVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class TowerIconArea : IconArea
|
||||
{
|
||||
[SerializeField] private Image _baseIcon;
|
||||
|
||||
[SerializeField] private Image _bearingIcon;
|
||||
|
||||
[SerializeField] private Image _muzzleIcon;
|
||||
|
||||
public Sprite BaseIconSprite => _baseIcon != null ? _baseIcon.sprite : null;
|
||||
|
||||
public Sprite BearingIconSprite => _bearingIcon != null ? _bearingIcon.sprite : null;
|
||||
|
||||
public Sprite MuzzleIconSprite => _muzzleIcon != null ? _muzzleIcon.sprite : null;
|
||||
|
||||
public Color BaseIconColor => _baseIcon != null ? _baseIcon.color : Color.white;
|
||||
|
||||
public Color BearingIconColor => _bearingIcon != null ? _bearingIcon.color : Color.white;
|
||||
|
||||
public Color MuzzleIconColor => _muzzleIcon != null ? _muzzleIcon.color : Color.white;
|
||||
|
||||
public Material BaseIconMaterial => _baseIcon != null ? _baseIcon.material : null;
|
||||
|
||||
public Material BearingIconMaterial => _bearingIcon != null ? _bearingIcon.material : null;
|
||||
|
||||
public Material MuzzleIconMaterial => _muzzleIcon != null ? _muzzleIcon.material : null;
|
||||
|
||||
public override void OnInit(IconAreaContext context)
|
||||
{
|
||||
if (!(context is TowerIconAreaContext towerContext))
|
||||
{
|
||||
base.OnInit(context);
|
||||
return;
|
||||
}
|
||||
|
||||
SetRarity(towerContext.Rarity);
|
||||
SetIconVisible(false);
|
||||
|
||||
SetLayerColor(_baseIcon, towerContext.BaseColor);
|
||||
SetLayerColor(_bearingIcon, towerContext.BearingColor);
|
||||
SetLayerColor(_muzzleIcon, towerContext.MuzzleColor);
|
||||
}
|
||||
|
||||
public void OnInit(TowerIconAreaContext context)
|
||||
{
|
||||
OnInit((IconAreaContext)context);
|
||||
}
|
||||
|
||||
public override void OnReset()
|
||||
{
|
||||
base.OnReset();
|
||||
SetLayerColor(_baseIcon, Color.clear);
|
||||
SetLayerColor(_bearingIcon, Color.clear);
|
||||
SetLayerColor(_muzzleIcon, Color.clear);
|
||||
SetIconVisible(false);
|
||||
}
|
||||
|
||||
private static void SetLayerColor(Image icon, Color color)
|
||||
{
|
||||
if (icon == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
icon.color = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 33a1436bff53c844e858f3bced1565ca
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user