Passion & UI

This commit is contained in:
SoulliesOfficial
2026-06-12 17:11:39 -04:00
parent 7bc1e1722c
commit 6d7ebc5825
3444 changed files with 865284 additions and 463132 deletions

View File

@@ -0,0 +1,136 @@
using Cielonos.MainGame.Inventory;
using SLSUtilities.General;
using SLSUtilities.UI;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace Cielonos.MainGame.UI
{
/// <summary>
/// 背包网格中的单个物品槽位。
/// 显示物品图标、名称,消耗品额外显示堆叠数量。
/// 点击后通知 InventoryUIPage 选中该物品并更新详情面板。
/// </summary>
public class InventoryItemSelector : UIElementBase
{
private InventoryUIPage Page => PlayerCanvas.MainGamePages.inventoryPage;
// ─────────────────── 数据 ───────────────────
/// <summary>此槽位绑定的物品实例。</summary>
public ItemBase Item { get; private set; }
// ─────────────────── UI 引用 ───────────────────
[Header("UI References")]
public Button button;
public Image background;
public Image itemIcon;
public Image rarityFrame;
//public Image selectorHint;
//public TMP_Text itemName;
[Tooltip("消耗品堆叠数量显示,非消耗品时隐藏。")]
public TMP_Text stackText;
// ─────────────────── 视觉设置 ───────────────────
[Header("Visual Settings")]
public Color normalColor = new Color(0.2f, 0.2f, 0.2f, 0.8f);
public Color selectedColor = new Color(0.4f, 0.6f, 0.9f, 0.9f);
private bool isSelected;
// ================================================================
// 公开接口
// ================================================================
/// <summary>
/// 用给定的物品数据配置此槽位的显示内容。
/// </summary>
public void Setup(ItemBase item)
{
Item = item;
if (item == null || item.contentData == null)
{
Hide();
return;
}
ContentData data = item.contentData;
Sprite icon = data.itemIcon;
if (itemIcon != null)
{
itemIcon.sprite = icon;
itemIcon.enabled = icon != null;
}
// 名称(本地化)
/*if (itemName != null)
{
itemName.text = data.displayNameKey.Localize();
}*/
// 堆叠数量(仅消耗品)
RefreshStackDisplay();
// 默认取消选中
SetSelected(false);
// 绑定按钮
if (button != null)
{
button.onClick.RemoveAllListeners();
button.onClick.AddListener(OnClicked);
}
Show();
}
/// <summary>
/// 设置选中/取消选中的视觉状态。
/// </summary>
public void SetSelected(bool selected)
{
isSelected = selected;
if (background != null)
{
background.color = isSelected ? selectedColor : normalColor;
}
/*if (selectorHint != null)
{
selectorHint.enabled = isSelected;
}*/
}
/// <summary>
/// 刷新消耗品堆叠数量显示。非消耗品时隐藏堆叠文本。
/// </summary>
public void RefreshStackDisplay()
{
if (stackText == null) return;
if (Item is ConsumableBase consumable)
{
stackText.gameObject.SetActive(true);
stackText.text = consumable.stackAmount.ToString();
}
else
{
stackText.gameObject.SetActive(false);
}
}
// ─────────────────── 内部 ───────────────────
private void OnClicked()
{
Page?.SelectItem(this);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 2abecad67abab4e4692a134234d722c8

View File

@@ -0,0 +1,284 @@
using System.Collections.Generic;
using Cielonos.MainGame.Characters;
using Cielonos.MainGame.Inventory;
using Cielonos.MainGame.Items;
using Sirenix.OdinInspector;
using SLSUtilities.UI;
using UnityEngine;
using UnityEngine.UI;
namespace Cielonos.MainGame.UI
{
/// <summary>
/// 背包/装备界面 UI 页面。
/// 左侧为背包物品网格GridLayoutGroup支持按类型多选筛选和多种排序模式
/// 右侧为物品详情面板ItemDetailPanel选中物品后显示详细信息。
/// </summary>
public class InventoryUIPage : UIPageBase
{
// ─────────────────── 选择器 ───────────────────
[Title("Selectors")]
[Tooltip("背包网格中每个物品槽位的预制体,需挂载 InventoryItemSelector 组件。")]
public GameObject selectorPrefab;
[Tooltip("物品槽位的容器,应挂载 GridLayoutGroup 以实现网格布局。")]
public RectTransform selectorContainer;
[ReadOnly]
public List<InventoryItemSelector> selectors = new List<InventoryItemSelector>();
// ─────────────────── 详情面板 ───────────────────
[Title("Detail Panel")]
public ItemDetailPanel itemDetailPanel;
// ─────────────────── 筛选与排序 ───────────────────
[Title("Filter & Sort")]
[Tooltip("多选类别筛选下拉框,按 ItemType 过滤可见物品。")]
public ItemCategoryDropdown categoryDropdown;
[Tooltip("单选排序模式下拉框,决定物品排列顺序。")]
public ItemSortDropdown sortDropdown;
// ─────────────────── 按钮 ───────────────────
[Title("Buttons")]
public Button closeButton;
// ─────────────────── 运行时数据 ───────────────────
private InventoryItemSelector currentSelected;
/// <summary>当前选中的物品null 表示未选中。</summary>
public ItemBase SelectedItem => currentSelected != null ? currentSelected.Item : null;
// ================================================================
// 生命周期
// ================================================================
protected override void Start()
{
base.Start();
if (closeButton != null)
{
closeButton.onClick.AddListener(OnCloseClicked);
}
if (categoryDropdown != null)
{
categoryDropdown.OnFilterChanged += OnFilterChanged;
}
if (sortDropdown != null)
{
sortDropdown.OnSortChanged += OnSortChanged;
}
}
protected override void OnPageOpened()
{
RefreshInventory();
}
protected override void OnPageClosed()
{
currentSelected = null;
ClearSelectors();
categoryDropdown?.ResetToAll();
sortDropdown?.ResetToDefault();
}
// ================================================================
// 公开接口
// ================================================================
/// <summary>
/// 从玩家背包读取所有物品,重新生成网格选择器并应用排序与筛选。
/// </summary>
public void RefreshInventory()
{
ClearSelectors();
PlayerInventorySubcontroller.BackpackSubmodule backpack =
MainGameManager.Player.inventorySc.backpackSm;
PopulateFromList(backpack.mainWeapons);
PopulateFromList(backpack.supportEquipments);
PopulateFromList(backpack.passiveEquipments);
PopulateFromList(backpack.consumables);
currentSelected = null;
ApplySortAndFilter();
if (itemDetailPanel != null)
{
itemDetailPanel.ClearPanel();
}
}
/// <summary>
/// 由 InventoryItemSelector 调用,选中指定的物品槽位。
/// </summary>
public void SelectItem(InventoryItemSelector 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);
}
}
// ================================================================
// 筛选与排序
// ================================================================
/// <summary>
/// 对选择器列表执行排序,然后按当前筛选条件显示/隐藏。
/// 当任一 Dropdown 变化或背包刷新时调用。
/// </summary>
private void ApplySortAndFilter()
{
// ── 排序 ──
ItemSortMode sortMode = sortDropdown != null ? sortDropdown.CurrentMode : ItemSortMode.Default;
List<ItemBase> items = selectors.ConvertAll(s => s.Item);
ItemSorter.Sort(items, sortMode);
// 按排序结果重排选择器列表
Dictionary<ItemBase, InventoryItemSelector> itemToSelector =
new Dictionary<ItemBase, InventoryItemSelector>(selectors.Count);
foreach (InventoryItemSelector sel in selectors)
{
itemToSelector.TryAdd(sel.Item, sel);
}
List<InventoryItemSelector> sorted = new List<InventoryItemSelector>(selectors.Count);
foreach (ItemBase item in items)
{
if (itemToSelector.TryGetValue(item, out InventoryItemSelector sel))
{
sorted.Add(sel);
}
}
selectors.Clear();
selectors.AddRange(sorted);
// 更新 UI 层级顺序
for (int i = 0; i < selectors.Count; i++)
{
selectors[i].transform.SetSiblingIndex(i);
}
// ── 筛选 ──
ItemFilter filter = categoryDropdown != null ? categoryDropdown.BuildFilter() : ItemFilter.None;
bool selectedHidden = false;
foreach (InventoryItemSelector selector in selectors)
{
if (selector == null || selector.Item == null) continue;
bool visible = filter.Match(selector.Item);
selector.gameObject.SetActive(visible);
if (!visible && selector == currentSelected)
{
selectedHidden = true;
}
}
if (selectedHidden)
{
currentSelected.SetSelected(false);
currentSelected = null;
itemDetailPanel?.ClearPanel();
}
}
// ─────────────────── Dropdown 回调 ───────────────────
private void OnFilterChanged(ItemFilter filter)
{
ApplySortAndFilter();
}
private void OnSortChanged(ItemSortMode mode)
{
ApplySortAndFilter();
}
// ================================================================
// 选择器管理
// ================================================================
private void PopulateFromList<T>(List<T> items) where T : ItemBase
{
if (items == null) return;
foreach (T item in items)
{
if (item == null || item.contentData == null) continue;
InventoryItemSelector selector = CreateSelector();
if (selector != null)
{
selector.Setup(item);
}
}
}
private InventoryItemSelector CreateSelector()
{
if (selectorPrefab == null || selectorContainer == null)
{
Debug.LogError("[InventoryUIPage] selectorPrefab 或 selectorContainer 未配置。");
return null;
}
GameObject obj = Instantiate(selectorPrefab, selectorContainer);
InventoryItemSelector selector = obj.GetComponent<InventoryItemSelector>();
if (selector == null)
{
Debug.LogError("[InventoryUIPage] selectorPrefab 缺少 InventoryItemSelector 组件。");
Destroy(obj);
return null;
}
selectors.Add(selector);
return selector;
}
private void ClearSelectors()
{
foreach (InventoryItemSelector selector in selectors)
{
if (selector != null)
{
Destroy(selector.gameObject);
}
}
selectors.Clear();
}
// ─────────────────── 按钮回调 ───────────────────
private void OnCloseClicked()
{
Close();
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b8ea321de103c2e4ab8833abc7897452