Files
5.24BuYu/Assets/MyGame/aa/UI/Game/Sub/SuoDingPanel.cs
T
2026-10-07 18:33:54 +08:00

264 lines
10 KiB
C#

using Assets.MyGame.Scripts.Net.API.GameConfig_SubClass;
using Assets.MyGame.Scripts.Net.APIResponses.Enum;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 单独锁定面板(SuoDing.prefab)。
/// ⭐ 本阶段只做界面:
/// - 单列表不分类,只显示 黄金鱼/特殊鱼/Boss鱼/特殊Boss(不含普通鱼)
/// - 每个 item 带 Toggle(勾选=作为锁定目标)
/// - 两层排序:①鱼类型 特殊Boss > Boss鱼 > 特殊鱼 > 黄金鱼;②同类型内按最大爆奖倍数(与 item 显示同源)从大到小
/// - 全选/取消全选 两个按钮
/// - GetSelectedFishNumbers() 暴露选中列表,后续锁定功能从这里对接
/// </summary>
public class SuoDingPanel : SubUIBase
{
[Header("Item 模板(TuJianItem+Toggle,可挂在模板自身或子节点;模板未激活也行,克隆后会自动激活)")]
public GameObject prefab_Item;
[Header("列表父节点(不分类,所有条目都放这里)")]
public Transform parent_List;
[Header("按钮")]
public Button btn_SelectAll; // 全选
public Button btn_DeselectAll; // 取消全选
[Header("滚动视图")]
public ScrollRect scrollRect;
/// <summary>fishNumber → 条目(TuJianItem 显示 + Toggle 勾选)</summary>
private readonly Dictionary<string, Entry> entries = new Dictionary<string, Entry>();
/// <summary>当前勾选的鱼编号集合(Toggle 的 onValueChanged 实时维护,锁定系统 O(1) 查询)</summary>
private readonly HashSet<string> selectedSet = new HashSet<string>();
private class Entry
{
public string fishNumber;
public FishTypeEnum fishType;
public TuJianItem item;
public Toggle toggle;
}
public override void Awake()
{
base.Awake();
if (btn_SelectAll != null) btn_SelectAll.onClick.AddListener(SelectAll);
if (btn_DeselectAll != null) btn_DeselectAll.onClick.AddListener(DeselectAll);
BuildList();
// ⭐ 默认全部不选:不勾选 = 不限制(正常锁定),玩家想锁哪条就勾哪条
DeselectAll();
}
protected override void OnShow(object args = null)
{
base.OnShow(args);
// 打开时滚动到最上方
// ⭐ 只重置纵向(verticalNormalizedPosition):
// normalizedPosition 会同时写 x 轴(=0 横向滚到最左),ScrollRect 会直接改写
// content(列表父对象)的 anchoredPosition.x,导致父对象 X 从 0 被移走
if (scrollRect != null)
scrollRect.verticalNormalizedPosition = 1f;
}
protected override void OnHide()
{
base.OnHide();
// ⭐ 关闭面板 = 应用勾选结果:通知主面板打开锁定并按勾选白名单自动锁定
// (parentUIBase 就是挂着本面板的主面板,各游戏主面板都继承 GameMainPanel_FishBase)
if (uIManager != null && uIManager.parentUIBase is GameMainPanel_FishBase main)
main.ApplySuoDingSelection();
}
// ==================== 列表构建 ====================
private void BuildList()
{
if (prefab_Item == null || parent_List == null) return;
// ① 收集本房间可出鱼编号(鱼阵条目解析出阵内实际鱼),去重
var fishNumbers = new HashSet<string>();
var spawnList = CreateFishManager.Instance != null ? CreateFishManager.Instance.spawnList : null;
if (spawnList != null)
{
foreach (var spawn in spawnList)
{
if (spawn.type == 2)
{
// 鱼阵条目:fishNumber 存的是鱼阵编号,解析出阵内实际生成的鱼
if (CreateFishManager.Instance.FishArrayDatas.TryGetValue(spawn.fishNumber, out var yz))
TryAddFishNumber(fishNumbers, yz.fishNumber);
}
else
{
TryAddFishNumber(fishNumbers, spawn.fishNumber);
}
}
}
// ② 过滤:只保留 黄金鱼/特殊鱼/Boss鱼/特殊Boss(不显示普通鱼)
// 同时带上"最大爆奖倍数"(与 item 上显示的数字同源,第二层排序用)
var filtered = new List<(string fishNumber, FishTypeEnum fishType, double multiple)>();
foreach (var fn in fishNumbers)
{
if (!GameManager.Instance.dic_fishTypeConfigs.TryGetValue(fn, out var cfg)) continue;
var t = (FishTypeEnum)cfg.fishType;
if (t == FishTypeEnum.普通鱼) continue;
filtered.Add((fn, t, GetShowMultiple(cfg.fishMultipleDesc, cfg.fishScore)));
}
// ③ 两层排序(与 XJMH 锁定面板同口径):
// 第一层:鱼类型 特殊Boss > Boss鱼 > 特殊鱼 > 黄金鱼
// 第二层:同类型内按"最大爆奖倍数"从大到小;倍数相同再按鱼号
filtered.Sort((a, b) =>
{
int pa = GetTypeSortOrder(a.fishType);
int pb = GetTypeSortOrder(b.fishType);
if (pa != pb) return pa.CompareTo(pb);
int sc = b.multiple.CompareTo(a.multiple); // ⭐ 从大到小
if (sc != 0) return sc;
return CompareFishNumber(a.fishNumber, b.fishNumber);
});
// ④ 实例化条目
foreach (var (fishNumber, fishType, _) in filtered)
CreateItem(fishNumber, fishType);
}
/// <summary>
/// 取 item 上显示给玩家的"最大爆奖倍数"(排序用,保证顺序和 item 上的数字一致):
/// 优先解析服务端文案 fishMultipleDesc(如"最高500倍"、"1.5万倍"),
/// 解析不到数字时回退用 fishScore。
/// ⭐ public static:XJMH 锁定面板(PW_SetLock)也用同一份口径排序。
/// </summary>
public static double GetShowMultiple(string fishMultipleDesc, long fishScore)
{
double v = ParseNumber(fishMultipleDesc);
return v > 0 ? v : fishScore;
}
/// <summary>从文案里解析第一个数字(支持小数与"万/亿"单位;解析不到返回 0)</summary>
private static double ParseNumber(string s)
{
if (string.IsNullOrEmpty(s)) return 0;
int i = 0;
while (i < s.Length && (s[i] < '0' || s[i] > '9')) i++; // 跳过前缀(如"最高")
if (i >= s.Length) return 0;
int start = i;
bool dot = false;
while (i < s.Length && ((s[i] >= '0' && s[i] <= '9') || (s[i] == '.' && !dot)))
{
if (s[i] == '.') dot = true;
i++;
}
double v;
if (!double.TryParse(s.Substring(start, i - start),
System.Globalization.NumberStyles.Float,
System.Globalization.CultureInfo.InvariantCulture, out v))
return 0;
if (i < s.Length)
{
if (s[i] == '万') v *= 10000;
else if (s[i] == '亿') v *= 100000000;
}
return v;
}
private void TryAddFishNumber(HashSet<string> set, string fishNumber)
{
if (!string.IsNullOrEmpty(fishNumber))
set.Add(fishNumber);
}
/// <summary>显示排序:特殊Boss(0) > Boss鱼(1) > 特殊鱼(2) > 黄金鱼(3),与自动锁定优先级一致</summary>
private static int GetTypeSortOrder(FishTypeEnum t)
{
switch (t)
{
case FishTypeEnum.特殊Boss: return 0;
case FishTypeEnum.Boss鱼: return 1;
case FishTypeEnum.特殊鱼: return 2;
case FishTypeEnum.黄金鱼: return 3;
default: return int.MaxValue;
}
}
private static int CompareFishNumber(string a, string b)
{
if (int.TryParse(a, out var na) && int.TryParse(b, out var nb))
return na.CompareTo(nb);
return string.CompareOrdinal(a, b);
}
private void CreateItem(string fishNumber, FishTypeEnum fishType)
{
// 模板是面板下的未激活场景对象,克隆后要手动激活
var go = Instantiate(prefab_Item, parent_List);
go.SetActive(true);
go.name = $"SuoDingItem_{fishNumber}";
// TuJianItem / Toggle 可挂在模板自身或子节点(两种摆法都兼容)
var item = go.GetComponentInChildren<TuJianItem>(true);
var toggle = go.GetComponentInChildren<Toggle>(true);
if (item == null) return;
// 黄金鱼显示固定倍数,特殊鱼/Boss/特殊Boss显示"最高X倍"(与图鉴一致)
item.InItItem(new RoomFishDetailConfig { fishNumber = fishNumber }, fishType == FishTypeEnum.黄金鱼);
if (toggle != null)
{
// ⭐ 多选:清掉可能误挂的排他 ToggleGroup(注册进组后全选会被组吞成单选)
if (toggle.group != null) toggle.group = null;
// ⭐ 勾选状态实时同步到 selectedSet(全选/取消全选/手动点击都会触发 onValueChanged)
toggle.onValueChanged.AddListener(on =>
{
if (on) selectedSet.Add(fishNumber);
else selectedSet.Remove(fishNumber);
});
if (toggle.isOn) selectedSet.Add(fishNumber);
}
entries[fishNumber] = new Entry { fishNumber = fishNumber, fishType = fishType, item = item, toggle = toggle };
}
// ==================== 全选/取消全选 ====================
public void SelectAll()
{
foreach (var e in entries.Values)
if (e.toggle != null) e.toggle.isOn = true;
}
public void DeselectAll()
{
foreach (var e in entries.Values)
if (e.toggle != null) e.toggle.isOn = false;
}
// ==================== 选中列表(锁定对接入口) ====================
/// <summary>是否至少勾选了一条(白名单是否生效)。锁定系统每帧查询,用 O(1) 属性</summary>
public bool HasSelection => selectedSet.Count > 0;
/// <summary>当前勾选的鱼编号列表(锁定系统从这里读取)</summary>
public List<string> GetSelectedFishNumbers()
{
return new List<string>(selectedSet);
}
/// <summary>某条鱼是否被勾选(未创建条目视为未选中)。O(1),锁定系统逐鱼查询用</summary>
public bool IsFishSelected(string fishNumber)
{
return !string.IsNullOrEmpty(fishNumber) && selectedSet.Contains(fishNumber);
}
}