优化 UI 效果
This commit is contained in:
@@ -9,33 +9,14 @@ namespace SepCore.UI
|
||||
{
|
||||
[SerializeField] private Image _background = null;
|
||||
|
||||
private Color _originalBackgroundColor;
|
||||
|
||||
[SerializeField] private UnityEvent _onPointerEnterAction = new();
|
||||
|
||||
[SerializeField] private UnityEvent _onPointerExitAction = new();
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
_originalBackgroundColor = _background.color;
|
||||
}
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
_background.color = _originalBackgroundColor;
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
base.OnDisable();
|
||||
_background.color = new Color(0.3f, 0.3f, 0.3f, 0.3f);
|
||||
}
|
||||
|
||||
public override void OnPointerEnter(PointerEventData eventData)
|
||||
{
|
||||
if (eventData.button != PointerEventData.InputButton.Left)
|
||||
base.OnPointerEnter(eventData);
|
||||
if (eventData.button != PointerEventData.InputButton.Left || !IsActive() || !IsInteractable())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -45,6 +26,7 @@ namespace SepCore.UI
|
||||
|
||||
public override void OnPointerExit(PointerEventData eventData)
|
||||
{
|
||||
base.OnPointerExit(eventData);
|
||||
if (eventData.button != PointerEventData.InputButton.Left)
|
||||
{
|
||||
return;
|
||||
@@ -55,16 +37,33 @@ namespace SepCore.UI
|
||||
|
||||
public override void OnSelect(BaseEventData eventData)
|
||||
{
|
||||
_background.color = new Color(1f, 0.9f, 0.3f);
|
||||
base.OnSelect(eventData);
|
||||
if (!IsActive() || !IsInteractable())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnterHoverState();
|
||||
}
|
||||
|
||||
public override void OnDeselect(BaseEventData eventData)
|
||||
{
|
||||
_background.color = _originalBackgroundColor;
|
||||
base.OnDeselect(eventData);
|
||||
ExitHoverState();
|
||||
}
|
||||
|
||||
protected override void DoStateTransition(SelectionState state, bool instant)
|
||||
{
|
||||
base.DoStateTransition(state, instant);
|
||||
if (transition == Transition.SpriteSwap)
|
||||
{
|
||||
_background.canvasRenderer.SetColor(
|
||||
state == SelectionState.Highlighted || state == SelectionState.Selected
|
||||
? new Color(1f, 0.96f, 0.8f, 1f)
|
||||
: Color.white);
|
||||
}
|
||||
}
|
||||
|
||||
private void EnterHoverState()
|
||||
{
|
||||
if (EventSystem.current.currentSelectedGameObject != gameObject)
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace SepCore.UI
|
||||
public string IconAssetName;
|
||||
public string Title;
|
||||
public ItemType ItemType;
|
||||
public string TypeName;
|
||||
public Rarity Rarity;
|
||||
public string Description;
|
||||
public int Price;
|
||||
@@ -21,6 +22,7 @@ namespace SepCore.UI
|
||||
Index = -1;
|
||||
IconAssetName = string.Empty;
|
||||
Title = string.Empty;
|
||||
TypeName = string.Empty;
|
||||
ItemType = ItemType.None;
|
||||
Rarity = Rarity.White;
|
||||
Description = string.Empty;
|
||||
@@ -43,6 +45,7 @@ namespace SepCore.UI
|
||||
var data = rawData.WeaponData;
|
||||
IconAssetName = data.Sprite;
|
||||
Title = data.Title;
|
||||
TypeName = ItemDescUtility.FormatWeaponTags(data);
|
||||
Description = ItemDescUtility.CreateWeaponDescription(data);
|
||||
}
|
||||
else if (ItemType == ItemType.Prop)
|
||||
@@ -50,6 +53,7 @@ namespace SepCore.UI
|
||||
var data = rawData.PropData;
|
||||
IconAssetName = data.IconAssetName;
|
||||
Title = data.Title;
|
||||
TypeName = "道具";
|
||||
Description = ItemDescUtility.CreatePropDescription(data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace SepCore.UI
|
||||
View.contentRectTransform.anchoredPosition3D = _targetPos;
|
||||
|
||||
View.titleText.text = _context.Title;
|
||||
View.typeText.text = BuildTypeText(_context.ItemType);
|
||||
View.typeText.text = _context.TypeName;
|
||||
View.infoText.text = _context.Description;
|
||||
View.textFormatText.Set(_context.Price);
|
||||
|
||||
@@ -173,16 +173,5 @@ namespace SepCore.UI
|
||||
float z = View.contentRectTransform.anchoredPosition3D.z;
|
||||
return new Vector3(localPoint.x, localPoint.y, z);
|
||||
}
|
||||
|
||||
private string BuildTypeText(ItemType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
ItemType.None => "error",
|
||||
ItemType.Weapon => "武器",
|
||||
ItemType.Prop => "道具",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
"GUID:47a82ffa13c291447ab895cd0bc251cd",
|
||||
"GUID:436e23dbdc31e7d4fb5c3f804548b2df",
|
||||
"GUID:d54b9488b03814a44ab937f0aeb738b1",
|
||||
"GUID:3bb549212964b4192b427888ac9382e7"
|
||||
"GUID:3bb549212964b4192b427888ac9382e7",
|
||||
"GUID:75469ad4d38634e559750d17036d5f7c"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
@@ -19,4 +20,4 @@
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,32 +36,23 @@ namespace SepCore.UI
|
||||
|
||||
if (ItemType == ItemType.Weapon)
|
||||
{
|
||||
DamageType damageType;
|
||||
if (rawData.DataRow is WeaponConfig weaponConfig)
|
||||
{
|
||||
Name = weaponConfig.WeaponName;
|
||||
Description = ItemDescUtility.CreateWeaponDescription(weaponConfig);
|
||||
damageType = weaponConfig.DamageType;
|
||||
TypeName = ItemDescUtility.FormatWeaponTags(weaponConfig);
|
||||
}
|
||||
else if (rawData.DataRow is WeaponData weaponData)
|
||||
{
|
||||
Name = weaponData.Title;
|
||||
Description = ItemDescUtility.CreateWeaponDescription(weaponData);
|
||||
damageType = weaponData.DamageType;
|
||||
TypeName = ItemDescUtility.FormatWeaponTags(weaponData);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error("Weapon data row is invalid.");
|
||||
return;
|
||||
}
|
||||
|
||||
TypeName = damageType switch
|
||||
{
|
||||
DamageType.Melee => "近战武器",
|
||||
DamageType.Ranged => "远程武器",
|
||||
DamageType.Element => "元素武器",
|
||||
_ => "武器"
|
||||
};
|
||||
}
|
||||
else if (ItemType == ItemType.Prop)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using SepCore.Event;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
@@ -55,11 +56,19 @@ namespace SepCore.UI
|
||||
View.statForm.OnInit(context.StatContext);
|
||||
context.NeedRefreshStat = false;
|
||||
}
|
||||
|
||||
bool weaponCapacityFull = context.WeaponListContext.CurrentCount >= context.WeaponListContext.MaxCount;
|
||||
foreach (ShopGoodsItem item in _goodsItems)
|
||||
{
|
||||
item.RefreshAvailability(context.PlayerCoin, weaponCapacityFull);
|
||||
}
|
||||
View.refreshButton.interactable = context.PlayerCoin >= context.RefreshPrice;
|
||||
}
|
||||
|
||||
protected override void OnOpen(object userData)
|
||||
{
|
||||
base.OnOpen(userData);
|
||||
SetAttributesVisible(false);
|
||||
|
||||
if (userData is not ShopContext context)
|
||||
{
|
||||
@@ -72,6 +81,7 @@ namespace SepCore.UI
|
||||
|
||||
protected override void OnClose(bool isShutdown, object userData)
|
||||
{
|
||||
SetAttributesVisible(false);
|
||||
_context = null;
|
||||
|
||||
for (int i = 0; i < _goodsItems.Count; i++)
|
||||
@@ -96,6 +106,9 @@ namespace SepCore.UI
|
||||
|
||||
View.continueButton.onClick.AddListener(OnContinueButtonClick);
|
||||
View.refreshButton.onClick.AddListener(OnRefreshButtonClick);
|
||||
View.attributeToggleButton.onClick.AddListener(ShowAttributes);
|
||||
View.attributeCloseButton.onClick.AddListener(HideAttributes);
|
||||
View.attributeDismissButton.onClick.AddListener(HideAttributes);
|
||||
}
|
||||
|
||||
private void RefreshGoodsItems(List<GoodsItemContext> goodsItems)
|
||||
@@ -112,8 +125,16 @@ namespace SepCore.UI
|
||||
}
|
||||
else
|
||||
{
|
||||
item.OnReset();
|
||||
item.gameObject.SetActive(false);
|
||||
if (i < goodsItems.Count)
|
||||
{
|
||||
item.MarkPurchased();
|
||||
item.gameObject.SetActive(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.OnReset();
|
||||
item.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,5 +157,40 @@ namespace SepCore.UI
|
||||
{
|
||||
GameEntry.Event.Fire(this, ShopRefreshEventArgs.Create(_context.RefreshPrice));
|
||||
}
|
||||
|
||||
private void ShowAttributes()
|
||||
{
|
||||
SetAttributesVisible(true);
|
||||
}
|
||||
|
||||
private void HideAttributes()
|
||||
{
|
||||
SetAttributesVisible(false);
|
||||
}
|
||||
|
||||
private void SetAttributesVisible(bool visible)
|
||||
{
|
||||
View.attributeDrawer.gameObject.SetActive(visible);
|
||||
View.attributeToggleButton.gameObject.SetActive(!visible);
|
||||
}
|
||||
|
||||
protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
base.OnUpdate(elapseSeconds, realElapseSeconds);
|
||||
if (!View.attributeDrawer.gameObject.activeSelf)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
var keyboard = UnityEngine.InputSystem.Keyboard.current;
|
||||
if (keyboard != null && keyboard.escapeKey.wasPressedThisFrame)
|
||||
#else
|
||||
if (Input.GetKeyDown(KeyCode.Escape))
|
||||
#endif
|
||||
{
|
||||
HideAttributes();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,11 @@ namespace SepCore.UI
|
||||
[SerializeField] private TMP_Text _descriptionText;
|
||||
|
||||
[SerializeField] private TMP_Text _costText;
|
||||
[SerializeField] private CommonButton _purchaseButton = null;
|
||||
[SerializeField] private TMP_Text _purchaseLabel = null;
|
||||
[SerializeField] private CanvasGroup _canvasGroup = null;
|
||||
|
||||
private GoodsItemContext _data;
|
||||
|
||||
private int _index = -1;
|
||||
|
||||
@@ -26,6 +31,9 @@ namespace SepCore.UI
|
||||
EnsureListeners();
|
||||
|
||||
_index = index;
|
||||
_data = data;
|
||||
_canvasGroup.alpha = 1f;
|
||||
_purchaseLabel.text = "购买";
|
||||
|
||||
_iconArea.OnInit(data.Icon, data.Rarity);
|
||||
_titleText.text = data.Name;
|
||||
@@ -37,6 +45,28 @@ namespace SepCore.UI
|
||||
public void OnReset()
|
||||
{
|
||||
_index = -1;
|
||||
_data = null;
|
||||
}
|
||||
|
||||
public void MarkPurchased()
|
||||
{
|
||||
OnReset();
|
||||
_canvasGroup.alpha = 0.5f;
|
||||
_purchaseButton.interactable = false;
|
||||
_purchaseLabel.text = "已购买";
|
||||
}
|
||||
|
||||
public void RefreshAvailability(int playerCoin, bool weaponCapacityFull)
|
||||
{
|
||||
if (_index < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool weaponFull = _data.ItemType == ItemType.Weapon && weaponCapacityFull;
|
||||
bool affordable = playerCoin >= _data.Price;
|
||||
_purchaseButton.interactable = affordable && !weaponFull;
|
||||
_purchaseLabel.text = weaponFull ? "武器已满" : affordable ? "购买" : "金币不足";
|
||||
}
|
||||
|
||||
private void EnsureListeners()
|
||||
@@ -48,8 +78,7 @@ namespace SepCore.UI
|
||||
|
||||
_listenersBound = true;
|
||||
|
||||
CommonButton button = GetComponentInChildren<CommonButton>(true);
|
||||
button.onClick.AddListener(OnPurchaseClick);
|
||||
_purchaseButton.onClick.AddListener(OnPurchaseClick);
|
||||
}
|
||||
|
||||
private void OnPurchaseClick()
|
||||
|
||||
@@ -8,12 +8,16 @@ namespace SepCore.UI
|
||||
{
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI titleFormatText;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI playerCoinFormatText;
|
||||
[SerializeField] public global::SepCore.UI.CommonButton refreshButton;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI refreshButtonFormatText;
|
||||
[SerializeField] public global::UnityEngine.RectTransform GoodsItemRoot;
|
||||
[SerializeField] public global::SepCore.UI.ShopGoodsItem goodsItemTemplate;
|
||||
[SerializeField] public global::SepCore.UI.CommonButton refreshButton;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI refreshButtonFormatText;
|
||||
[SerializeField] public global::SepCore.UI.CommonButton continueButton;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI continueButtonFormatText;
|
||||
[SerializeField] public global::SepCore.UI.CommonButton attributeToggleButton;
|
||||
[SerializeField] public global::UnityEngine.RectTransform attributeDrawer;
|
||||
[SerializeField] public global::UnityEngine.UI.Button attributeDismissButton;
|
||||
[SerializeField] public global::SepCore.UI.CommonButton attributeCloseButton;
|
||||
[SerializeField] public global::SepCore.UI.DisplayListForm weaponList;
|
||||
[SerializeField] public global::SepCore.UI.DisplayListForm propList;
|
||||
[SerializeField] public global::SepCore.UI.StatForm statForm;
|
||||
|
||||
@@ -28,7 +28,69 @@ namespace SepCore.CustomUtility
|
||||
"收获", // Harvesting = 15
|
||||
"幸运" // Luck = 16
|
||||
};
|
||||
|
||||
|
||||
private static readonly Dictionary<WeaponTag, string> _weaponTagNames = new()
|
||||
{
|
||||
{ WeaponTag.Blade, "刀剑" },
|
||||
{ WeaponTag.Precise, "精准" },
|
||||
{ WeaponTag.Gun, "枪械" },
|
||||
{ WeaponTag.Engineering, "工程" },
|
||||
{ WeaponTag.Blunt, "钝器" },
|
||||
{ WeaponTag.Primitive, "原始" },
|
||||
{ WeaponTag.Elemental, "元素" },
|
||||
{ WeaponTag.Unarmed, "徒手" },
|
||||
{ WeaponTag.Medical, "医疗" },
|
||||
{ WeaponTag.Heavy, "重型" },
|
||||
};
|
||||
|
||||
public static string GetWeaponTagName(WeaponTag tag)
|
||||
{
|
||||
return _weaponTagNames.TryGetValue(tag, out string name) ? name : tag.ToString();
|
||||
}
|
||||
|
||||
public static string FormatWeaponTags(IReadOnlyList<WeaponTag> tags)
|
||||
{
|
||||
if (tags == null || tags.Count == 0)
|
||||
{
|
||||
return "武器";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < tags.Count; i++)
|
||||
{
|
||||
WeaponTag tag = tags[i];
|
||||
if (tag == WeaponTag.None)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sb.Length > 0)
|
||||
{
|
||||
sb.Append(" - ");
|
||||
}
|
||||
|
||||
sb.Append(GetWeaponTagName(tag));
|
||||
}
|
||||
|
||||
return sb.Length > 0 ? sb.ToString() : "武器";
|
||||
}
|
||||
|
||||
public static string FormatWeaponTags(WeaponConfig config)
|
||||
{
|
||||
return FormatWeaponTags(config.Tags);
|
||||
}
|
||||
|
||||
public static string FormatWeaponTags(WeaponData data)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
Log.Error("Weapon data is invalid.");
|
||||
return "武器";
|
||||
}
|
||||
|
||||
return FormatWeaponTags(data.Tags);
|
||||
}
|
||||
|
||||
public static string Describe(StatModifierConfig statModifierConfig)
|
||||
{
|
||||
if (statModifierConfig == null)
|
||||
|
||||
Reference in New Issue
Block a user