264 lines
10 KiB
C#
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);
|
|
}
|
|
}
|