Files
SoulliesOfficial 649b7a5ddc 更新
2026-05-23 08:27:50 -04:00

340 lines
11 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using Cielonos.MainGame.Inventory;
using Cielonos.MainGame.Interactions;
using Cielonos.MainGame.Items;
using Sirenix.OdinInspector;
using SLSUtilities.UI;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace Cielonos.MainGame.UI
{
/// <summary>
/// 物流中心商店UI 页面。
/// 左侧为可购买商品列表Selector右侧为物品详情面板ItemDetailPanel
/// 玩家点击列表条目选中商品,点击 Buy 确认购买(消耗 RareMaterial 并获得装备)。
/// </summary>
public class LogisticsCenterUIPage : UIPageBase
{
[Title("Selectors")]
public GameObject selectorPrefab;
public RectTransform selectorContainer;
public List<LogisticsCenterSelector> selectors = new List<LogisticsCenterSelector>();
[Title("Detail Panel")]
public ItemDetailPanel itemDetailPanel;
[Title("Rare Material Display")]
public TMP_Text currentRareMaterialText;
public TMP_Text predictedRareMaterialText;
[Title("Buttons")]
public List<Button> categoryButtons;
private static readonly ItemFilter[] CategoryFilters =
{
ItemFilter.None,
ItemFilter.ByType(ItemType.MainWeapon),
ItemFilter.ByType(ItemType.Support),
ItemFilter.ByType(ItemType.Passive),
ItemFilter.ByType(ItemType.Consumable)
};
public Button buyButton;
public Button closeButton;
// - 运行时数据 -
private LogisticsCenterSelector currentSelected;
private Action<int> onPurchaseCallback;
private List<ShopOffer> currentOffers;
private ItemFilter activeFilter;
/// <summary>当前选中的 Selector 索引,-1 表示未选中。</summary>
public int SelectedIndex => currentSelected != null ? selectors.IndexOf(currentSelected) : -1;
protected override void Start()
{
base.Start();
if (buyButton != null)
{
buyButton.onClick.AddListener(OnBuyClicked);
}
if (closeButton != null)
{
closeButton.onClick.AddListener(OnCloseClicked);
}
// 绑定分类按钮
if (categoryButtons != null)
{
for (int i = 0; i < categoryButtons.Count; i++)
{
if (categoryButtons[i] == null) continue;
int index = i;
categoryButtons[i].onClick.AddListener(() => OnCategoryClicked(index));
}
}
}
/// <summary>
/// 用商品列表填充选择器,并注册购买回调。
/// 每次调用会清除旧选择器并重新生成。
/// </summary>
/// <param name="offers">商品列表,每个商品包含预制体和价格。</param>
/// <param name="onPurchase">玩家点击 Buy 后的回调,参数为选中的商品在原始列表中的索引。</param>
public void SetOffers(List<ShopOffer> offers, Action<int> onPurchase)
{
onPurchaseCallback = onPurchase;
currentOffers = offers;
ClearSelectors();
if (offers == null) return;
for (int i = 0; i < offers.Count; i++)
{
ShopOffer offer = offers[i];
if (offer == null || offer.prefab == null) continue;
ItemBase itemComponent = offer.prefab.GetComponent<ItemBase>();
if (itemComponent == null)
{
Debug.LogWarning($"[LogisticCenterUIPage] 预制体 '{offer.prefab.name}' 缺少 ItemBase 组件,已跳过。");
continue;
}
LogisticsCenterSelector selector = CreateSelector();
selector.Setup(itemComponent, offer.price);
}
// 重置选中状态与过滤
currentSelected = null;
activeFilter = ItemFilter.None;
RefreshBuyButton();
RefreshCurrencyDisplay();
// 详情面板默认隐藏
if (itemDetailPanel != null)
{
itemDetailPanel.ClearPanel();
}
}
/// <summary>
/// 由 LogisticCenterSelector 调用,选中指定的选择器。
/// </summary>
public void SelectItem(LogisticsCenterSelector selector)
{
if (selector == null || !selectors.Contains(selector)) return;
// 取消上一个选中
if (currentSelected != null)
{
currentSelected.SetSelected(false);
}
// 设置新选中
currentSelected = selector;
currentSelected.SetSelected(true);
// 更新详情面板
if (itemDetailPanel != null)
{
itemDetailPanel.SetItem(currentSelected.item);
}
// 刷新购买按钮状态与货币预测显示
RefreshBuyButton();
RefreshCurrencyDisplay();
}
protected override void OnPageOpened()
{
RefreshBuyButton();
RefreshCurrencyDisplay();
}
protected override void OnPageClosed()
{
currentSelected = null;
onPurchaseCallback = null;
currentOffers = null;
}
private void OnBuyClicked()
{
if (currentSelected == null) return;
int selectorIndex = SelectedIndex;
if (selectorIndex < 0) return;
// 检查 RareMaterial 是否足够
int playerCurrency = MainGameManager.Player.inventorySc.GetRareMaterialAmount();
if (playerCurrency < currentSelected.price)
{
Debug.Log("[LogisticCenterUIPage] RareMaterial 不足,无法购买。");
return;
}
// 先缓存回调
Action<int> callback = onPurchaseCallback;
// 调用购买逻辑(会扣除 RareMaterial 并修改 currentOffers 列表)
callback?.Invoke(selectorIndex);
// 移除已购买的选择器
LogisticsCenterSelector purchasedSelector = currentSelected;
currentSelected = null;
selectors.Remove(purchasedSelector);
Destroy(purchasedSelector.gameObject);
// 刷新所有选择器的价格颜色和货币显示
RefreshAllSelectorPrices();
RefreshBuyButton();
RefreshCurrencyDisplay();
// 清空详情面板
if (itemDetailPanel != null)
{
itemDetailPanel.ClearPanel();
}
}
private void OnCloseClicked()
{
Close();
}
/// <summary>
/// 分类按钮点击回调,根据索引切换当前过滤类型并刷新可见列表。
/// </summary>
private void OnCategoryClicked(int index)
{
if (index < 0 || index >= CategoryFilters.Length) return;
activeFilter = CategoryFilters[index];
ApplyFilter();
}
/// <summary>
/// 按当前 activeFilter 显示/隐藏选择器。
/// 若当前选中的商品被隐藏,则取消选中。
/// </summary>
private void ApplyFilter()
{
bool selectedHidden = false;
foreach (LogisticsCenterSelector selector in selectors)
{
if (selector == null || selector.item == null || selector.item.contentData == null)
continue;
bool visible = activeFilter.Match(selector.item);
selector.gameObject.SetActive(visible);
if (!visible && selector == currentSelected)
{
selectedHidden = true;
}
}
// 被过滤掉的选中项需要清除
if (selectedHidden)
{
currentSelected.SetSelected(false);
currentSelected = null;
if (itemDetailPanel != null)
{
itemDetailPanel.ClearPanel();
}
}
RefreshBuyButton();
RefreshCurrencyDisplay();
}
private LogisticsCenterSelector CreateSelector()
{
if (selectorPrefab == null || selectorContainer == null)
{
Debug.LogError("[LogisticCenterUIPage] selectorPrefab 或 selectorContainer 未配置。");
return null;
}
GameObject obj = Instantiate(selectorPrefab, selectorContainer);
LogisticsCenterSelector selector = obj.GetComponent<LogisticsCenterSelector>();
if (selector == null)
{
Debug.LogError("[LogisticCenterUIPage] selectorPrefab 缺少 LogisticCenterSelector 组件。");
Destroy(obj);
return null;
}
selectors.Add(selector);
return selector;
}
private void ClearSelectors()
{
foreach (LogisticsCenterSelector selector in selectors)
{
if (selector != null)
{
Destroy(selector.gameObject);
}
}
selectors.Clear();
currentSelected = null;
}
private void RefreshBuyButton()
{
if (buyButton == null) return;
if (currentSelected == null)
{
buyButton.interactable = false;
return;
}
int playerCurrency = MainGameManager.Player.inventorySc.GetRareMaterialAmount();
bool canAfford = playerCurrency >= currentSelected.price;
buyButton.interactable = canAfford;
}
private void RefreshCurrencyDisplay()
{
int rmAmount = MainGameManager.Player.inventorySc.GetRareMaterialAmount();
currentRareMaterialText.text = "Rare Materials: " + rmAmount.ToString();
if (currentSelected == null)
{
predictedRareMaterialText.text = string.Empty;
return;
}
int predicted = rmAmount - currentSelected.price;
predictedRareMaterialText.color = predicted >= 0 ? new Color(0.3f, 1f, 0.3f, 1f) : new Color(1f, 0.3f, 0.3f, 1f);
predictedRareMaterialText.text = "(" + predicted.ToString() + ")";
}
private void RefreshAllSelectorPrices()
{
foreach (LogisticsCenterSelector selector in selectors)
{
if (selector != null)
{
selector.RefreshPriceDisplay();
}
}
}
}
}