添加“奖励 3 选 1”UI

- RewardSelectForm:其中包括 3 个可选的 RewardItem ,刷新和放弃按钮
- 应用战斗节点基地生命产生的额外事件
This commit is contained in:
SepComet
2026-03-02 21:42:27 +08:00
parent daba9cbdf9
commit 3e52a4df55
52 changed files with 4495 additions and 133 deletions
@@ -111,7 +111,8 @@ namespace GeometryTD.UI
{
Title = $"[Tower] {tower.Name} ({tower.Rarity})",
InstanceId = tower.InstanceId,
ComponentSlotType = TowerCompSlotType.None
ComponentSlotType = TowerCompSlotType.None,
IconAreaContext = BuildIconAreaContext(tower.Rarity)
});
}
}
@@ -130,7 +131,8 @@ namespace GeometryTD.UI
{
Title = $"[Muzzle] {item.Name} ({item.Rarity})",
InstanceId = item.InstanceId,
ComponentSlotType = TowerCompSlotType.Muzzle
ComponentSlotType = TowerCompSlotType.Muzzle,
IconAreaContext = BuildIconAreaContext(item.Rarity)
});
}
}
@@ -149,7 +151,8 @@ namespace GeometryTD.UI
{
Title = $"[Bearing] {item.Name} ({item.Rarity})",
InstanceId = item.InstanceId,
ComponentSlotType = TowerCompSlotType.Bearing
ComponentSlotType = TowerCompSlotType.Bearing,
IconAreaContext = BuildIconAreaContext(item.Rarity)
});
}
}
@@ -168,7 +171,8 @@ namespace GeometryTD.UI
{
Title = $"[Base] {item.Name} ({item.Rarity})",
InstanceId = item.InstanceId,
ComponentSlotType = TowerCompSlotType.Base
ComponentSlotType = TowerCompSlotType.Base,
IconAreaContext = BuildIconAreaContext(item.Rarity)
});
}
}
@@ -176,6 +180,15 @@ namespace GeometryTD.UI
return itemContexts.ToArray();
}
private static IconAreaContext BuildIconAreaContext(RarityType rarity)
{
return new IconAreaContext
{
Rarity = rarity,
Icon = null
};
}
private void OnCombatFinishReturnButtonClicked(object sender, GameEventArgs e)
{
if (!(sender is CombatFinishForm) || !(e is CombatFinishReturnEventArgs))
@@ -7,5 +7,6 @@ namespace GeometryTD.UI
public string Title;
public long InstanceId;
public TowerCompSlotType ComponentSlotType;
public IconAreaContext IconAreaContext;
}
}
@@ -93,7 +93,8 @@ namespace GeometryTD.UI
{
Title = $"[Tower] {tower.Name} ({tower.Rarity})",
InstanceId = tower.InstanceId,
ComponentSlotType = TowerCompSlotType.None
ComponentSlotType = TowerCompSlotType.None,
IconAreaContext = BuildIconAreaContext(tower.Rarity)
});
}
}
@@ -106,7 +107,8 @@ namespace GeometryTD.UI
{
Title = $"[Muzzle] {item.Name} ({item.Rarity})",
InstanceId = item.InstanceId,
ComponentSlotType = TowerCompSlotType.Muzzle
ComponentSlotType = TowerCompSlotType.Muzzle,
IconAreaContext = BuildIconAreaContext(item.Rarity)
});
}
}
@@ -119,7 +121,8 @@ namespace GeometryTD.UI
{
Title = $"[Bearing] {item.Name} ({item.Rarity})",
InstanceId = item.InstanceId,
ComponentSlotType = TowerCompSlotType.Bearing
ComponentSlotType = TowerCompSlotType.Bearing,
IconAreaContext = BuildIconAreaContext(item.Rarity)
});
}
}
@@ -132,7 +135,8 @@ namespace GeometryTD.UI
{
Title = $"[Base] {item.Name} ({item.Rarity})",
InstanceId = item.InstanceId,
ComponentSlotType = TowerCompSlotType.Base
ComponentSlotType = TowerCompSlotType.Base,
IconAreaContext = BuildIconAreaContext(item.Rarity)
});
}
}
@@ -158,6 +162,15 @@ namespace GeometryTD.UI
_itemContextMap[itemContext.InstanceId] = itemContext;
}
private static IconAreaContext BuildIconAreaContext(RarityType rarity)
{
return new IconAreaContext
{
Rarity = rarity,
Icon = null
};
}
private void OnRepoItemSelected(object sender, GameEventArgs e)
{
if (!(e is RepoItemSelectedEventArgs args))
@@ -1,4 +1,3 @@
using System.Collections.Generic;
using GeometryTD.Definition;
namespace GeometryTD.UI
@@ -2,7 +2,6 @@ using GeometryTD.CustomEvent;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using UnityGameFramework.Runtime;
namespace GeometryTD.UI
{
@@ -10,6 +9,7 @@ namespace GeometryTD.UI
{
[SerializeField] private TMP_Text _titleText;
[SerializeField] private Image _highlightImage;
[SerializeField] private IconArea _iconArea;
private static readonly Color NormalColor = new Color32(40, 40, 40, 180);
private static readonly Color SelectedColor = new Color32(255, 216, 102, 255);
@@ -31,6 +31,8 @@ namespace GeometryTD.UI
_titleText.text = context.Title ?? string.Empty;
}
_iconArea.OnInit(context.IconAreaContext);
SetSelected(false);
}
@@ -0,0 +1,12 @@
using GeometryTD.Definition;
using GeometryTD.UI;
using UnityEngine;
namespace GeometryTD.UI
{
public class IconAreaContext : UIContext
{
public RarityType Rarity;
public Sprite Icon;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c5d39fc6e1ad1fe4ba9d2454eb9a0cb3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,15 @@
namespace GeometryTD.UI
{
public class RewardItemContext : UIContext
{
public int Index;
public long RewardId;
public IconAreaContext IconArea;
public string Title;
public string TypeText;
public string Description;
public TagItemContext[] Tags;
public bool IsSelectable;
public object UserData;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8ab52d2f24634cd47bd8344b69dc6ee9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,11 @@
namespace GeometryTD.UI
{
public class RewardSelectFormContext : UIContext
{
public string TipText;
public string RefreshButtonText;
public bool CanRefresh;
public bool CanGiveUp;
public RewardItemContext[] RewardItems;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6f4ec685dcc5a07458a149792aa422f1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,11 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace GeometryTD.UI
{
public class TagItemContext : UIContext
{
public string TagName;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 83fe4616261e1614e8fc6c049cbe4606
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,290 @@
using System;
using GeometryTD.CustomEvent;
using GeometryTD.DataTable;
using GeometryTD.Definition;
using GameFramework.Event;
using UnityEngine;
using UnityGameFramework.Runtime;
namespace GeometryTD.UI
{
public class RewardSelectFormController : UIFormControllerCommonBase<RewardSelectFormContext, RewardSelectForm>
{
private RewardSelectFormUseCase _useCase;
protected override UIFormType UIFormTypeId => UIFormType.RewardSelectForm;
protected override void RefreshUI(RewardSelectForm form, RewardSelectFormContext context)
{
form.RefreshUI(context);
}
protected override void SubscribeCustomEvents()
{
GameEntry.Event.Subscribe(RewardSelectItemSelectedEventArgs.EventId, OnRewardSelected);
GameEntry.Event.Subscribe(RewardSelectRefreshEventArgs.EventId, OnRefreshClicked);
GameEntry.Event.Subscribe(RewardSelectGiveUpEventArgs.EventId, OnGiveUpClicked);
}
protected override void UnsubscribeCustomEvents()
{
GameEntry.Event.Unsubscribe(RewardSelectItemSelectedEventArgs.EventId, OnRewardSelected);
GameEntry.Event.Unsubscribe(RewardSelectRefreshEventArgs.EventId, OnRefreshClicked);
GameEntry.Event.Unsubscribe(RewardSelectGiveUpEventArgs.EventId, OnGiveUpClicked);
}
public override int? OpenUI(object userData = null)
{
if (userData is RewardSelectFormContext context)
{
return OpenUIInternal(context);
}
if (userData is RewardSelectFormRawData rawDataFromUserData)
{
return OpenUI(rawDataFromUserData);
}
if (userData != null)
{
Log.Warning("RewardSelectFormController.OpenUI() userData type is invalid.");
return null;
}
if (_useCase == null)
{
Log.Error("RewardSelectFormController.OpenUI() useCase is null.");
return null;
}
RewardSelectFormRawData rawData = _useCase.CreateInitialModel();
return OpenUI(rawData);
}
public int? OpenUI(RewardSelectFormRawData rawData)
{
RewardSelectFormContext context = BuildContext(rawData);
return OpenUIInternal(context);
}
public override void BindUseCase(IUIUseCase useCase)
{
if (!(useCase is RewardSelectFormUseCase rewardSelectUseCase))
{
Log.Error("RewardSelectFormController.BindUseCase() useCase is invalid.");
return;
}
_useCase = rewardSelectUseCase;
}
private static RewardSelectFormContext BuildContext(RewardSelectFormRawData rawData)
{
if (rawData == null)
{
return null;
}
return new RewardSelectFormContext
{
TipText = string.IsNullOrWhiteSpace(rawData.TipText) ? "Select one reward" : rawData.TipText,
RefreshButtonText = BuildRefreshButtonText(rawData.RefreshCost, rawData.CanRefresh),
CanRefresh = rawData.CanRefresh,
CanGiveUp = rawData.CanGiveUp,
RewardItems = BuildRewardItemContexts(rawData.RewardItems)
};
}
private static string BuildRefreshButtonText(int refreshCost, bool canRefresh)
{
if (!canRefresh)
{
return "Refreshed";
}
if (refreshCost <= 0)
{
return "Refresh";
}
return $"Refresh -{refreshCost}";
}
private static RewardItemContext[] BuildRewardItemContexts(RewardSelectItemRawData[] rawItems)
{
if (rawItems == null || rawItems.Length <= 0)
{
return System.Array.Empty<RewardItemContext>();
}
RewardItemContext[] contexts = new RewardItemContext[rawItems.Length];
for (int i = 0; i < rawItems.Length; i++)
{
RewardSelectItemRawData rawItem = rawItems[i];
if (rawItem == null)
{
continue;
}
contexts[i] = new RewardItemContext
{
Index = i,
RewardId = rawItem.RewardId,
IconArea = new IconAreaContext
{
Icon = rawItem.Icon,
Rarity = rawItem.Rarity
},
Title = rawItem.Title ?? string.Empty,
TypeText = ResolveTypeText(rawItem),
Description = rawItem.Description ?? string.Empty,
Tags = BuildTagContexts(rawItem.Tags),
IsSelectable = rawItem.IsSelectable,
UserData = rawItem.UserData
};
}
return contexts;
}
private static string ResolveTypeText(RewardSelectItemRawData rawItem)
{
if (!string.IsNullOrWhiteSpace(rawItem.TypeText))
{
return rawItem.TypeText;
}
return rawItem.SlotType switch
{
TowerCompSlotType.Muzzle => "Muzzle Component",
TowerCompSlotType.Bearing => "Bearing Component",
TowerCompSlotType.Base => "Base Component",
TowerCompSlotType.Accessory => "Accessory",
_ => "Component"
};
}
private static TagItemContext[] BuildTagContexts(TagType[] tags)
{
if (tags == null || tags.Length <= 0)
{
return System.Array.Empty<TagItemContext>();
}
TagItemContext[] contexts = new TagItemContext[tags.Length];
for (int i = 0; i < tags.Length; i++)
{
TagType tagType = tags[i];
contexts[i] = new TagItemContext
{
TagName = ResolveTagName(tagType)
};
}
return contexts;
}
private static string ResolveTagName(TagType tagType)
{
if (tagType == TagType.None)
{
return string.Empty;
}
var tagTable = GameEntry.DataTable.GetDataTable<DRTag>();
if (tagTable != null)
{
DRTag tagRow = tagTable.GetDataRow((int)tagType);
if (tagRow != null && !string.IsNullOrWhiteSpace(tagRow.Name))
{
return tagRow.Name;
}
}
return tagType.ToString();
}
private void OnRewardSelected(object sender, GameEventArgs e)
{
if (!IsEventFromCurrentForm(sender) || !(e is RewardSelectItemSelectedEventArgs args))
{
return;
}
if (_useCase == null)
{
return;
}
RewardSelectFormRawData nextRawData = _useCase.SelectReward(args.SelectedIndex);
if (nextRawData == null)
{
CloseUI();
return;
}
OpenUI(nextRawData);
}
private void OnRefreshClicked(object sender, GameEventArgs e)
{
if (!IsEventFromCurrentForm(sender) || !(e is RewardSelectRefreshEventArgs))
{
return;
}
if (_useCase == null)
{
return;
}
RewardSelectFormRawData nextRawData = _useCase.TryRefresh();
if (nextRawData == null)
{
CloseUI();
return;
}
OpenUI(nextRawData);
}
private void OnGiveUpClicked(object sender, GameEventArgs e)
{
if (!IsEventFromCurrentForm(sender) || !(e is RewardSelectGiveUpEventArgs))
{
return;
}
if (_useCase == null)
{
return;
}
if (_useCase.TryGiveUp())
{
CloseUI();
}
}
private bool IsEventFromCurrentForm(object sender)
{
if (Form == null)
{
return false;
}
if (ReferenceEquals(sender, Form))
{
return true;
}
if (sender is Component component)
{
RewardSelectForm ownerForm = component.GetComponentInParent<RewardSelectForm>();
return ownerForm == Form;
}
return false;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8d4d6617e96d6984dac4f279d4f194e5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,11 @@
namespace GeometryTD.UI
{
public class RewardSelectFormRawData
{
public string TipText;
public RewardSelectItemRawData[] RewardItems;
public int RefreshCost;
public bool CanRefresh;
public bool CanGiveUp;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 642bc21ab1e2948468912ffa6e051a6a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,20 @@
using GeometryTD.Definition;
using UnityEngine;
namespace GeometryTD.UI
{
public class RewardSelectItemRawData
{
public long RewardId;
public TowerCompSlotType SlotType;
public string Title;
public string TypeText;
public string Description;
public RarityType Rarity;
public TagType[] Tags;
public Sprite Icon;
public bool IsSelectable = true;
public TowerCompItemData SourceItem;
public object UserData;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d00c968c551de7b4a8d8841cf5e98d66
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,338 @@
using System;
using System.Collections.Generic;
using GeometryTD.Definition;
using UnityEngine;
using Random = UnityEngine.Random;
namespace GeometryTD.UI
{
public class RewardSelectFormUseCase : IUIUseCase
{
private readonly List<RewardSelectItemRawData> _rewardPool = new List<RewardSelectItemRawData>();
private RewardSelectFormRawData _currentModel;
private Action<RewardSelectItemRawData> _onRewardSelected;
private Action _onGiveUp;
private int _displayCount = 3;
private int _refreshCost;
private bool _allowRefreshOnce = true;
private bool _allowGiveUp = true;
private bool _hasRefreshed;
private string _tipText = "Select one reward";
public RewardSelectFormUseCase()
{
ConfigureRewardPool(BuildDefaultRewardPool());
}
public void ConfigureRewardPool(
IReadOnlyList<RewardSelectItemRawData> rewardPool,
int displayCount = 3,
int refreshCost = 0,
bool allowRefreshOnce = true,
bool allowGiveUp = true,
string tipText = null)
{
_rewardPool.Clear();
if (rewardPool != null)
{
for (int i = 0; i < rewardPool.Count; i++)
{
RewardSelectItemRawData item = rewardPool[i];
if (item == null)
{
continue;
}
_rewardPool.Add(CloneRawItem(item));
}
}
_displayCount = Mathf.Max(1, displayCount);
_refreshCost = Mathf.Max(0, refreshCost);
_allowRefreshOnce = allowRefreshOnce;
_allowGiveUp = allowGiveUp;
_tipText = string.IsNullOrWhiteSpace(tipText) ? "Select one reward" : tipText;
_hasRefreshed = false;
_currentModel = null;
}
public void SetCallbacks(Action<RewardSelectItemRawData> onRewardSelected, Action onGiveUp = null)
{
_onRewardSelected = onRewardSelected;
_onGiveUp = onGiveUp;
}
public RewardSelectFormRawData CreateInitialModel()
{
_hasRefreshed = false;
_currentModel = BuildModel();
return _currentModel;
}
public RewardSelectFormRawData TryRefresh()
{
if (_currentModel == null)
{
return null;
}
if (!CanRefreshInternal())
{
return _currentModel;
}
if (!TryConsumeRefreshCost())
{
_currentModel.CanRefresh = false;
return _currentModel;
}
_hasRefreshed = true;
_currentModel = BuildModel();
return _currentModel;
}
public RewardSelectFormRawData SelectReward(int selectedIndex)
{
if (_currentModel?.RewardItems == null || _currentModel.RewardItems.Length <= 0)
{
return null;
}
if (selectedIndex < 0 || selectedIndex >= _currentModel.RewardItems.Length)
{
return _currentModel;
}
RewardSelectItemRawData selectedReward = _currentModel.RewardItems[selectedIndex];
_onRewardSelected?.Invoke(selectedReward);
_currentModel = null;
return null;
}
public bool TryGiveUp()
{
if (!_allowGiveUp)
{
return false;
}
_onGiveUp?.Invoke();
_currentModel = null;
return true;
}
private RewardSelectFormRawData BuildModel()
{
RewardSelectItemRawData[] selectedRewards = SelectRewards();
return new RewardSelectFormRawData
{
TipText = _tipText,
RewardItems = selectedRewards,
RefreshCost = _refreshCost,
CanRefresh = selectedRewards.Length > 0 && CanRefreshInternal(),
CanGiveUp = _allowGiveUp
};
}
private RewardSelectItemRawData[] SelectRewards()
{
if (_rewardPool.Count <= 0)
{
return Array.Empty<RewardSelectItemRawData>();
}
int finalCount = Mathf.Clamp(_displayCount, 1, _rewardPool.Count);
int[] indexes = new int[_rewardPool.Count];
for (int i = 0; i < indexes.Length; i++)
{
indexes[i] = i;
}
for (int i = 0; i < finalCount; i++)
{
int randomIndex = Random.Range(i, indexes.Length);
(indexes[i], indexes[randomIndex]) = (indexes[randomIndex], indexes[i]);
}
RewardSelectItemRawData[] results = new RewardSelectItemRawData[finalCount];
for (int i = 0; i < finalCount; i++)
{
RewardSelectItemRawData source = _rewardPool[indexes[i]];
results[i] = CloneRawItem(source);
}
return results;
}
private bool CanRefreshInternal()
{
if (!_allowRefreshOnce || _hasRefreshed)
{
return false;
}
return CanPayRefreshCost();
}
private bool CanPayRefreshCost()
{
if (_refreshCost <= 0)
{
return true;
}
if (GameEntry.PlayerInventory == null)
{
return true;
}
return GameEntry.PlayerInventory.Gold >= _refreshCost;
}
private bool TryConsumeRefreshCost()
{
if (_refreshCost <= 0)
{
return true;
}
if (GameEntry.PlayerInventory == null)
{
return true;
}
return GameEntry.PlayerInventory.TryConsumeGold(_refreshCost);
}
private static List<RewardSelectItemRawData> BuildDefaultRewardPool()
{
BackpackInventoryData inventory = RepoFormUseCase.SampleInventory();
List<RewardSelectItemRawData> rewards = new List<RewardSelectItemRawData>();
if (inventory?.MuzzleComponents != null)
{
for (int i = 0; i < inventory.MuzzleComponents.Count; i++)
{
MuzzleCompItemData item = inventory.MuzzleComponents[i];
if (item == null)
{
continue;
}
rewards.Add(BuildRawItem(item));
}
}
if (inventory?.BearingComponents != null)
{
for (int i = 0; i < inventory.BearingComponents.Count; i++)
{
BearingCompItemData item = inventory.BearingComponents[i];
if (item == null)
{
continue;
}
rewards.Add(BuildRawItem(item));
}
}
if (inventory?.BaseComponents != null)
{
for (int i = 0; i < inventory.BaseComponents.Count; i++)
{
BaseCompItemData item = inventory.BaseComponents[i];
if (item == null)
{
continue;
}
rewards.Add(BuildRawItem(item));
}
}
return rewards;
}
private static RewardSelectItemRawData BuildRawItem(TowerCompItemData item)
{
return new RewardSelectItemRawData
{
RewardId = item.InstanceId,
SlotType = item.SlotType,
Title = item.Name,
TypeText = BuildTypeText(item.SlotType),
Description = BuildDescription(item),
Rarity = item.Rarity,
Tags = item.Tags != null ? (TagType[])item.Tags.Clone() : Array.Empty<TagType>(),
Icon = null,
IsSelectable = true,
SourceItem = item
};
}
private static RewardSelectItemRawData CloneRawItem(RewardSelectItemRawData source)
{
if (source == null)
{
return null;
}
return new RewardSelectItemRawData
{
RewardId = source.RewardId,
SlotType = source.SlotType,
Title = source.Title,
TypeText = source.TypeText,
Description = source.Description,
Rarity = source.Rarity,
Tags = source.Tags != null ? (TagType[])source.Tags.Clone() : Array.Empty<TagType>(),
Icon = source.Icon,
IsSelectable = source.IsSelectable,
SourceItem = source.SourceItem,
UserData = source.UserData
};
}
private static string BuildTypeText(TowerCompSlotType slotType)
{
return slotType switch
{
TowerCompSlotType.Muzzle => "Muzzle Component",
TowerCompSlotType.Bearing => "Bearing Component",
TowerCompSlotType.Base => "Base Component",
TowerCompSlotType.Accessory => "Accessory",
_ => "Component"
};
}
private static string BuildDescription(TowerCompItemData item)
{
if (item is MuzzleCompItemData muzzle)
{
int damage = muzzle.AttackDamage != null && muzzle.AttackDamage.Length > 0 ? muzzle.AttackDamage[0] : 0;
return $"Damage: {damage}, Spread: {muzzle.DamageRandomRate:P0}";
}
if (item is BearingCompItemData bearing)
{
float range = bearing.AttackRange != null && bearing.AttackRange.Length > 0 ? bearing.AttackRange[0] : 0f;
float rotateSpeed = bearing.RotateSpeed != null && bearing.RotateSpeed.Length > 0 ? bearing.RotateSpeed[0] : 0f;
return $"Range: {range:0.##}, Rotate Speed: {rotateSpeed:0.##}";
}
if (item is BaseCompItemData baseComp)
{
float attackSpeed = baseComp.AttackSpeed != null && baseComp.AttackSpeed.Length > 0 ? baseComp.AttackSpeed[0] : 0f;
return $"Attack Speed: {attackSpeed:0.##}, Property: {baseComp.AttackPropertyType}";
}
return string.Empty;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ee056442ccca28c4da90ef00330d5a55
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,53 @@
using GeometryTD.Definition;
using UnityEngine;
using UnityEngine.UI;
using UnityGameFramework.Runtime;
namespace GeometryTD.UI
{
public class IconArea : MonoBehaviour
{
[SerializeField] private Image _board;
[SerializeField] private Image _icon;
private IconAreaContext _context;
public void OnInit(IconAreaContext context)
{
if (context == null)
{
Log.Error("Icon area need IconAreaContext.");
return;
}
_context = context;
SetIcon(_context.Icon);
SetRarity(_context.Rarity);
}
public void SetIcon(Sprite sprite)
{
_icon.sprite = sprite;
}
public void SetRarity(RarityType rarity)
{
_board.color = rarity switch
{
RarityType.White => Color.white,
RarityType.Green => Color.green,
RarityType.Blue => Color.blue,
RarityType.Purple => Color.magenta,
RarityType.Red => Color.red,
_ => Color.clear,
};
}
public void OnReset()
{
SetIcon(null);
SetRarity(RarityType.None);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7ed74147813b96e4e95b5418f21999b7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,171 @@
using System.Collections.Generic;
using GeometryTD.CustomEvent;
using TMPro;
using UnityEngine;
namespace GeometryTD.UI
{
public class RewardItem : MonoBehaviour
{
[SerializeField] private IconArea _iconArea;
[SerializeField] private TMP_Text _titleText;
[SerializeField] private TMP_Text _typeText;
[SerializeField] private TMP_Text _descriptionText;
[SerializeField] private Transform _tagItemParent;
[SerializeField] private TagItem _tagItemTemplate;
private readonly List<TagItem> _runtimeTagItems = new List<TagItem>();
private RewardItemContext _context;
public void OnInit(RewardItemContext context)
{
if (context == null)
{
OnReset();
gameObject.SetActive(false);
return;
}
_context = context;
gameObject.SetActive(true);
if (_iconArea != null)
{
if (context.IconArea != null)
{
_iconArea.OnInit(context.IconArea);
}
else
{
_iconArea.OnReset();
}
}
if (_titleText != null)
{
_titleText.text = context.Title ?? string.Empty;
}
if (_typeText != null)
{
_typeText.text = context.TypeText ?? string.Empty;
}
if (_descriptionText != null)
{
_descriptionText.text = context.Description ?? string.Empty;
}
RefreshTags(context.Tags);
}
public void OnReset()
{
_context = null;
if (_iconArea != null)
{
_iconArea.OnReset();
}
if (_titleText != null)
{
_titleText.text = string.Empty;
}
if (_typeText != null)
{
_typeText.text = string.Empty;
}
if (_descriptionText != null)
{
_descriptionText.text = string.Empty;
}
ClearTags();
}
public void OnClick()
{
if (_context == null || !_context.IsSelectable)
{
return;
}
GameEntry.Event.Fire(this, RewardSelectItemSelectedEventArgs.Create(_context.Index));
}
private void RefreshTags(TagItemContext[] tagContexts)
{
ClearTags();
if (_tagItemParent == null || tagContexts == null || tagContexts.Length <= 0)
{
return;
}
TagItem template = ResolveTagTemplate();
if (template == null)
{
return;
}
for (int i = 0; i < tagContexts.Length; i++)
{
TagItemContext tagContext = tagContexts[i];
if (tagContext == null || string.IsNullOrWhiteSpace(tagContext.TagName))
{
continue;
}
TagItem tagItem = Instantiate(template, _tagItemParent);
tagItem.gameObject.SetActive(true);
tagItem.OnInit(tagContext);
_runtimeTagItems.Add(tagItem);
}
}
private TagItem ResolveTagTemplate()
{
if (_tagItemTemplate != null)
{
return _tagItemTemplate;
}
if (_tagItemParent == null)
{
return null;
}
_tagItemTemplate = _tagItemParent.GetComponentInChildren<TagItem>(true);
if (_tagItemTemplate != null)
{
_tagItemTemplate.gameObject.SetActive(false);
}
return _tagItemTemplate;
}
private void ClearTags()
{
for (int i = _runtimeTagItems.Count - 1; i >= 0; i--)
{
TagItem tagItem = _runtimeTagItems[i];
if (tagItem != null)
{
Destroy(tagItem.gameObject);
}
}
_runtimeTagItems.Clear();
}
}
}
@@ -0,0 +1,167 @@
using GeometryTD.CustomEvent;
using TMPro;
using UnityEngine;
using UnityGameFramework.Runtime;
namespace GeometryTD.UI
{
public class RewardSelectForm : UGuiForm
{
[SerializeField] private Transform _selectItemParent;
[SerializeField] private RewardItem[] _rewardItems;
[SerializeField] private TMP_Text _tipText;
[SerializeField] private TMP_Text _refreshButtonText;
[SerializeField] private CommonButton _refreshButton;
[SerializeField] private CommonButton _giveUpButton;
private RewardSelectFormContext _context;
public void OnInit(RewardSelectFormContext context)
{
if (context == null)
{
Log.Error("RewardSelectForm need Context.");
return;
}
RefreshUI(context);
}
public void RefreshUI(RewardSelectFormContext context)
{
_context = context;
EnsureRewardItems();
if (_tipText != null)
{
_tipText.text = context?.TipText ?? string.Empty;
}
if (_refreshButtonText != null)
{
_refreshButtonText.text = context?.RefreshButtonText ?? string.Empty;
}
if (_refreshButton != null)
{
_refreshButton.Interactive = context?.CanRefresh ?? false;
}
if (_giveUpButton != null)
{
_giveUpButton.Interactive = context?.CanGiveUp ?? false;
}
if (_rewardItems == null || _rewardItems.Length <= 0)
{
return;
}
for (int i = 0; i < _rewardItems.Length; i++)
{
RewardItem rewardItem = _rewardItems[i];
if (rewardItem == null)
{
continue;
}
RewardItemContext itemContext = null;
if (context?.RewardItems != null && i < context.RewardItems.Length)
{
itemContext = context.RewardItems[i];
}
rewardItem.OnInit(itemContext);
}
}
public void OnRefreshButtonClick()
{
if (_context != null && !_context.CanRefresh)
{
return;
}
GameEntry.Event.Fire(this, RewardSelectRefreshEventArgs.Create());
}
public void OnGiveUpButtonClick()
{
if (_context != null && !_context.CanGiveUp)
{
return;
}
GameEntry.Event.Fire(this, RewardSelectGiveUpEventArgs.Create());
}
protected override void OnOpen(object userData)
{
base.OnOpen(userData);
if (userData is RewardSelectFormContext context)
{
RefreshUI(context);
return;
}
Log.Warning("RewardSelectForm requires RewardSelectFormContext as userData.");
}
protected override void OnClose(bool isShutdown, object userData)
{
_context = null;
if (_tipText != null)
{
_tipText.text = string.Empty;
}
if (_refreshButtonText != null)
{
_refreshButtonText.text = string.Empty;
}
if (_rewardItems != null)
{
for (int i = 0; i < _rewardItems.Length; i++)
{
RewardItem rewardItem = _rewardItems[i];
if (rewardItem == null)
{
continue;
}
rewardItem.OnReset();
rewardItem.gameObject.SetActive(false);
}
}
base.OnClose(isShutdown, userData);
}
private void EnsureRewardItems()
{
if (_rewardItems != null && _rewardItems.Length > 0)
{
return;
}
if (_selectItemParent != null)
{
_rewardItems = _selectItemParent.GetComponentsInChildren<RewardItem>(true);
}
if (_rewardItems == null || _rewardItems.Length <= 0)
{
_rewardItems = GetComponentsInChildren<RewardItem>(true);
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 60b499ea8a70a7f489bbd5bf0cec5768
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,27 @@
using TMPro;
using UnityEngine;
namespace GeometryTD.UI
{
public class TagItem : MonoBehaviour
{
[SerializeField] private RectTransform _bgRect;
[SerializeField] private TMP_Text _tagName;
[SerializeField] private float _bgExtraWidth = 12f;
private TagItemContext _context;
public void OnInit(TagItemContext context)
{
_context = context;
_tagName.text = _context?.TagName ?? string.Empty;
_tagName.ForceMeshUpdate();
var targetWidth = _tagName.preferredWidth + _bgExtraWidth;
_bgRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, targetWidth);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0beb75e5722a1db47af08437f98a0e63
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,32 +0,0 @@
// using TMPro;
// using UnityEngine;
// using UnityEngine.UI;
//
// namespace UI
// {
// public class ShopGoodsItem : MonoBehaviour
// {
// [SerializeField] private IconArea _iconArea;
//
// [SerializeField] private TMP_Text _titleText;
//
// [SerializeField] private TMP_Text _typeText;
//
// [SerializeField] private TMP_Text _descriptionText;
//
// [SerializeField] private TMP_Text _costText;
//
// #region Init
//
// public void Init(GoodsItemContext data)
// {
// _iconArea.OnInit(data.Icon, data.Rarity);
// _titleText.text = data.Title;
// _typeText.text = data.Type;
// _descriptionText.text = data.Description;
// _costText.text = $"{data.Price} <sprite name=\"coin\" index=0>";
// }
//
// #endregion
// }
// }