8.30
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9618a0e69480c40b383585e41cda54a1
|
||||
guid: 4df8f90e8698941068b8d0dd7c3af46e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
@@ -0,0 +1,41 @@
|
||||
using SepCore.Definition;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 使用 Luban 格式化文本表(TbFormatText)驱动 TextMeshProUGUI 的组件。
|
||||
/// 在 Inspector 上填写 Key,调用 Set 传入格式化参数即可更新文本。
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(TextMeshProUGUI))]
|
||||
public class FormatTextUI : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private string key;
|
||||
|
||||
private TextMeshProUGUI _text;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_text = GetComponent<TextMeshProUGUI>();
|
||||
}
|
||||
|
||||
public void Set(params object[] args)
|
||||
{
|
||||
FormatText format = GameEntry.Luban.Tables.TbFormatText.GetOrDefault(key);
|
||||
if (format == null)
|
||||
{
|
||||
Log.Warning("Can not find format text '{0}'.", key);
|
||||
return;
|
||||
}
|
||||
|
||||
_text.SetText(string.Format(format.Format, args));
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_text.SetText(string.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ba271361c636f48edb5d7d8ba15a595c
|
||||
guid: 6566a3a7cfd184008ab2282feea295f8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -6,16 +6,8 @@ namespace SepCore.UI
|
||||
[DisallowMultipleComponent]
|
||||
public partial class CombatReadinessView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI squadMemberText;
|
||||
[SerializeField] public global::UnityEngine.RectTransform characterSlotRoot;
|
||||
[SerializeField] public global::SepCore.UI.CharacterSlotItem characterSlotTemplate;
|
||||
[SerializeField] public global::UnityEngine.UI.ToggleGroup difficultyTabsToggleGroup;
|
||||
[SerializeField] public global::TMPro.TMP_InputField seedInput;
|
||||
[SerializeField] public global::UnityEngine.UI.Button randomizeButton;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI partySizeText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI mapIdText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI timeLimitText;
|
||||
[SerializeField] public global::UnityEngine.UI.Button beginRunButton;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI storageText;
|
||||
[SerializeField] public global::SepCore.UI.SquadForm squadForm;
|
||||
[SerializeField] public global::SepCore.UI.DeploymentForm deploymentForm;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 233579b69c85c4f9db143fcf0368c36a
|
||||
guid: e9d3ff59008964126bb0c8052f0626e0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
@@ -0,0 +1,13 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class DeploymentForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private DeploymentView _view = null;
|
||||
|
||||
public DeploymentView View => _view;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f585fae70a14d446ba433f3244efded1
|
||||
guid: 37901c3791a804ff6b35692ab2f67f04
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -0,0 +1,19 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class DeploymentView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public global::UnityEngine.UI.Toggle tier1Toggle;
|
||||
[SerializeField] public global::UnityEngine.UI.Toggle tier2Toggle;
|
||||
[SerializeField] public global::UnityEngine.UI.Toggle tier3Toggle;
|
||||
[SerializeField] public global::TMPro.TMP_InputField seedInput;
|
||||
[SerializeField] public global::UnityEngine.UI.Button randomizeButton;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI partySizeText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI mapIdText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI timeLimitText;
|
||||
[SerializeField] public global::UnityEngine.UI.Button beginRunButton;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bffe339530c484a4b83162e20f163ed8
|
||||
guid: 0e9a8d6edf3794bc69f3b822e538ff96
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -0,0 +1,195 @@
|
||||
using System.Collections.Generic;
|
||||
using SepCore.Base;
|
||||
using SepCore.Definition;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 物品列表界面逻辑(手写 partial,与自动生成的 InventoryForm.cs 合并)。
|
||||
/// 支持按物品类型筛选(ALL / 战利品 / 装备 / 消耗品)。
|
||||
/// 注意:本表单作为嵌套表单挂在 LobbyForm/WarehouseForm 下,UGF 生命周期(OnInit/OnOpen)
|
||||
/// 不会被框架调用,事件绑定改为幂等式(EnsureListenersBound)。
|
||||
/// </summary>
|
||||
public partial class InventoryForm : UGuiForm
|
||||
{
|
||||
private bool _listenersBound = false;
|
||||
private IReadOnlyList<ItemStack> _stacks = null;
|
||||
private ItemType? _filterType = null;
|
||||
private List<ItemStack> _visibleStacks = new List<ItemStack>();
|
||||
private readonly List<WarehouseSlotItem> _slots = new List<WarehouseSlotItem>();
|
||||
|
||||
private void EnsureListenersBound()
|
||||
{
|
||||
if (_listenersBound)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_listenersBound = true;
|
||||
View.allToggle.onValueChanged.AddListener(OnAllToggleValueChanged);
|
||||
View.lootToggle.onValueChanged.AddListener(OnLootToggleValueChanged);
|
||||
View.equipmentToggle.onValueChanged.AddListener(OnEquipmentToggleValueChanged);
|
||||
View.consumablesToggle.onValueChanged.AddListener(OnConsumablesToggleValueChanged);
|
||||
}
|
||||
|
||||
private void OnAllToggleValueChanged(bool isOn)
|
||||
{
|
||||
if (isOn)
|
||||
{
|
||||
SetFilter(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLootToggleValueChanged(bool isOn)
|
||||
{
|
||||
if (isOn)
|
||||
{
|
||||
SetFilter(ItemType.Loot);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEquipmentToggleValueChanged(bool isOn)
|
||||
{
|
||||
if (isOn)
|
||||
{
|
||||
SetFilter(ItemType.Equipment);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnConsumablesToggleValueChanged(bool isOn)
|
||||
{
|
||||
if (isOn)
|
||||
{
|
||||
SetFilter(ItemType.Consumable);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetFilter(ItemType? filterType)
|
||||
{
|
||||
_filterType = filterType;
|
||||
RebuildGrid();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置列表数据并重建网格,保留当前筛选。
|
||||
/// </summary>
|
||||
public void RefreshList(IReadOnlyList<ItemStack> stacks)
|
||||
{
|
||||
EnsureListenersBound();
|
||||
|
||||
_stacks = stacks;
|
||||
RebuildGrid();
|
||||
}
|
||||
|
||||
private void RebuildGrid()
|
||||
{
|
||||
InventoryView inventoryView = View;
|
||||
if (inventoryView == null || inventoryView.warehouseSlotRoot == null ||
|
||||
inventoryView.warehouseSlotTemplate == null)
|
||||
{
|
||||
Log.Warning("InventoryForm is not fully configured.");
|
||||
return;
|
||||
}
|
||||
|
||||
int slotCount = GameEntry.Luban.Global.Data.WarehouseSlotCount;
|
||||
if (slotCount <= 0)
|
||||
{
|
||||
Log.Warning("Warehouse slot count from global config is invalid: {0}.", slotCount);
|
||||
return;
|
||||
}
|
||||
|
||||
_visibleStacks = CollectVisibleStacks();
|
||||
_slots.Clear();
|
||||
|
||||
WarehouseSlotItem template = inventoryView.warehouseSlotTemplate;
|
||||
template.gameObject.SetActive(false);
|
||||
|
||||
for (int i = inventoryView.warehouseSlotRoot.childCount - 1; i >= 0; i--)
|
||||
{
|
||||
Transform child = inventoryView.warehouseSlotRoot.GetChild(i);
|
||||
if (child == template.transform)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
|
||||
for (int i = 0; i < slotCount; i++)
|
||||
{
|
||||
WarehouseSlotItem slot = Instantiate(template, inventoryView.warehouseSlotRoot);
|
||||
slot.gameObject.SetActive(true);
|
||||
slot.SetSlotId(i);
|
||||
if (i < _visibleStacks.Count)
|
||||
{
|
||||
slot.SetItem(_visibleStacks[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
slot.SetEmpty();
|
||||
}
|
||||
|
||||
_slots.Add(slot);
|
||||
}
|
||||
|
||||
if (inventoryView.itemCountFormatText != null)
|
||||
{
|
||||
int usedSlotCount = _stacks != null ? _stacks.Count : 0;
|
||||
inventoryView.itemCountFormatText.Set(usedSlotCount, slotCount);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按网格索引高亮对应格子,其余格子清除选中。
|
||||
/// </summary>
|
||||
public void SetSelectedSlot(int slotId)
|
||||
{
|
||||
for (int i = 0; i < _slots.Count; i++)
|
||||
{
|
||||
_slots[i].SetSelected(i == slotId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定网格索引对应的物品 ID;空格或越界返回 0。
|
||||
/// </summary>
|
||||
public int GetItemIdAtSlot(int slotId)
|
||||
{
|
||||
if (slotId < 0 || slotId >= _visibleStacks.Count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _visibleStacks[slotId].itemId;
|
||||
}
|
||||
|
||||
private List<ItemStack> CollectVisibleStacks()
|
||||
{
|
||||
List<ItemStack> visible = new List<ItemStack>();
|
||||
if (_stacks == null)
|
||||
{
|
||||
return visible;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _stacks.Count; i++)
|
||||
{
|
||||
ItemStack stack = _stacks[i];
|
||||
if (_filterType.HasValue)
|
||||
{
|
||||
ItemConfig config = GameEntry.Luban.Get<ItemConfig>(stack.itemId);
|
||||
if (config == null || config.ItemType != _filterType.Value)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
visible.Add(stack);
|
||||
}
|
||||
|
||||
return visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4774c8ef6d24f489c8c5858aa014ff13
|
||||
guid: 0452e5e692a1e42118fa2097e6575eaa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -6,10 +6,15 @@ namespace SepCore.UI
|
||||
[DisallowMultipleComponent]
|
||||
public partial class InventoryView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public global::UnityEngine.UI.Toggle allToggle;
|
||||
[SerializeField] public global::UnityEngine.UI.Toggle lootToggle;
|
||||
[SerializeField] public global::UnityEngine.UI.Toggle equipmentToggle;
|
||||
[SerializeField] public global::UnityEngine.UI.Toggle consumablesToggle;
|
||||
[SerializeField] public global::TMPro.TMP_InputField searchInput;
|
||||
[SerializeField] public global::UnityEngine.UI.Button sortButton;
|
||||
[SerializeField] public global::UnityEngine.UI.ScrollRect itemScroll;
|
||||
[SerializeField] public global::UnityEngine.RectTransform warehouseSlotRoot;
|
||||
[SerializeField] public global::SepCore.UI.WarehouseSlotItem warehouseSlotTemplate;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI itemCountFormatText;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class InventoryPanelForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private InventoryPanelView _view = null;
|
||||
|
||||
public InventoryPanelView View => _view;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class InventoryPanelView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public global::UnityEngine.UI.InputField searchInput;
|
||||
[SerializeField] public global::UnityEngine.UI.Button sortButton;
|
||||
[SerializeField] public global::UnityEngine.UI.ScrollRect itemScroll;
|
||||
[SerializeField] public global::UnityEngine.RectTransform warehouseSlotRoot;
|
||||
[SerializeField] public global::SepCore.UI.WarehouseSlotItem warehouseSlotTemplate;
|
||||
[SerializeField] public global::UnityEngine.UI.Text itemCountText;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using SepCore.Definition;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
@@ -11,10 +11,57 @@ namespace SepCore.UI
|
||||
[SerializeField] private Image bg;
|
||||
[SerializeField] private Image icon;
|
||||
[SerializeField] private TextMeshProUGUI characterName;
|
||||
[SerializeField] private TextMeshProUGUI hpText;
|
||||
[SerializeField] private TextMeshProUGUI mpText;
|
||||
[SerializeField] private TextMeshProUGUI speedText;
|
||||
[SerializeField] private TextMeshProUGUI atkText;
|
||||
[SerializeField] private TextMeshProUGUI matText;
|
||||
[SerializeField] private FormatTextUI hpText;
|
||||
[SerializeField] private FormatTextUI mpText;
|
||||
[SerializeField] private FormatTextUI speedText;
|
||||
[SerializeField] private FormatTextUI atkText;
|
||||
[SerializeField] private FormatTextUI matText;
|
||||
|
||||
/// <summary>
|
||||
/// 用存档角色填充格子;角色配置不存在时按空格子显示。
|
||||
/// </summary>
|
||||
public void SetCharacter(CharacterSave save)
|
||||
{
|
||||
CharacterConfig config = GameEntry.Luban.Get<CharacterConfig>(save.characterId);
|
||||
if (config == null)
|
||||
{
|
||||
Log.Warning("Can not find character config '{0}' for squad slot.", save.characterId);
|
||||
SetEmpty();
|
||||
return;
|
||||
}
|
||||
|
||||
characterName.text = config.Name;
|
||||
hpText.Set(config.MaxHp);
|
||||
mpText.Set(config.MaxMp);
|
||||
speedText.Set(config.Speed);
|
||||
atkText.Set(config.Atk);
|
||||
matText.Set(config.Mat);
|
||||
HideIcon();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示为空格子。
|
||||
/// </summary>
|
||||
public void SetEmpty()
|
||||
{
|
||||
characterName.text = string.Empty;
|
||||
hpText.Clear();
|
||||
mpText.Clear();
|
||||
speedText.Clear();
|
||||
atkText.Clear();
|
||||
matText.Clear();
|
||||
HideIcon();
|
||||
}
|
||||
|
||||
private void HideIcon()
|
||||
{
|
||||
if (icon == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
icon.sprite = null;
|
||||
icon.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,137 @@
|
||||
using SepCore.Base;
|
||||
using SepCore.Definition;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
public class WarehouseSlotItem : MonoBehaviour
|
||||
{
|
||||
private static readonly Color RarityWhite = new Color32(245, 247, 248, 255);
|
||||
private static readonly Color RarityGreen = new Color32(93, 155, 97, 255);
|
||||
private static readonly Color RarityBlue = new Color32(52, 127, 168, 255);
|
||||
private static readonly Color RarityGold = new Color32(214, 169, 61, 255);
|
||||
private static readonly Color RarityRed = new Color32(185, 87, 79, 255);
|
||||
private static readonly Color RarityEmpty = new Color32(111, 101, 90, 255);
|
||||
private static readonly Color SelectedBgColor = new Color(0.86f, 0.95f, 1f, 1f);
|
||||
|
||||
[SerializeField] private Image bg;
|
||||
[SerializeField] private Button button;
|
||||
[SerializeField] private Image icon;
|
||||
[SerializeField] private Image rarity;
|
||||
[SerializeField] private TextMeshProUGUI quantityText;
|
||||
|
||||
private int _slotId = 0;
|
||||
private bool _filled = false;
|
||||
private bool _clickBound = false;
|
||||
|
||||
/// <summary>
|
||||
/// 设置格子在固定网格中的索引,点击事件以此作为唯一标识。
|
||||
/// </summary>
|
||||
public void SetSlotId(int slotId)
|
||||
{
|
||||
_slotId = slotId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用物品堆叠填充格子;物品配置不存在时按空格子显示。
|
||||
/// </summary>
|
||||
public void SetItem(ItemStack stack)
|
||||
{
|
||||
ItemConfig config = GameEntry.Luban.Get<ItemConfig>(stack.itemId);
|
||||
if (config == null)
|
||||
{
|
||||
Log.Warning("Can not find item config '{0}' for warehouse slot.", stack.itemId);
|
||||
SetEmpty();
|
||||
return;
|
||||
}
|
||||
|
||||
_filled = true;
|
||||
rarity.color = GetRarityColor(config.Rarity);
|
||||
quantityText.text = stack.count.ToString();
|
||||
HideIcon();
|
||||
BindClick();
|
||||
if (button != null)
|
||||
{
|
||||
button.interactable = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示为空格子。
|
||||
/// </summary>
|
||||
public void SetEmpty()
|
||||
{
|
||||
_filled = false;
|
||||
rarity.color = RarityEmpty;
|
||||
quantityText.text = string.Empty;
|
||||
HideIcon();
|
||||
if (button != null)
|
||||
{
|
||||
button.interactable = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置选中高亮。
|
||||
/// </summary>
|
||||
public void SetSelected(bool selected)
|
||||
{
|
||||
if (bg != null)
|
||||
{
|
||||
bg.color = selected ? SelectedBgColor : Color.white;
|
||||
}
|
||||
}
|
||||
|
||||
private void BindClick()
|
||||
{
|
||||
if (_clickBound || button == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_clickBound = true;
|
||||
button.onClick.AddListener(OnClick);
|
||||
}
|
||||
|
||||
private void OnClick()
|
||||
{
|
||||
if (!_filled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameEntry.Event.Fire(this, WarehouseSlotItemClickEventArgs.Create(_slotId));
|
||||
}
|
||||
|
||||
private void HideIcon()
|
||||
{
|
||||
if (icon == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
icon.sprite = null;
|
||||
icon.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
private static Color GetRarityColor(Rarity rarity)
|
||||
{
|
||||
switch (rarity)
|
||||
{
|
||||
case Rarity.Green:
|
||||
return RarityGreen;
|
||||
case Rarity.Blue:
|
||||
return RarityBlue;
|
||||
case Rarity.Gold:
|
||||
return RarityGold;
|
||||
case Rarity.Red:
|
||||
return RarityRed;
|
||||
default:
|
||||
return RarityWhite;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
using SepCore.Definition;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 道具详情界面逻辑(手写 partial,与自动生成的 ItemDetailsForm.cs 合并)。
|
||||
/// 只提供详情显示能力,由调用方(WarehouseForm)传入物品 ID 后刷新。
|
||||
/// </summary>
|
||||
public partial class ItemDetailsForm : UGuiForm
|
||||
{
|
||||
/// <summary>
|
||||
/// 按物品 ID 刷新详情界面;配置不存在时清空显示。
|
||||
/// </summary>
|
||||
public void Refresh(int itemId)
|
||||
{
|
||||
ItemDetailsView view = View;
|
||||
if (view == null)
|
||||
{
|
||||
Log.Warning("ItemDetailsForm view is not configured.");
|
||||
return;
|
||||
}
|
||||
|
||||
ItemConfig config = GameEntry.Luban.Get<ItemConfig>(itemId);
|
||||
if (config == null)
|
||||
{
|
||||
Log.Warning("Can not find item config '{0}' for item details.", itemId);
|
||||
ClearDetails(view);
|
||||
return;
|
||||
}
|
||||
|
||||
if (view.itemDetailNameText != null)
|
||||
{
|
||||
view.itemDetailNameText.text = config.Name;
|
||||
}
|
||||
|
||||
if (view.itemDetailTypeText != null)
|
||||
{
|
||||
view.itemDetailTypeText.text = GetItemTypeName(config.ItemType) + " / " + GetRarityName(config.Rarity);
|
||||
}
|
||||
|
||||
if (view.hpFormatText != null)
|
||||
{
|
||||
view.hpFormatText.Set(config.MaxHpBonus);
|
||||
}
|
||||
|
||||
if (view.atkFormatText != null)
|
||||
{
|
||||
view.atkFormatText.Set(config.AtkBonus);
|
||||
}
|
||||
|
||||
if (view.mpFormatText != null)
|
||||
{
|
||||
view.mpFormatText.Set(config.MaxMpBonus);
|
||||
}
|
||||
|
||||
if (view.matFormatText != null)
|
||||
{
|
||||
view.matFormatText.Set(config.MatBonus);
|
||||
}
|
||||
|
||||
if (view.speedFormatText != null)
|
||||
{
|
||||
view.speedFormatText.Set(0);
|
||||
}
|
||||
|
||||
if (view.stackFormatText != null)
|
||||
{
|
||||
view.stackFormatText.Set(config.StackLimit);
|
||||
}
|
||||
|
||||
if (view.itemDetailDescriptionText != null)
|
||||
{
|
||||
view.itemDetailDescriptionText.text = string.Empty;
|
||||
}
|
||||
|
||||
if (view.itemDetailIcon != null)
|
||||
{
|
||||
view.itemDetailIcon.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ClearDetails(ItemDetailsView view)
|
||||
{
|
||||
if (view.itemDetailNameText != null)
|
||||
{
|
||||
view.itemDetailNameText.text = string.Empty;
|
||||
}
|
||||
|
||||
if (view.itemDetailTypeText != null)
|
||||
{
|
||||
view.itemDetailTypeText.text = string.Empty;
|
||||
}
|
||||
|
||||
if (view.itemDetailDescriptionText != null)
|
||||
{
|
||||
view.itemDetailDescriptionText.text = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetItemTypeName(ItemType itemType)
|
||||
{
|
||||
switch (itemType)
|
||||
{
|
||||
case ItemType.Loot:
|
||||
return "战利品";
|
||||
case ItemType.Equipment:
|
||||
return "装备";
|
||||
case ItemType.Consumable:
|
||||
return "消耗品";
|
||||
default:
|
||||
return "未知";
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetRarityName(Rarity rarity)
|
||||
{
|
||||
switch (rarity)
|
||||
{
|
||||
case Rarity.White:
|
||||
return "白";
|
||||
case Rarity.Green:
|
||||
return "绿";
|
||||
case Rarity.Blue:
|
||||
return "蓝";
|
||||
case Rarity.Gold:
|
||||
return "金";
|
||||
case Rarity.Red:
|
||||
return "红";
|
||||
default:
|
||||
return "无";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 33d70aa8e73294a65b7b132a8a0619af
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -9,12 +9,12 @@ namespace SepCore.UI
|
||||
[SerializeField] public global::UnityEngine.UI.Image itemDetailIcon;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI itemDetailNameText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI itemDetailTypeText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI hpText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI atkText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI mpText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI matText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI speedText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI stackText;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI hpFormatText;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI atkFormatText;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI mpFormatText;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI matFormatText;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI speedFormatText;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI stackFormatText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI itemDetailDescriptionText;
|
||||
[SerializeField] public global::UnityEngine.UI.Button openLoadoutButton;
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class ItemDetailsPanelForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private ItemDetailsPanelView _view = null;
|
||||
|
||||
public ItemDetailsPanelView View => _view;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class ItemDetailsPanelView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public global::UnityEngine.UI.Image itemDetailIcon;
|
||||
[SerializeField] public global::UnityEngine.UI.Text nameText;
|
||||
[SerializeField] public global::UnityEngine.UI.Text typeText;
|
||||
[SerializeField] public global::UnityEngine.UI.Text hpText;
|
||||
[SerializeField] public global::UnityEngine.UI.Text atkText;
|
||||
[SerializeField] public global::UnityEngine.UI.Text mpText;
|
||||
[SerializeField] public global::UnityEngine.UI.Text matText;
|
||||
[SerializeField] public global::UnityEngine.UI.Text speedText;
|
||||
[SerializeField] public global::UnityEngine.UI.Text stackText;
|
||||
[SerializeField] public global::UnityEngine.UI.Button openLoadoutButton;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
using DG.Tweening;
|
||||
using SepCore.Definition;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 大厅界面逻辑(手写 partial,与自动生成的 LobbyForm.cs 合并)。
|
||||
/// 导航使用 Toggle + ToggleGroup 管理选中状态;本类只负责页面切换与标记动画。
|
||||
/// </summary>
|
||||
public partial class LobbyForm : UGuiForm
|
||||
{
|
||||
private const float SelectionMarkerMoveDuration = 0.25f;
|
||||
|
||||
private enum LobbyPage
|
||||
{
|
||||
CombatReadiness,
|
||||
Warehouse,
|
||||
}
|
||||
|
||||
protected override void OnInit(object userData)
|
||||
{
|
||||
base.OnInit(userData);
|
||||
|
||||
View.homeToggle.onValueChanged.AddListener(OnHomeToggleValueChanged);
|
||||
View.warehouseToggle.onValueChanged.AddListener(OnWarehouseToggleValueChanged);
|
||||
View.loadoutToggle.onValueChanged.AddListener(OnLoadoutToggleValueChanged);
|
||||
}
|
||||
|
||||
protected override void OnOpen(object userData)
|
||||
{
|
||||
base.OnOpen(userData);
|
||||
SwitchPage(LobbyPage.CombatReadiness, View.homeToggle);
|
||||
}
|
||||
|
||||
protected override void OnClose(bool isShutdown, object userData)
|
||||
{
|
||||
if (View.selectionMarkerObject != null)
|
||||
{
|
||||
View.selectionMarkerObject.DOKill();
|
||||
}
|
||||
|
||||
View.homeToggle.onValueChanged.RemoveListener(OnHomeToggleValueChanged);
|
||||
View.warehouseToggle.onValueChanged.RemoveListener(OnWarehouseToggleValueChanged);
|
||||
View.loadoutToggle.onValueChanged.RemoveListener(OnLoadoutToggleValueChanged);
|
||||
|
||||
base.OnClose(isShutdown, userData);
|
||||
}
|
||||
|
||||
private void OnHomeToggleValueChanged(bool isOn)
|
||||
{
|
||||
if (isOn)
|
||||
{
|
||||
SwitchPage(LobbyPage.CombatReadiness, View.homeToggle);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWarehouseToggleValueChanged(bool isOn)
|
||||
{
|
||||
if (isOn)
|
||||
{
|
||||
SwitchPage(LobbyPage.Warehouse, View.warehouseToggle);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLoadoutToggleValueChanged(bool isOn)
|
||||
{
|
||||
// 战备页暂无对应界面,选中状态由 ToggleGroup 维护,仅预留切换入口
|
||||
}
|
||||
|
||||
private void SwitchPage(LobbyPage page, Toggle activeToggle)
|
||||
{
|
||||
bool showCombatReadiness = page == LobbyPage.CombatReadiness;
|
||||
bool showWarehouse = page == LobbyPage.Warehouse;
|
||||
|
||||
if (View.combatRandinessForm != null)
|
||||
{
|
||||
View.combatRandinessForm.gameObject.SetActive(showCombatReadiness);
|
||||
}
|
||||
|
||||
if (View.warehouseForm != null)
|
||||
{
|
||||
View.warehouseForm.gameObject.SetActive(showWarehouse);
|
||||
}
|
||||
|
||||
MoveSelectionMarker(activeToggle.transform as RectTransform);
|
||||
|
||||
if (showCombatReadiness)
|
||||
{
|
||||
RefreshCombatReadiness();
|
||||
}
|
||||
|
||||
if (showWarehouse)
|
||||
{
|
||||
RefreshWarehouse();
|
||||
}
|
||||
}
|
||||
|
||||
private void MoveSelectionMarker(RectTransform targetToggle)
|
||||
{
|
||||
RectTransform marker = View.selectionMarkerObject;
|
||||
if (marker == null || targetToggle == null || marker.parent == targetToggle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 把标记相对目标 Toggle 锚点(anchorMin)的偏移,换算到 Toggle pivot 的局部坐标空间:
|
||||
// 锚点相对 pivot 的偏移 = (anchor - pivot) * rect 尺寸。
|
||||
Vector3 targetLocalPosition = new Vector3(
|
||||
marker.anchoredPosition.x + (marker.anchorMin.x - targetToggle.pivot.x) * targetToggle.rect.width,
|
||||
marker.anchoredPosition.y + (marker.anchorMin.y - targetToggle.pivot.y) * targetToggle.rect.height,
|
||||
0f);
|
||||
Vector3 targetWorldPosition = targetToggle.TransformPoint(targetLocalPosition);
|
||||
marker.DOKill();
|
||||
marker.DOMove(targetWorldPosition, SelectionMarkerMoveDuration)
|
||||
.SetEase(Ease.OutCubic)
|
||||
.OnComplete(() => marker.SetParent(targetToggle, true));
|
||||
}
|
||||
|
||||
private void RefreshCombatReadiness()
|
||||
{
|
||||
CombatReadinessForm form = View.combatRandinessForm;
|
||||
if (form == null)
|
||||
{
|
||||
Log.Warning("LobbyForm combat readiness form is not configured.");
|
||||
return;
|
||||
}
|
||||
|
||||
SaveData save = GameEntry.Save.Data;
|
||||
if (save == null || form.View == null || form.View.squadForm == null)
|
||||
{
|
||||
Log.Warning("LobbyForm can not refresh combat readiness.");
|
||||
return;
|
||||
}
|
||||
|
||||
form.View.squadForm.RefreshCharacterList(save.characters);
|
||||
}
|
||||
|
||||
private void RefreshWarehouse()
|
||||
{
|
||||
if (View.warehouseForm == null)
|
||||
{
|
||||
Log.Warning("LobbyForm warehouse form is not configured.");
|
||||
return;
|
||||
}
|
||||
|
||||
SaveData save = GameEntry.Save.Data;
|
||||
View.warehouseForm.Refresh(save != null ? save.mainWarehouse : null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d236e85e2eab43f6904de56f9e5246d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -6,11 +6,11 @@ namespace SepCore.UI
|
||||
[DisallowMultipleComponent]
|
||||
public partial class LobbyView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public global::UnityEngine.UI.Button homeButton;
|
||||
[SerializeField] public global::UnityEngine.UI.Toggle homeToggle;
|
||||
[SerializeField] public global::UnityEngine.RectTransform selectionMarkerObject;
|
||||
[SerializeField] public global::UnityEngine.UI.Button warehouseButton;
|
||||
[SerializeField] public global::UnityEngine.UI.Button loadoutButton;
|
||||
[SerializeField] public global::SepCore.UI.WarehouseView warehouseView;
|
||||
[SerializeField] public global::SepCore.UI.CombatReadinessView combatRandinessView;
|
||||
[SerializeField] public global::UnityEngine.UI.Toggle warehouseToggle;
|
||||
[SerializeField] public global::UnityEngine.UI.Toggle loadoutToggle;
|
||||
[SerializeField] public global::SepCore.UI.CombatReadinessForm combatRandinessForm;
|
||||
[SerializeField] public global::SepCore.UI.WarehouseForm warehouseForm;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class MainWarehouseForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private MainWarehouseView _view = null;
|
||||
|
||||
public MainWarehouseView View => _view;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca70f33fa4f2c4a989b89f280e24201a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,20 +0,0 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class MainWarehouseView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public global::UnityEngine.UI.Button homeButton;
|
||||
[SerializeField] public global::UnityEngine.UI.Button warehouseButton;
|
||||
[SerializeField] public global::UnityEngine.UI.Button loadoutButton;
|
||||
[SerializeField] public global::UnityEngine.UI.InputField searchInput;
|
||||
[SerializeField] public global::UnityEngine.UI.Button sortButton;
|
||||
[SerializeField] public global::UnityEngine.UI.ScrollRect itemScroll;
|
||||
[SerializeField] public global::UnityEngine.RectTransform warehouseSlotRoot;
|
||||
[SerializeField] public global::SepCore.UI.WarehouseSlotItem warehouseSlotTemplate;
|
||||
[SerializeField] public global::UnityEngine.UI.Text itemCountText;
|
||||
[SerializeField] public global::SepCore.UI.ItemDetailsView itemDetailsView;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f169da115e10a47e4b0b3bfefaff0d71
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -6,6 +6,7 @@
|
||||
"GUID:6055be8ebefd69e48b49212b09b47b2f",
|
||||
"GUID:11ec41dbc3557e6499b2845ba531a9b0",
|
||||
"GUID:363c5eb08ff8e6a439b85e37b8c20d96",
|
||||
"GUID:3bb549212964b4192b427888ac9382e7",
|
||||
"GUID:f51ebe6a0ceec4240a699833d6309b23",
|
||||
"GUID:d54b9488b03814a44ab937f0aeb738b1"
|
||||
],
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
@@ -10,7 +11,7 @@ namespace SepCore.UI
|
||||
public sealed class UISerializationRoot : MonoBehaviour
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class NestedViewReference
|
||||
public sealed class NestedFormReference
|
||||
{
|
||||
[SerializeField] private UISerializationRoot root;
|
||||
[SerializeField] private bool generateReference;
|
||||
@@ -21,7 +22,7 @@ namespace SepCore.UI
|
||||
public string VariableName => variableName;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
internal NestedViewReference(UISerializationRoot nestedRoot, string defaultVariableName)
|
||||
internal NestedFormReference(UISerializationRoot nestedRoot, string defaultVariableName)
|
||||
{
|
||||
root = nestedRoot;
|
||||
generateReference = true;
|
||||
@@ -33,6 +34,19 @@ namespace SepCore.UI
|
||||
generateReference = shouldGenerate;
|
||||
variableName = generatedVariableName;
|
||||
}
|
||||
|
||||
internal bool MigrateLegacyVariableName()
|
||||
{
|
||||
if (string.IsNullOrEmpty(variableName) ||
|
||||
!variableName.EndsWith("View", StringComparison.Ordinal) ||
|
||||
variableName.Length <= 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
variableName = variableName.Substring(0, variableName.Length - 4) + "Form";
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -40,10 +54,11 @@ namespace SepCore.UI
|
||||
private List<UISerializationItem> serializationItems = new List<UISerializationItem>();
|
||||
|
||||
[SerializeField, HideInInspector]
|
||||
private List<NestedViewReference> nestedViewReferences = new List<NestedViewReference>();
|
||||
[FormerlySerializedAs("nestedViewReferences")]
|
||||
private List<NestedFormReference> nestedFormReferences = new List<NestedFormReference>();
|
||||
|
||||
public IReadOnlyList<UISerializationItem> SerializationItems => serializationItems;
|
||||
public IReadOnlyList<NestedViewReference> NestedViewReferences => nestedViewReferences;
|
||||
public IReadOnlyList<NestedFormReference> NestedFormReferences => nestedFormReferences;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private bool refreshQueued;
|
||||
@@ -76,8 +91,18 @@ namespace SepCore.UI
|
||||
}
|
||||
|
||||
bool itemsChanged = !HasSameItems(ownedItems);
|
||||
bool nestedViewsChanged = !HasSameNestedViews(directNestedRoots);
|
||||
if (!itemsChanged && !nestedViewsChanged)
|
||||
bool nestedFormsChanged = !HasSameNestedForms(directNestedRoots);
|
||||
bool nestedNamesChanged = false;
|
||||
for (int i = 0; i < directNestedRoots.Count; i++)
|
||||
{
|
||||
NestedFormReference existing = FindNestedForm(directNestedRoots[i]);
|
||||
if (existing != null)
|
||||
{
|
||||
nestedNamesChanged |= existing.MigrateLegacyVariableName();
|
||||
}
|
||||
}
|
||||
|
||||
if (!itemsChanged && !nestedFormsChanged && !nestedNamesChanged)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -88,24 +113,24 @@ namespace SepCore.UI
|
||||
serializationItems.AddRange(ownedItems);
|
||||
}
|
||||
|
||||
if (nestedViewsChanged)
|
||||
if (nestedFormsChanged)
|
||||
{
|
||||
var next = new List<NestedViewReference>(directNestedRoots.Count);
|
||||
var next = new List<NestedFormReference>(directNestedRoots.Count);
|
||||
for (int i = 0; i < directNestedRoots.Count; i++)
|
||||
{
|
||||
UISerializationRoot nestedRoot = directNestedRoots[i];
|
||||
NestedViewReference existing = FindNestedView(nestedRoot);
|
||||
next.Add(existing ?? new NestedViewReference(nestedRoot, CreateDefaultNestedViewVariableName(nestedRoot)));
|
||||
NestedFormReference existing = FindNestedForm(nestedRoot);
|
||||
next.Add(existing ?? new NestedFormReference(nestedRoot, CreateDefaultNestedFormVariableName(nestedRoot)));
|
||||
}
|
||||
|
||||
nestedViewReferences = next;
|
||||
nestedFormReferences = next;
|
||||
}
|
||||
|
||||
UnityEditor.EditorUtility.SetDirty(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetNestedViewReference(UISerializationRoot nestedRoot, bool shouldGenerate, string variableName)
|
||||
public bool SetNestedFormReference(UISerializationRoot nestedRoot, bool shouldGenerate, string variableName)
|
||||
{
|
||||
if (nestedRoot == null || FindNearestParentRoot(nestedRoot.transform) != this)
|
||||
{
|
||||
@@ -113,7 +138,7 @@ namespace SepCore.UI
|
||||
}
|
||||
|
||||
RefreshItems();
|
||||
NestedViewReference reference = FindNestedView(nestedRoot);
|
||||
NestedFormReference reference = FindNestedForm(nestedRoot);
|
||||
if (reference == null)
|
||||
{
|
||||
throw new InvalidOperationException("The nested root is not registered.");
|
||||
@@ -130,7 +155,7 @@ namespace SepCore.UI
|
||||
return true;
|
||||
}
|
||||
|
||||
public static string CreateDefaultNestedViewVariableName(UISerializationRoot nestedRoot)
|
||||
public static string CreateDefaultNestedFormVariableName(UISerializationRoot nestedRoot)
|
||||
{
|
||||
string sourceName = nestedRoot == null ? "nested" : nestedRoot.gameObject.name.Replace("(Clone)", string.Empty).Trim();
|
||||
if (sourceName.EndsWith("Form", StringComparison.Ordinal) && sourceName.Length > 4)
|
||||
@@ -148,7 +173,7 @@ namespace SepCore.UI
|
||||
identifier = "Nested";
|
||||
}
|
||||
|
||||
return char.ToLowerInvariant(identifier[0]) + identifier.Substring(1) + "View";
|
||||
return char.ToLowerInvariant(identifier[0]) + identifier.Substring(1) + "Form";
|
||||
}
|
||||
|
||||
internal void QueueRefresh()
|
||||
@@ -220,16 +245,16 @@ namespace SepCore.UI
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HasSameNestedViews(List<UISerializationRoot> found)
|
||||
private bool HasSameNestedForms(List<UISerializationRoot> found)
|
||||
{
|
||||
if (nestedViewReferences.Count != found.Count)
|
||||
if (nestedFormReferences.Count != found.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < found.Count; i++)
|
||||
{
|
||||
if (nestedViewReferences[i] == null || nestedViewReferences[i].Root != found[i])
|
||||
if (nestedFormReferences[i] == null || nestedFormReferences[i].Root != found[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -238,11 +263,11 @@ namespace SepCore.UI
|
||||
return true;
|
||||
}
|
||||
|
||||
private NestedViewReference FindNestedView(UISerializationRoot nestedRoot)
|
||||
private NestedFormReference FindNestedForm(UISerializationRoot nestedRoot)
|
||||
{
|
||||
for (int i = 0; i < nestedViewReferences.Count; i++)
|
||||
for (int i = 0; i < nestedFormReferences.Count; i++)
|
||||
{
|
||||
NestedViewReference reference = nestedViewReferences[i];
|
||||
NestedFormReference reference = nestedFormReferences[i];
|
||||
if (reference != null && reference.Root == nestedRoot)
|
||||
{
|
||||
return reference;
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ceade84509cfa498a91c9a2fe55cc189
|
||||
guid: 82e9f2ea2a9254e848f8afcf5ff556e9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System.Collections.Generic;
|
||||
using SepCore.Definition;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 编队界面逻辑(手写 partial,与自动生成的 SquadForm.cs 合并)。
|
||||
/// 以传入的角色列表重建角色槽列表,模板槽来自 SquadView.characterSlotTemplate。
|
||||
/// </summary>
|
||||
public partial class SquadForm : UGuiForm
|
||||
{
|
||||
/// <summary>
|
||||
/// 按传入的角色列表重建角色槽列表 UI,每名角色一个槽位。
|
||||
/// </summary>
|
||||
public void RefreshCharacterList(IReadOnlyList<CharacterSave> characters)
|
||||
{
|
||||
SquadView squadView = View;
|
||||
if (squadView == null || squadView.characterSlotRoot == null ||
|
||||
squadView.characterSlotTemplate == null)
|
||||
{
|
||||
Log.Warning("SquadForm is not fully configured.");
|
||||
return;
|
||||
}
|
||||
|
||||
CharacterSlotItem template = squadView.characterSlotTemplate;
|
||||
template.gameObject.SetActive(false);
|
||||
|
||||
for (int i = squadView.characterSlotRoot.childCount - 1; i >= 0; i--)
|
||||
{
|
||||
Transform child = squadView.characterSlotRoot.GetChild(i);
|
||||
if (child == template.transform)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
|
||||
int characterCount = characters != null ? characters.Count : 0;
|
||||
for (int i = 0; i < characterCount; i++)
|
||||
{
|
||||
CharacterSlotItem slot = Instantiate(template, squadView.characterSlotRoot);
|
||||
slot.gameObject.SetActive(true);
|
||||
slot.SetCharacter(characters[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2a629f39601d3456ca1a8228059fa845
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class SquadForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private SquadView _view = null;
|
||||
|
||||
public SquadView View => _view;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c6542ec01d550457587508eff74a6957
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class SquadView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI squadMemberText;
|
||||
[SerializeField] public global::UnityEngine.RectTransform characterSlotRoot;
|
||||
[SerializeField] public global::SepCore.UI.CharacterSlotItem characterSlotTemplate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6eacd1573559d4784862ed9c21d5928c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,73 @@
|
||||
using System.Collections.Generic;
|
||||
using GameFramework.Event;
|
||||
using SepCore.Base;
|
||||
using SepCore.Definition;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 主仓库界面逻辑(手写 partial,与自动生成的 WarehouseForm.cs 合并)。
|
||||
/// 只提供仓库界面能力,数据由调用方(LobbyForm)传入;
|
||||
/// 监听格子点击事件,驱动选中高亮与详情界面刷新。
|
||||
/// 注意:本表单作为嵌套表单使用,UGF 生命周期不会被框架调用,
|
||||
/// 事件订阅改为幂等式(EnsureEventBound)。
|
||||
/// </summary>
|
||||
public partial class WarehouseForm : UGuiForm
|
||||
{
|
||||
private bool _eventBound = false;
|
||||
|
||||
/// <summary>
|
||||
/// 用主仓库内容刷新整个仓库界面(物品列表)。
|
||||
/// </summary>
|
||||
public void Refresh(IReadOnlyList<ItemStack> stacks)
|
||||
{
|
||||
EnsureEventBound();
|
||||
|
||||
InventoryForm inventoryForm = View.inventoryPanelForm;
|
||||
if (inventoryForm == null)
|
||||
{
|
||||
Log.Warning("WarehouseForm inventory panel form is not configured.");
|
||||
return;
|
||||
}
|
||||
|
||||
inventoryForm.RefreshList(stacks);
|
||||
}
|
||||
|
||||
private void EnsureEventBound()
|
||||
{
|
||||
if (_eventBound)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_eventBound = true;
|
||||
GameEntry.Event.Subscribe(WarehouseSlotItemClickEventArgs.EventId, OnWarehouseSlotItemClick);
|
||||
}
|
||||
|
||||
private void OnWarehouseSlotItemClick(object sender, GameEventArgs e)
|
||||
{
|
||||
if (this == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WarehouseSlotItemClickEventArgs ne = (WarehouseSlotItemClickEventArgs)e;
|
||||
int slotId = ne.SlotId;
|
||||
|
||||
if (View.inventoryPanelForm == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
View.inventoryPanelForm.SetSelectedSlot(slotId);
|
||||
|
||||
int itemId = View.inventoryPanelForm.GetItemIdAtSlot(slotId);
|
||||
if (itemId != 0 && View.itemDetailsPanelForm != null)
|
||||
{
|
||||
View.itemDetailsPanelForm.Refresh(itemId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be961300f50004e35ad24b4ff3368124
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -6,7 +6,7 @@ namespace SepCore.UI
|
||||
[DisallowMultipleComponent]
|
||||
public partial class WarehouseView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public global::SepCore.UI.InventoryView inventoryPanelView;
|
||||
[SerializeField] public global::SepCore.UI.ItemDetailsView itemDetailsPanelView;
|
||||
[SerializeField] public global::SepCore.UI.InventoryForm inventoryPanelForm;
|
||||
[SerializeField] public global::SepCore.UI.ItemDetailsForm itemDetailsPanelForm;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user