拆分 UIController 组装 Context 职责 + 描述文本滚动展示

This commit is contained in:
SepComet
2026-03-12 16:45:20 +08:00
parent 4962b98714
commit f67888a8da
26 changed files with 2522 additions and 1053 deletions
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 05393ff6a1d531544bac8ffe4328d917
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,269 @@
using System.Collections.Generic;
using GeometryTD.CustomUtility;
using GeometryTD.Definition;
using UnityEngine;
namespace GeometryTD.UI
{
public partial class CombatFinishFormController
{
private CombatFinishFormContext BuildContext(CombatFinishFormRawData rawData)
{
_itemDescSeedMap.Clear();
if (rawData == null)
{
return null;
}
return new CombatFinishFormContext
{
EnemyKilledText = rawData.DefeatedEnemyCount.ToString(),
GoldGainedText = rawData.GainedGold.ToString(),
RewardItems = BuildRewardItems(rawData.RewardInventory),
CanReturn = rawData.CanReturn
};
}
private RepoItemContext[] BuildRewardItems(BackpackInventoryData inventory)
{
if (inventory == null)
{
return System.Array.Empty<RepoItemContext>();
}
Dictionary<long, MuzzleCompItemData> muzzleMap = BuildComponentMap(inventory.MuzzleComponents);
Dictionary<long, BearingCompItemData> bearingMap = BuildComponentMap(inventory.BearingComponents);
Dictionary<long, BaseCompItemData> baseMap = BuildComponentMap(inventory.BaseComponents);
List<RepoItemContext> itemContexts = new List<RepoItemContext>();
if (inventory.Towers != null)
{
foreach (TowerItemData tower in inventory.Towers)
{
if (tower == null)
{
continue;
}
itemContexts.Add(new RepoItemContext
{
InstanceId = tower.InstanceId,
CanDrag = false,
EnduranceRate01 = ItemDescUtility.ResolveTowerEnduranceRate(tower, muzzleMap, bearingMap, baseMap),
ClickActionType = RepoItemClickActionType.OpenDetail,
ComponentSlotType = TowerCompSlotType.None,
IconAreaContext = BuildTowerIconContext(tower, muzzleMap, bearingMap, baseMap)
});
AddItemDescSeed(
tower.InstanceId,
tower.Name,
"Tower",
ItemDescUtility.BuildTowerDesc(tower, muzzleMap, bearingMap, baseMap) ?? string.Empty,
tower.Stats?.Tags,
tower.Stats?.TagRuntimes);
}
}
if (inventory.MuzzleComponents != null)
{
foreach (MuzzleCompItemData item in inventory.MuzzleComponents)
{
if (item == null)
{
continue;
}
itemContexts.Add(new RepoItemContext
{
InstanceId = item.InstanceId,
CanDrag = false,
EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item),
ClickActionType = RepoItemClickActionType.OpenDetail,
ComponentSlotType = TowerCompSlotType.Muzzle,
IconAreaContext = BuildIconAreaContext(item)
});
AddItemDescSeed(
item.InstanceId,
item.Name,
BuildComponentTypeText(item.SlotType),
ItemDescUtility.BuildMuzzleDesc(item) ?? string.Empty,
item.Tags,
null);
}
}
if (inventory.BearingComponents != null)
{
foreach (BearingCompItemData item in inventory.BearingComponents)
{
if (item == null)
{
continue;
}
itemContexts.Add(new RepoItemContext
{
InstanceId = item.InstanceId,
CanDrag = false,
EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item),
ClickActionType = RepoItemClickActionType.OpenDetail,
ComponentSlotType = TowerCompSlotType.Bearing,
IconAreaContext = BuildIconAreaContext(item)
});
AddItemDescSeed(
item.InstanceId,
item.Name,
BuildComponentTypeText(item.SlotType),
ItemDescUtility.BuildBearingDesc(item) ?? string.Empty,
item.Tags,
null);
}
}
if (inventory.BaseComponents != null)
{
foreach (BaseCompItemData item in inventory.BaseComponents)
{
if (item == null)
{
continue;
}
itemContexts.Add(new RepoItemContext
{
InstanceId = item.InstanceId,
CanDrag = false,
EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item),
ClickActionType = RepoItemClickActionType.OpenDetail,
ComponentSlotType = TowerCompSlotType.Base,
IconAreaContext = BuildIconAreaContext(item)
});
AddItemDescSeed(
item.InstanceId,
item.Name,
BuildComponentTypeText(item.SlotType),
ItemDescUtility.BuildBaseDesc(item) ?? string.Empty,
item.Tags,
null);
}
}
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,
TagRuntimeData[] tagRuntimes)
{
if (itemId <= 0)
{
return;
}
_itemDescSeedMap[itemId] = new ItemDescSeed
{
Title = string.IsNullOrWhiteSpace(title) ? $"Item {itemId}" : title,
TypeText = typeText ?? string.Empty,
Description = description ?? string.Empty,
Tags = tags,
TagRuntimes = tagRuntimes
};
}
private static string BuildComponentTypeText(TowerCompSlotType slotType)
{
return slotType switch
{
TowerCompSlotType.Muzzle => "Muzzle Component",
TowerCompSlotType.Bearing => "Bearing Component",
TowerCompSlotType.Base => "Base Component",
TowerCompSlotType.Accessory => "Accessory",
_ => "Component"
};
}
private static Dictionary<long, TComp> BuildComponentMap<TComp>(IReadOnlyList<TComp> items)
where TComp : TowerCompItemData
{
Dictionary<long, TComp> map = new Dictionary<long, TComp>();
if (items == null)
{
return map;
}
foreach (TComp item in items)
{
if (item == null || item.InstanceId <= 0)
{
continue;
}
map[item.InstanceId] = item;
}
return map;
}
private static IconAreaContext BuildIconAreaContext(TowerCompItemData item)
{
if (item == null)
{
return new IconAreaContext
{
ComponentSlotType = TowerCompSlotType.None,
Rarity = RarityType.None,
Color = Color.white,
Icon = null
};
}
return new IconAreaContext
{
ComponentSlotType = item.SlotType,
Rarity = item.Rarity,
Color = IconColorGenerator.GenerateForComponent(item),
Icon = null
};
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 985f3ab0e98b21f4c9c0872647df27d0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,76 @@
using GeometryTD.Definition;
using UnityEngine;
namespace GeometryTD.UI
{
public partial class CombatInfoFormController
{
private static CombatInfoFormContext BuildContext(CombatInfoFormRawData rawData)
{
if (rawData == null)
{
return null;
}
return new CombatInfoFormContext
{
LevelMetaText = BuildLevelMetaText(rawData.LevelThemeType, rawData.LevelId),
LevelPhaseText = BuildPhaseText(rawData.CurrentPhaseIndex, rawData.TotalPhaseCount),
CoinText = BuildCoinText(rawData.Coin),
BaseHpText = BuildBaseHpText(rawData.BaseHp, rawData.BaseHpMax),
EnemyHpRateText = BuildEnemyHpRateText(rawData.EnemyHpRateMultiplier),
CanPause = rawData.CanPause,
CanEnd = rawData.CanEnd
};
}
private static string BuildLevelMetaText(LevelThemeType themeType, int levelId)
{
if (levelId <= 0)
{
return "Map -";
}
return $"{themeType} Map.{levelId}";
}
private static string BuildPhaseText(int currentPhaseIndex, int totalPhaseCount)
{
int phaseIndex = currentPhaseIndex < 0 ? 0 : currentPhaseIndex;
if (totalPhaseCount <= 0)
{
return $"{phaseIndex}/?";
}
return $"Wave: {phaseIndex}/{totalPhaseCount}";
}
private static string BuildCoinText(int coin)
{
if (coin < 0)
{
return "Coin: -";
}
return $"Coin: {coin}";
}
private static string BuildBaseHpText(int baseHp, int baseHpMax)
{
if (baseHpMax <= 0)
{
return "\u57FA\u5730\uFF1A-";
}
int clampedHp = Mathf.Clamp(baseHp, 0, baseHpMax);
int percent = Mathf.RoundToInt((float)clampedHp / baseHpMax * 100f);
return $"\u57FA\u5730\uFF1A{percent}%";
}
private static string BuildEnemyHpRateText(int enemyHpRateMultiplier)
{
int resolvedMultiplier = enemyHpRateMultiplier > 0 ? enemyHpRateMultiplier : 1;
return $"\u96BE\u5EA6\uFF1A{resolvedMultiplier}x";
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3493c7f4a84ea9349a8286366f11962d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,77 @@
using UnityEngine;
namespace GeometryTD.UI
{
public partial class CombatSelectFormController
{
private static CombatSelectFormContext BuildContext(CombatSelectFormRawData rawData)
{
if (rawData == null)
{
return null;
}
return new CombatSelectFormContext
{
IsVisible = rawData.IsVisible,
ScreenPosition = rawData.ScreenPosition,
ShowBuildArea = rawData.IsVisible && rawData.DisplayMode == CombatSelectDisplayMode.Build,
ShowFuncArea = rawData.IsVisible && rawData.DisplayMode == CombatSelectDisplayMode.Func,
BuildItems = BuildItemContexts(rawData.BuildItems),
UpgradeItem = BuildItemContext(rawData.UpgradeItem),
DestroyItem = BuildItemContext(rawData.DestroyItem)
};
}
private static TowerSelectItemContext[] BuildItemContexts(TowerSelectItemRawData[] itemRawData)
{
if (itemRawData == null || itemRawData.Length <= 0)
{
return System.Array.Empty<TowerSelectItemContext>();
}
TowerSelectItemContext[] contexts = new TowerSelectItemContext[itemRawData.Length];
for (int i = 0; i < itemRawData.Length; i++)
{
contexts[i] = BuildItemContext(itemRawData[i]);
}
return contexts;
}
private static TowerSelectItemContext BuildItemContext(TowerSelectItemRawData rawData)
{
if (rawData == null)
{
return null;
}
return new TowerSelectItemContext
{
Icon = rawData.Icon,
PriceText = BuildPriceText(rawData.Price, rawData.IsGain),
IsVisible = rawData.IsVisible,
IsInteractable = rawData.IsInteractable,
ActionType = rawData.ActionType,
ActionIndex = rawData.ActionIndex,
TowerIconAreaContext = new TowerIconAreaContext
{
BaseColor = rawData.BaseColor,
BearingColor = rawData.BearingColor,
MuzzleColor = rawData.MuzzleColor
}
};
}
private static string BuildPriceText(int price, bool isGain)
{
int positivePrice = Mathf.Max(0, price);
if (isGain)
{
return $"+{positivePrice}";
}
return positivePrice.ToString();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c9f949f5f7e07424abba9b57426d0fab
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,14 +1,13 @@
using System.Collections.Generic;
using GameFramework.Event;
using GeometryTD.CustomEvent;
using GeometryTD.CustomUtility;
using GeometryTD.Definition;
using UnityEngine;
using UnityGameFramework.Runtime;
namespace GeometryTD.UI
{
public class CombatFinishFormController : UIFormControllerCommonBase<CombatFinishFormContext, CombatFinishForm>
public partial class CombatFinishFormController : UIFormControllerCommonBase<CombatFinishFormContext, CombatFinishForm>
{
private CombatFinishFormUseCase _useCase;
private readonly Dictionary<long, ItemDescSeed> _itemDescSeedMap = new Dictionary<long, ItemDescSeed>();
@@ -86,265 +85,6 @@ namespace GeometryTD.UI
_useCase = combatFinishFormUseCase;
}
private CombatFinishFormContext BuildContext(CombatFinishFormRawData rawData)
{
_itemDescSeedMap.Clear();
if (rawData == null)
{
return null;
}
return new CombatFinishFormContext
{
EnemyKilledText = rawData.DefeatedEnemyCount.ToString(),
GoldGainedText = rawData.GainedGold.ToString(),
RewardItems = BuildRewardItems(rawData.RewardInventory),
CanReturn = rawData.CanReturn
};
}
private RepoItemContext[] BuildRewardItems(BackpackInventoryData inventory)
{
if (inventory == null)
{
return System.Array.Empty<RepoItemContext>();
}
Dictionary<long, MuzzleCompItemData> muzzleMap = BuildComponentMap(inventory.MuzzleComponents);
Dictionary<long, BearingCompItemData> bearingMap = BuildComponentMap(inventory.BearingComponents);
Dictionary<long, BaseCompItemData> baseMap = BuildComponentMap(inventory.BaseComponents);
List<RepoItemContext> itemContexts = new List<RepoItemContext>();
if (inventory.Towers != null)
{
foreach (TowerItemData tower in inventory.Towers)
{
if (tower == null)
{
continue;
}
itemContexts.Add(new RepoItemContext
{
InstanceId = tower.InstanceId,
CanDrag = false,
EnduranceRate01 = ItemDescUtility.ResolveTowerEnduranceRate(tower, muzzleMap, bearingMap, baseMap),
ClickActionType = RepoItemClickActionType.OpenDetail,
ComponentSlotType = TowerCompSlotType.None,
IconAreaContext = BuildTowerIconContext(tower, muzzleMap, bearingMap, baseMap)
});
AddItemDescSeed(
tower.InstanceId,
tower.Name,
"Tower",
ItemDescUtility.BuildTowerDesc(tower, muzzleMap, bearingMap, baseMap) ?? string.Empty,
tower.Stats?.Tags,
tower.Stats?.TagRuntimes);
}
}
if (inventory.MuzzleComponents != null)
{
foreach (MuzzleCompItemData item in inventory.MuzzleComponents)
{
if (item == null)
{
continue;
}
itemContexts.Add(new RepoItemContext
{
InstanceId = item.InstanceId,
CanDrag = false,
EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item),
ClickActionType = RepoItemClickActionType.OpenDetail,
ComponentSlotType = TowerCompSlotType.Muzzle,
IconAreaContext = BuildIconAreaContext(item)
});
AddItemDescSeed(
item.InstanceId,
item.Name,
BuildComponentTypeText(item.SlotType),
ItemDescUtility.BuildMuzzleDesc(item) ?? string.Empty,
item.Tags,
null);
}
}
if (inventory.BearingComponents != null)
{
foreach (BearingCompItemData item in inventory.BearingComponents)
{
if (item == null)
{
continue;
}
itemContexts.Add(new RepoItemContext
{
InstanceId = item.InstanceId,
CanDrag = false,
EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item),
ClickActionType = RepoItemClickActionType.OpenDetail,
ComponentSlotType = TowerCompSlotType.Bearing,
IconAreaContext = BuildIconAreaContext(item)
});
AddItemDescSeed(
item.InstanceId,
item.Name,
BuildComponentTypeText(item.SlotType),
ItemDescUtility.BuildBearingDesc(item) ?? string.Empty,
item.Tags,
null);
}
}
if (inventory.BaseComponents != null)
{
foreach (BaseCompItemData item in inventory.BaseComponents)
{
if (item == null)
{
continue;
}
itemContexts.Add(new RepoItemContext
{
InstanceId = item.InstanceId,
CanDrag = false,
EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item),
ClickActionType = RepoItemClickActionType.OpenDetail,
ComponentSlotType = TowerCompSlotType.Base,
IconAreaContext = BuildIconAreaContext(item)
});
AddItemDescSeed(
item.InstanceId,
item.Name,
BuildComponentTypeText(item.SlotType),
ItemDescUtility.BuildBaseDesc(item) ?? string.Empty,
item.Tags,
null);
}
}
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,
TagRuntimeData[] tagRuntimes)
{
if (itemId <= 0)
{
return;
}
_itemDescSeedMap[itemId] = new ItemDescSeed
{
Title = string.IsNullOrWhiteSpace(title) ? $"Item {itemId}" : title,
TypeText = typeText ?? string.Empty,
Description = description ?? string.Empty,
Tags = tags,
TagRuntimes = tagRuntimes
};
}
private static string BuildComponentTypeText(TowerCompSlotType slotType)
{
return slotType switch
{
TowerCompSlotType.Muzzle => "Muzzle Component",
TowerCompSlotType.Bearing => "Bearing Component",
TowerCompSlotType.Base => "Base Component",
TowerCompSlotType.Accessory => "Accessory",
_ => "Component"
};
}
private static Dictionary<long, TComp> BuildComponentMap<TComp>(IReadOnlyList<TComp> items)
where TComp : TowerCompItemData
{
Dictionary<long, TComp> map = new Dictionary<long, TComp>();
if (items == null)
{
return map;
}
foreach (TComp item in items)
{
if (item == null || item.InstanceId <= 0)
{
continue;
}
map[item.InstanceId] = item;
}
return map;
}
private static IconAreaContext BuildIconAreaContext(TowerCompItemData item)
{
if (item == null)
{
return new IconAreaContext
{
ComponentSlotType = TowerCompSlotType.None,
Rarity = RarityType.None,
Color = Color.white,
Icon = null
};
}
return new IconAreaContext
{
ComponentSlotType = item.SlotType,
Rarity = item.Rarity,
Color = IconColorGenerator.GenerateForComponent(item),
Icon = null
};
}
#region Event Handlers
private void OnCombatFinishReturnButtonClicked(object sender, GameEventArgs e)
@@ -5,7 +5,7 @@ using UnityGameFramework.Runtime;
namespace GeometryTD.UI
{
public class CombatInfoFormController : UIFormControllerCommonBase<CombatInfoFormContext, CombatInfoForm>
public partial class CombatInfoFormController : UIFormControllerCommonBase<CombatInfoFormContext, CombatInfoForm>
{
private CombatInfoFormUseCase _useCase;
@@ -83,74 +83,6 @@ namespace GeometryTD.UI
_useCase = combatInfoFormUseCase;
}
private static CombatInfoFormContext BuildContext(CombatInfoFormRawData rawData)
{
if (rawData == null)
{
return null;
}
return new CombatInfoFormContext
{
LevelMetaText = BuildLevelMetaText(rawData.LevelThemeType, rawData.LevelId),
LevelPhaseText = BuildPhaseText(rawData.CurrentPhaseIndex, rawData.TotalPhaseCount),
CoinText = BuildCoinText(rawData.Coin),
BaseHpText = BuildBaseHpText(rawData.BaseHp, rawData.BaseHpMax),
EnemyHpRateText = BuildEnemyHpRateText(rawData.EnemyHpRateMultiplier),
CanPause = rawData.CanPause,
CanEnd = rawData.CanEnd
};
}
private static string BuildLevelMetaText(LevelThemeType themeType, int levelId)
{
if (levelId <= 0)
{
return "Map -";
}
return $"{themeType} Map.{levelId}";
}
private static string BuildPhaseText(int currentPhaseIndex, int totalPhaseCount)
{
int phaseIndex = currentPhaseIndex < 0 ? 0 : currentPhaseIndex;
if (totalPhaseCount <= 0)
{
return $"{phaseIndex}/?";
}
return $"Wave: {phaseIndex}/{totalPhaseCount}";
}
private static string BuildCoinText(int coin)
{
if (coin < 0)
{
return "Coin: -";
}
return $"Coin: {coin}";
}
private static string BuildBaseHpText(int baseHp, int baseHpMax)
{
if (baseHpMax <= 0)
{
return "\u57FA\u5730\uFF1A-";
}
int clampedHp = UnityEngine.Mathf.Clamp(baseHp, 0, baseHpMax);
int percent = UnityEngine.Mathf.RoundToInt((float)clampedHp / baseHpMax * 100f);
return $"\u57FA\u5730\uFF1A{percent}%";
}
private static string BuildEnemyHpRateText(int enemyHpRateMultiplier)
{
int resolvedMultiplier = enemyHpRateMultiplier > 0 ? enemyHpRateMultiplier : 1;
return $"\u96BE\u5EA6\uFF1A{resolvedMultiplier}x";
}
private void OnCombatPauseButtonClicked(object sender, GameEventArgs e)
{
if (!(sender is CombatInfoForm) || !(e is CombatPauseEventArgs))
@@ -6,7 +6,7 @@ using UnityGameFramework.Runtime;
namespace GeometryTD.UI
{
public class CombatSelectFormController : UIFormControllerCommonBase<CombatSelectFormContext, CombatSelectForm>
public partial class CombatSelectFormController : UIFormControllerCommonBase<CombatSelectFormContext, CombatSelectForm>
{
private CombatSelectFormUseCase _useCase;
@@ -180,76 +180,6 @@ namespace GeometryTD.UI
RefreshCurrentUI();
}
private static CombatSelectFormContext BuildContext(CombatSelectFormRawData rawData)
{
if (rawData == null)
{
return null;
}
return new CombatSelectFormContext
{
IsVisible = rawData.IsVisible,
ScreenPosition = rawData.ScreenPosition,
ShowBuildArea = rawData.IsVisible && rawData.DisplayMode == CombatSelectDisplayMode.Build,
ShowFuncArea = rawData.IsVisible && rawData.DisplayMode == CombatSelectDisplayMode.Func,
BuildItems = BuildItemContexts(rawData.BuildItems),
UpgradeItem = BuildItemContext(rawData.UpgradeItem),
DestroyItem = BuildItemContext(rawData.DestroyItem)
};
}
private static TowerSelectItemContext[] BuildItemContexts(TowerSelectItemRawData[] itemRawData)
{
if (itemRawData == null || itemRawData.Length <= 0)
{
return System.Array.Empty<TowerSelectItemContext>();
}
TowerSelectItemContext[] contexts = new TowerSelectItemContext[itemRawData.Length];
for (int i = 0; i < itemRawData.Length; i++)
{
contexts[i] = BuildItemContext(itemRawData[i]);
}
return contexts;
}
private static TowerSelectItemContext BuildItemContext(TowerSelectItemRawData rawData)
{
if (rawData == null)
{
return null;
}
return new TowerSelectItemContext
{
Icon = rawData.Icon,
PriceText = BuildPriceText(rawData.Price, rawData.IsGain),
IsVisible = rawData.IsVisible,
IsInteractable = rawData.IsInteractable,
ActionType = rawData.ActionType,
ActionIndex = rawData.ActionIndex,
TowerIconAreaContext = new TowerIconAreaContext()
{
BaseColor = rawData.BaseColor,
BearingColor = rawData.BearingColor,
MuzzleColor = rawData.MuzzleColor
}
};
}
private static string BuildPriceText(int price, bool isGain)
{
int positivePrice = Mathf.Max(0, price);
if (isGain)
{
return $"+{positivePrice}";
}
return positivePrice.ToString();
}
private void OnSelectItemClicked(object sender, GameEventArgs e)
{
if (!(e is CombatSelectItemClickEventArgs args))
@@ -0,0 +1,41 @@
using GeometryTD.Definition;
using GeometryTD.Procedure;
namespace GeometryTD.UI
{
public sealed partial class NodeMapFormController
{
private static NodeMapFormContext BuildContext(NodeMapFormRawData rawData)
{
NodeItemContext[] nodeItemContexts = System.Array.Empty<NodeItemContext>();
if (rawData?.Nodes != null && rawData.Nodes.Count > 0)
{
nodeItemContexts = new NodeItemContext[rawData.Nodes.Count];
for (int i = 0; i < rawData.Nodes.Count; i++)
{
NodeMapNodeRawData node = rawData.Nodes[i];
nodeItemContexts[i] = new NodeItemContext
{
NodeId = node?.NodeId ?? 0,
SequenceIndex = node?.SequenceIndex ?? i,
NodeType = node?.NodeType ?? RunNodeType.None,
IsLocked = node != null && node.Status == RunNodeStatus.Locked,
IsCurrent = node != null && node.IsCurrentNode,
IsCompleted = node != null && node.Status == RunNodeStatus.Completed,
IsException = node != null && node.Status == RunNodeStatus.Exception,
CanClick = node != null && node.CanEnter
};
}
}
return new NodeMapFormContext
{
Title = rawData?.Title ?? "节点地图",
ProgressText = rawData?.ProgressText ?? "0 / 0",
CurrentNodeText = rawData?.CurrentNodeText ?? "当前节点: 无",
IsRunCompleted = rawData != null && rawData.IsRunCompleted,
NodeItems = nodeItemContexts
};
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cf16e881b2eeae447b3ff2b36e4f6753
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -7,7 +7,7 @@ using UnityGameFramework.Runtime;
namespace GeometryTD.UI
{
public sealed class NodeMapFormController : UIFormControllerCommonBase<NodeMapFormContext, NodeMapForm>
public sealed partial class NodeMapFormController : UIFormControllerCommonBase<NodeMapFormContext, NodeMapForm>
{
private NodeMapFormUseCase _useCase;
@@ -126,37 +126,5 @@ namespace GeometryTD.UI
return false;
}
private static NodeMapFormContext BuildContext(NodeMapFormRawData rawData)
{
NodeItemContext[] nodeItemContexts = System.Array.Empty<NodeItemContext>();
if (rawData?.Nodes != null && rawData.Nodes.Count > 0)
{
nodeItemContexts = new NodeItemContext[rawData.Nodes.Count];
for (int i = 0; i < rawData.Nodes.Count; i++)
{
NodeMapNodeRawData node = rawData.Nodes[i];
nodeItemContexts[i] = new NodeItemContext
{
NodeId = node?.NodeId ?? 0,
SequenceIndex = node?.SequenceIndex ?? i,
NodeType = node?.NodeType ?? RunNodeType.None,
IsLocked = node != null && node.Status == RunNodeStatus.Locked,
IsCurrent = node != null && node.IsCurrentNode,
IsCompleted = node != null && node.Status == RunNodeStatus.Completed,
IsException = node != null && node.Status == RunNodeStatus.Exception,
CanClick = node != null && node.CanEnter
};
}
}
return new NodeMapFormContext
{
Title = rawData?.Title ?? "节点地图",
ProgressText = rawData?.ProgressText ?? "0 / 0",
CurrentNodeText = rawData?.CurrentNodeText ?? "当前节点: 无",
IsRunCompleted = rawData != null && rawData.IsRunCompleted,
NodeItems = nodeItemContexts
};
}
}
}
@@ -2,6 +2,7 @@ using System.Collections.Generic;
using GeometryTD.CustomEvent;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace GeometryTD.UI
{
@@ -15,6 +16,12 @@ namespace GeometryTD.UI
[SerializeField] private TMP_Text _descriptionText;
[SerializeField] private RectTransform _descriptionScrollView;
[SerializeField] private RectTransform _descriptionContent;
[SerializeField] private float _maxDescriptionViewportHeight = 0f;
[SerializeField] private Transform _tagItemParent;
[SerializeField] private TagItem _tagItemTemplate;
@@ -63,6 +70,8 @@ namespace GeometryTD.UI
_descriptionText.text = context.Description ?? string.Empty;
}
ResizeDescriptionArea();
RefreshTags(context.Tags);
}
@@ -90,6 +99,8 @@ namespace GeometryTD.UI
_descriptionText.text = string.Empty;
}
ResetDescriptionScroll();
ClearTags();
}
@@ -133,6 +144,54 @@ namespace GeometryTD.UI
}
}
private void ResizeDescriptionArea()
{
if (_descriptionText == null)
{
return;
}
_descriptionText.ForceMeshUpdate();
float descriptionHeight = Mathf.Max(0f, _descriptionText.preferredHeight);
SetRectHeight(_descriptionText.rectTransform, descriptionHeight);
if (_descriptionContent != null)
{
SetRectHeight(_descriptionContent, descriptionHeight);
}
if (_descriptionScrollView != null)
{
float viewportHeight = _maxDescriptionViewportHeight > 0f
? Mathf.Min(descriptionHeight, _maxDescriptionViewportHeight)
: descriptionHeight;
SetRectHeight(_descriptionScrollView, viewportHeight);
}
ResetDescriptionScroll();
}
private void ResetDescriptionScroll()
{
if (_descriptionScrollView != null &&
_descriptionScrollView.TryGetComponent(out ScrollRect scrollRect))
{
scrollRect.verticalNormalizedPosition = 1f;
}
}
private static void SetRectHeight(RectTransform rectTransform, float height)
{
if (rectTransform == null)
{
return;
}
Vector2 size = rectTransform.sizeDelta;
size.y = height;
rectTransform.sizeDelta = size;
}
private TagItem ResolveTagTemplate()
{
if (_tagItemTemplate != null)
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 536ee8a3207a3fb409592f249663f9c8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2ec97872405fc20419b0f156bb6c7365
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,59 @@
using GeometryTD.CustomUtility;
namespace GeometryTD.UI
{
public sealed partial class ShopFormController
{
private static ShopFormContext BuildContext(ShopFormRawData rawData)
{
GoodsItemContext[] goodsItemContexts = System.Array.Empty<GoodsItemContext>();
if (rawData?.GoodsItems != null && rawData.GoodsItems.Count > 0)
{
goodsItemContexts = new GoodsItemContext[rawData.GoodsItems.Count];
for (int i = 0; i < rawData.GoodsItems.Count; i++)
{
GoodsItemRawData item = rawData.GoodsItems[i];
goodsItemContexts[i] = new GoodsItemContext
{
GoodsIndex = item?.GoodsIndex ?? i,
Title = item?.Title ?? string.Empty,
TypeText = item?.TypeText ?? string.Empty,
Description = BuildDescription(item),
TagTexts = BuildTagTexts(item),
PurchaseButtonText = item != null && item.IsPurchased ? "已购买" : $"购买 {item?.Price ?? 0}",
CanPurchase = item != null && !item.IsPurchased,
IconAreaContext = item?.IconAreaContext
};
}
}
return new ShopFormContext
{
GoldText = $"金币: {rawData?.PlayerGold ?? 0}",
GoodsItems = goodsItemContexts
};
}
private static string BuildDescription(GoodsItemRawData rawData)
{
string baseDescription = rawData?.Description ?? string.Empty;
string tagDescription = TagDisplayUtility.BuildTagDescriptionText(rawData?.Tags);
if (string.IsNullOrWhiteSpace(tagDescription))
{
return baseDescription;
}
if (string.IsNullOrWhiteSpace(baseDescription))
{
return tagDescription;
}
return $"{baseDescription}\n{tagDescription}";
}
private static string[] BuildTagTexts(GoodsItemRawData rawData)
{
return TagDisplayUtility.BuildTagTexts(rawData?.Tags);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3da82624de00938408d9de7b74f09459
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,13 +1,12 @@
using GeometryTD.CustomEvent;
using GeometryTD.Definition;
using GameFramework.Event;
using GeometryTD.CustomUtility;
using UnityEngine;
using UnityGameFramework.Runtime;
namespace GeometryTD.UI
{
public sealed class ShopFormController : UIFormControllerCommonBase<ShopFormContext, ShopForm>
public sealed partial class ShopFormController : UIFormControllerCommonBase<ShopFormContext, ShopForm>
{
private ShopFormUseCase _useCase;
@@ -134,56 +133,5 @@ namespace GeometryTD.UI
return false;
}
private static ShopFormContext BuildContext(ShopFormRawData rawData)
{
GoodsItemContext[] goodsItemContexts = System.Array.Empty<GoodsItemContext>();
if (rawData?.GoodsItems != null && rawData.GoodsItems.Count > 0)
{
goodsItemContexts = new GoodsItemContext[rawData.GoodsItems.Count];
for (int i = 0; i < rawData.GoodsItems.Count; i++)
{
GoodsItemRawData item = rawData.GoodsItems[i];
goodsItemContexts[i] = new GoodsItemContext
{
GoodsIndex = item?.GoodsIndex ?? i,
Title = item?.Title ?? string.Empty,
TypeText = item?.TypeText ?? string.Empty,
Description = BuildDescription(item),
TagTexts = BuildTagTexts(item),
PurchaseButtonText = item != null && item.IsPurchased ? "已购买" : $"购买 {item?.Price ?? 0}",
CanPurchase = item != null && !item.IsPurchased,
IconAreaContext = item?.IconAreaContext
};
}
}
return new ShopFormContext
{
GoldText = $"金币: {rawData?.PlayerGold ?? 0}",
GoodsItems = goodsItemContexts
};
}
private static string BuildDescription(GoodsItemRawData rawData)
{
string baseDescription = rawData?.Description ?? string.Empty;
string tagDescription = TagDisplayUtility.BuildTagDescriptionText(rawData?.Tags);
if (string.IsNullOrWhiteSpace(tagDescription))
{
return baseDescription;
}
if (string.IsNullOrWhiteSpace(baseDescription))
{
return tagDescription;
}
return $"{baseDescription}\n{tagDescription}";
}
private static string[] BuildTagTexts(GoodsItemRawData rawData)
{
return TagDisplayUtility.BuildTagTexts(rawData?.Tags);
}
}
}
@@ -1,6 +1,7 @@
using GeometryTD.CustomEvent;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace GeometryTD.UI
{
@@ -13,6 +14,12 @@ namespace GeometryTD.UI
[SerializeField] private TMP_Text _typeText;
[SerializeField] private TMP_Text _descriptionText;
[SerializeField] private RectTransform _descriptionScrollView;
[SerializeField] private RectTransform _descriptionContent;
[SerializeField] private float _maxDescriptionViewportHeight = 0f;
[SerializeField] private Transform _tagsParent;
@@ -46,6 +53,8 @@ namespace GeometryTD.UI
_descriptionText.text = context?.Description ?? string.Empty;
}
ResizeDescriptionArea();
if (_purchaseButtonText != null)
{
_purchaseButtonText.text = context?.PurchaseButtonText ?? string.Empty;
@@ -75,6 +84,8 @@ namespace GeometryTD.UI
_descriptionText.text = string.Empty;
}
ResetDescriptionScroll();
if (_purchaseButtonText != null)
{
_purchaseButtonText.text = string.Empty;
@@ -120,6 +131,54 @@ namespace GeometryTD.UI
}
}
private void ResizeDescriptionArea()
{
if (_descriptionText == null)
{
return;
}
_descriptionText.ForceMeshUpdate();
float descriptionHeight = Mathf.Max(0f, _descriptionText.preferredHeight);
SetRectHeight(_descriptionText.rectTransform, descriptionHeight);
if (_descriptionContent != null)
{
SetRectHeight(_descriptionContent, descriptionHeight);
}
if (_descriptionScrollView != null)
{
float viewportHeight = _maxDescriptionViewportHeight > 0f
? Mathf.Min(descriptionHeight, _maxDescriptionViewportHeight)
: descriptionHeight;
SetRectHeight(_descriptionScrollView, viewportHeight);
}
ResetDescriptionScroll();
}
private void ResetDescriptionScroll()
{
if (_descriptionScrollView != null &&
_descriptionScrollView.TryGetComponent(out ScrollRect scrollRect))
{
scrollRect.verticalNormalizedPosition = 1f;
}
}
private static void SetRectHeight(RectTransform rectTransform, float height)
{
if (rectTransform == null)
{
return;
}
Vector2 size = rectTransform.sizeDelta;
size.y = height;
rectTransform.sizeDelta = size;
}
private void ClearTags()
{
if (_tagsParent == null)