场景步骤宠物币消耗和步骤批次

This commit is contained in:
zhang hongbo 2026-03-25 11:03:13 +08:00
parent 8f1f51c506
commit e8067c676d
2 changed files with 960 additions and 0 deletions

View File

@ -0,0 +1,949 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using OfficeOpenXml;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace DesignTools.Scene
{
/// <summary>
/// 装饰场景消耗/批次配置工具
/// 读取 Docs/config/DecorateCost.xlsx 的 DecorateCost Sheet供策划编辑每步消耗与批次。
/// </summary>
public class DecorateCostPlannerEditor : BaseDesignToolEditor
{
private static readonly string[] BATCH_NAMES =
{
string.Empty,
"first",
"second",
"third",
"four",
"five",
"six",
"seven",
"eight",
"nine",
"ten",
"eleven",
"twelve",
"thirteen",
"fourteen",
"fifteen",
"sixteen",
"seventeen",
"eighteen",
"nineteen",
"twenty",
"twentyone",
"twentytwo",
"twentythree",
"twentyfour",
"twentyfive",
"twentysix",
"twentyseven",
"twentyeight",
"twentynine",
"thirty",
"thirtyone",
"thirtytwo",
"thirtythree",
"thirtyfour",
"thirtyfive",
"thirtysix",
"thirtyseven",
"thirtyeight",
"thirtynine",
"forty",
"fortyone"
};
private const string DECORATE_COST_EXCEL_NAME = "DecorateCost.xlsx";
private const string DECORATE_COST_SHEET_NAME = "DecorateCost";
private const int DATA_START_ROW = 3;
private const int TOTAL_COL_COUNT = 17;
private const int COL_ID = 1;
private const int COL_AREA_ID = 2;
private const int COL_SORT_ID = 3;
private const int COL_COST_COUNT = 4;
private const int COL_POS = 7;
private readonly List<DecorateCostExcelRow> allRows = new List<DecorateCostExcelRow>();
private readonly Dictionary<int, DecorateCostExcelRow> rowIndexMap = new Dictionary<int, DecorateCostExcelRow>();
private readonly HashSet<int> dirtyRowIndexes = new HashSet<int>();
private List<int> availableAreaIds = new List<int>();
private List<DecorateCostExcelRow> currentAreaStepRows = new List<DecorateCostExcelRow>();
private int selectedAreaId = -1;
private int areaIdInput = 2;
private int currentAreaExpectedStepCount;
[MenuItem("策划工具/场景/装饰场景消耗与批次")]
public static void ShowWindow()
{
var window = GetWindow<DecorateCostPlannerEditor>("装饰场景消耗与批次");
window.minSize = window.GetMinWindowSize();
window.Show();
}
protected override string GetDocsPathPrefKey()
{
return "DecorateCostPlannerEditor_DocsPath";
}
protected override string GetWindowTitle()
{
return "装饰场景消耗与批次工具";
}
protected override Vector2 GetMinWindowSize()
{
return new Vector2(920, 680);
}
protected override void LoadConfigData()
{
LoadDecorateCostExcel();
currentAreaStepRows.Clear();
currentAreaExpectedStepCount = 0;
selectedAreaId = -1;
areaIdInput = GetDefaultAreaId();
if (availableAreaIds.Count == 0)
{
EditorUtility.DisplayDialog("提示", "DecorateCost 中没有可编辑的 AreaId 数据。", "确定");
return;
}
EditorApplication.delayCall += ShowAreaInputDialog;
}
protected override void DrawDataEditor()
{
DrawAreaSelector();
EditorGUILayout.Space(6);
if (selectedAreaId < 0)
{
EditorGUILayout.HelpBox("请先输入并加载 AreaId。AreaId=1 不允许编辑AreaId=2-5 为 20 步AreaId>=6 为 25 步。", MessageType.Info);
return;
}
DrawAreaSummary();
EditorGUILayout.Space(6);
DrawQuickActions();
EditorGUILayout.Space(6);
DrawStepTable();
}
protected override void SaveDataToExcel()
{
SaveDecorateCostExcel();
}
private void LoadDecorateCostExcel()
{
allRows.Clear();
rowIndexMap.Clear();
dirtyRowIndexes.Clear();
string excelPath = GetDocsConfigFilePath(DECORATE_COST_EXCEL_NAME);
if (!File.Exists(excelPath))
{
throw new FileNotFoundException($"未找到 {DECORATE_COST_EXCEL_NAME}", excelPath);
}
using (ExcelPackage package = new ExcelPackage(new FileInfo(excelPath)))
{
ExcelWorksheet worksheet = package.Workbook.Worksheets[DECORATE_COST_SHEET_NAME];
if (worksheet == null)
{
throw new Exception($"未找到 Sheet: {DECORATE_COST_SHEET_NAME}");
}
if (worksheet.Dimension == null)
{
availableAreaIds = new List<int>();
return;
}
int rowCount = worksheet.Dimension.End.Row;
for (int row = DATA_START_ROW; row <= rowCount; row++)
{
string idText = worksheet.Cells[row, COL_ID].Text.Trim();
string areaIdText = worksheet.Cells[row, COL_AREA_ID].Text.Trim();
string sortIdText = worksheet.Cells[row, COL_SORT_ID].Text.Trim();
if (string.IsNullOrEmpty(idText) && string.IsNullOrEmpty(areaIdText) && string.IsNullOrEmpty(sortIdText))
{
continue;
}
string[] fields = new string[TOTAL_COL_COUNT];
for (int col = 1; col <= TOTAL_COL_COUNT; col++)
{
fields[col - 1] = worksheet.Cells[row, col].Text ?? string.Empty;
}
DecorateCostExcelRow dataRow = new DecorateCostExcelRow(row, fields);
allRows.Add(dataRow);
rowIndexMap[row] = dataRow;
}
}
availableAreaIds = allRows
.Select(row => row.AreaId)
.Where(areaId => areaId > 1)
.Distinct()
.OrderBy(areaId => areaId)
.ToList();
}
private void DrawAreaSelector()
{
EditorGUILayout.BeginVertical("box");
EditorGUILayout.LabelField("AreaId 选择", EditorStyles.boldLabel);
EditorGUILayout.BeginHorizontal();
areaIdInput = EditorGUILayout.IntField("AreaId", areaIdInput, GUILayout.Width(240));
if (GUILayout.Button("加载 AreaId", GUILayout.Width(120), GUILayout.Height(24)))
{
TrySelectArea(areaIdInput, true);
}
if (GUILayout.Button("重新输入", GUILayout.Width(100), GUILayout.Height(24)))
{
ShowAreaInputDialog();
}
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();
string previewText = availableAreaIds.Count <= 15
? string.Join(", ", availableAreaIds)
: string.Join(", ", availableAreaIds.Take(15)) + " ...";
EditorGUILayout.HelpBox($"可编辑 AreaId{previewText}", MessageType.None);
EditorGUILayout.EndVertical();
}
private void DrawAreaSummary()
{
List<int> missingSortIds = GetMissingSortIds();
int actualCount = currentAreaStepRows.Count;
string summary = $"当前 AreaId{selectedAreaId}\n期望步数{currentAreaExpectedStepCount}\n实际可编辑步数{actualCount}\n未保存修改{dirtyRowIndexes.Count} 行";
if (missingSortIds.Count > 0)
{
string missingText = string.Join(", ", missingSortIds.Take(10));
if (missingSortIds.Count > 10)
{
missingText += " ...";
}
EditorGUILayout.HelpBox(summary + $"\n\n⚠ 缺失步骤:{missingText}", MessageType.Warning);
return;
}
EditorGUILayout.HelpBox(summary, MessageType.Info);
}
private void DrawQuickActions()
{
using (new EditorGUI.DisabledScope(currentAreaStepRows.Count == 0 || currentAreaExpectedStepCount <= 0))
{
EditorGUILayout.BeginHorizontal();
GUI.backgroundColor = new Color(0.78f, 0.92f, 1f);
if (GUILayout.Button("快捷设置资源消耗", GUILayout.Width(180), GUILayout.Height(28)))
{
DecorateCostPlannerBatchCostWindow.ShowWindow(currentAreaExpectedStepCount, ApplyBatchCostSettings);
}
GUI.backgroundColor = new Color(1f, 0.9f, 0.65f);
if (GUILayout.Button("快捷设置步骤批次", GUILayout.Width(180), GUILayout.Height(28)))
{
DecorateCostPlannerBatchSkipWindow.ShowWindow(currentAreaExpectedStepCount, ApplyBatchBatchSettings);
}
GUI.backgroundColor = Color.white;
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();
}
GUI.backgroundColor = Color.white;
}
private void DrawStepTable()
{
EditorGUILayout.BeginVertical("box");
EditorGUILayout.LabelField("步骤配置", EditorStyles.boldLabel);
EditorGUILayout.Space(4);
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("SortId", EditorStyles.boldLabel, GUILayout.Width(70));
EditorGUILayout.LabelField("CostCount", EditorStyles.boldLabel, GUILayout.Width(120));
EditorGUILayout.LabelField("步骤批次", EditorStyles.boldLabel, GUILayout.Width(140));
EditorGUILayout.LabelField("批次映射", EditorStyles.boldLabel, GUILayout.Width(120));
EditorGUILayout.LabelField("Title", EditorStyles.boldLabel, GUILayout.Width(260));
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space(2);
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
foreach (DecorateCostExcelRow row in currentAreaStepRows.OrderBy(item => item.SortId))
{
DrawSingleStepRow(row);
}
EditorGUILayout.EndScrollView();
EditorGUILayout.EndVertical();
}
private void DrawSingleStepRow(DecorateCostExcelRow row)
{
EditorGUILayout.BeginHorizontal("box");
EditorGUILayout.LabelField(row.SortId.ToString(), GUILayout.Width(70));
EditorGUI.BeginChangeCheck();
int newCostCount = EditorGUILayout.IntField(row.CostCount, GUILayout.Width(120));
if (EditorGUI.EndChangeCheck())
{
row.CostCount = Mathf.Max(0, newCostCount);
MarkRowDirty(row);
}
EditorGUI.BeginChangeCheck();
int newBatchValue = EditorGUILayout.IntField(row.BatchValue, GUILayout.Width(140));
if (EditorGUI.EndChangeCheck())
{
row.BatchValue = Mathf.Max(0, newBatchValue);
MarkRowDirty(row);
}
EditorGUILayout.LabelField(GetBatchDisplayName(row.BatchValue), GUILayout.Width(120));
EditorGUILayout.LabelField(string.IsNullOrEmpty(row.Title) ? "-" : row.Title, GUILayout.Width(260));
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();
}
private void ApplyBatchCostSettings(int[] costs)
{
if (costs == null || costs.Length == 0)
{
return;
}
int updatedCount = 0;
List<int> missingSortIds = new List<int>();
for (int step = 1; step <= currentAreaExpectedStepCount; step++)
{
DecorateCostExcelRow row = currentAreaStepRows.FirstOrDefault(item => item.SortId == step);
if (row == null)
{
missingSortIds.Add(step);
continue;
}
int groupIndex = Mathf.Clamp((step - 1) / 5, 0, costs.Length - 1);
if (row.CostCount != costs[groupIndex])
{
row.CostCount = Mathf.Max(0, costs[groupIndex]);
MarkRowDirty(row);
updatedCount++;
}
}
ShowBatchApplyResult("资源消耗", updatedCount, missingSortIds);
}
private void ApplyBatchBatchSettings(int[] batches)
{
if (batches == null || batches.Length == 0)
{
return;
}
int updatedCount = 0;
List<int> missingSortIds = new List<int>();
for (int step = 1; step <= currentAreaExpectedStepCount; step++)
{
DecorateCostExcelRow row = currentAreaStepRows.FirstOrDefault(item => item.SortId == step);
if (row == null)
{
missingSortIds.Add(step);
continue;
}
int batchValue = step - 1 < batches.Length ? Mathf.Max(0, batches[step - 1]) : 0;
if (row.BatchValue != batchValue)
{
row.BatchValue = batchValue;
MarkRowDirty(row);
updatedCount++;
}
}
ShowBatchApplyResult("步骤批次", updatedCount, missingSortIds);
}
private void ShowBatchApplyResult(string label, int updatedCount, List<int> missingSortIds)
{
string message = $"已应用{label}快捷设置,更新 {updatedCount} 步。";
if (missingSortIds.Count > 0)
{
message += $"\n\n缺失步骤{string.Join(", ", missingSortIds)}";
}
EditorUtility.DisplayDialog("完成", message, "确定");
}
private void SaveDecorateCostExcel()
{
if (dirtyRowIndexes.Count == 0)
{
EditorUtility.DisplayDialog("提示", "当前没有需要保存的修改。", "确定");
return;
}
string excelPath = GetDocsConfigFilePath(DECORATE_COST_EXCEL_NAME);
if (!File.Exists(excelPath))
{
EditorUtility.DisplayDialog("错误", $"未找到文件:{excelPath}", "确定");
return;
}
try
{
using (ExcelPackage package = new ExcelPackage(new FileInfo(excelPath)))
{
ExcelWorksheet worksheet = package.Workbook.Worksheets[DECORATE_COST_SHEET_NAME];
if (worksheet == null)
{
EditorUtility.DisplayDialog("错误", $"未找到 Sheet{DECORATE_COST_SHEET_NAME}", "确定");
return;
}
foreach (int rowIndex in dirtyRowIndexes.OrderBy(index => index))
{
if (!rowIndexMap.TryGetValue(rowIndex, out DecorateCostExcelRow row))
{
continue;
}
worksheet.Cells[row.RowIndex, COL_COST_COUNT].Value = row.CostCount;
worksheet.Cells[row.RowIndex, COL_POS].Value = string.IsNullOrEmpty(row.Pos) ? null : row.Pos;
}
package.Save();
}
int savedCount = dirtyRowIndexes.Count;
dirtyRowIndexes.Clear();
AssetDatabase.Refresh();
EditorUtility.DisplayDialog("成功", $"已保存 {savedCount} 行修改到 {DECORATE_COST_EXCEL_NAME}。", "确定");
}
catch (Exception e)
{
EditorUtility.DisplayDialog("错误", $"保存失败:{e.Message}\n{e.StackTrace}", "确定");
}
}
private void ShowAreaInputDialog()
{
if (availableAreaIds == null || availableAreaIds.Count == 0)
{
return;
}
DecorateCostAreaInputWindow.ShowWindow(areaIdInput, TrySelectArea);
}
private bool TrySelectArea(int areaId)
{
return TrySelectArea(areaId, true);
}
private bool TrySelectArea(int areaId, bool showDialog)
{
if (areaId == 1)
{
if (showDialog)
{
EditorUtility.DisplayDialog("限制", "AreaId 1 为旧版特殊场景,不能在此工具中编辑。", "确定");
}
return false;
}
int expectedStepCount = GetExpectedStepCount(areaId);
if (expectedStepCount <= 0)
{
if (showDialog)
{
EditorUtility.DisplayDialog("错误", "请输入有效的 AreaId。AreaId=2-5 为 20 步AreaId>=6 为 25 步。", "确定");
}
return false;
}
bool hasArea = allRows.Any(row => row.AreaId == areaId);
if (!hasArea)
{
if (showDialog)
{
EditorUtility.DisplayDialog("未找到", $"DecorateCost 中不存在 AreaId={areaId} 的配置。", "确定");
}
return false;
}
selectedAreaId = areaId;
areaIdInput = areaId;
currentAreaExpectedStepCount = expectedStepCount;
currentAreaStepRows = allRows
.Where(row => row.AreaId == areaId && row.SortId != 0)
.OrderBy(row => row.SortId)
.ToList();
if (showDialog)
{
string message = $"已加载 AreaId={areaId}\n期望步数{currentAreaExpectedStepCount}\n可编辑步骤{currentAreaStepRows.Count}";
List<int> missingSortIds = GetMissingSortIds();
if (missingSortIds.Count > 0)
{
message += $"\n\n⚠ 缺失步骤:{string.Join(", ", missingSortIds)}";
}
EditorUtility.DisplayDialog("完成", message, "确定");
}
Repaint();
return true;
}
private List<int> GetMissingSortIds()
{
if (currentAreaExpectedStepCount <= 0)
{
return new List<int>();
}
HashSet<int> existingIds = new HashSet<int>(currentAreaStepRows.Select(row => row.SortId));
List<int> missingIds = new List<int>();
for (int sortId = 1; sortId <= currentAreaExpectedStepCount; sortId++)
{
if (!existingIds.Contains(sortId))
{
missingIds.Add(sortId);
}
}
return missingIds;
}
private int GetDefaultAreaId()
{
return availableAreaIds.FirstOrDefault();
}
private int GetExpectedStepCount(int areaId)
{
if (areaId >= 2 && areaId <= 5)
{
return 20;
}
if (areaId >= 6)
{
return 25;
}
return 0;
}
private void MarkRowDirty(DecorateCostExcelRow row)
{
dirtyRowIndexes.Add(row.RowIndex);
}
private static string GetBatchDisplayName(int batchValue)
{
if (batchValue <= 0)
{
return "空";
}
if (batchValue < BATCH_NAMES.Length)
{
return BATCH_NAMES[batchValue];
}
return $"第{batchValue}批";
}
private static int ParseBatchValue(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
return 0;
}
string trimmedValue = value.Trim();
if (int.TryParse(trimmedValue, out int numericValue))
{
return Mathf.Max(0, numericValue);
}
for (int index = 1; index < BATCH_NAMES.Length; index++)
{
if (string.Equals(BATCH_NAMES[index], trimmedValue, StringComparison.OrdinalIgnoreCase))
{
return index;
}
}
string normalizedValue = trimmedValue.Replace("-", string.Empty).Replace(" ", string.Empty).ToLowerInvariant();
for (int index = 1; index < BATCH_NAMES.Length; index++)
{
string normalizedBatchName = BATCH_NAMES[index].Replace("-", string.Empty).Replace(" ", string.Empty).ToLowerInvariant();
if (normalizedBatchName == normalizedValue)
{
return index;
}
}
switch (normalizedValue)
{
case "fourth": return 4;
case "fifth": return 5;
case "sixth": return 6;
case "seventh": return 7;
case "eighth": return 8;
case "ninth": return 9;
case "tenth": return 10;
case "eleventh": return 11;
case "twelfth": return 12;
case "thirteenth": return 13;
case "fourteenth": return 14;
case "fifteenth": return 15;
case "sixteenth": return 16;
case "seventeenth": return 17;
case "eighteenth": return 18;
case "nineteenth": return 19;
case "twentieth": return 20;
case "twentyfirst": return 21;
case "twentysecond": return 22;
case "twentythird": return 23;
case "twentyfourth": return 24;
case "twentyfifth": return 25;
case "twentysixth": return 26;
case "twentyseventh": return 27;
case "twentyeighth": return 28;
case "twentyninth": return 29;
case "thirtieth": return 30;
case "thirtyfirst": return 31;
case "thirtysecond": return 32;
case "thirtythird": return 33;
case "thirtyfourth": return 34;
case "thirtyfifth": return 35;
case "thirtysixth": return 36;
case "thirtyseventh": return 37;
case "thirtyeighth": return 38;
case "thirtyninth": return 39;
case "fortieth": return 40;
case "fortyfirst": return 41;
default: return 0;
}
}
private static string FormatBatchValue(int batchValue)
{
if (batchValue <= 0)
{
return string.Empty;
}
if (batchValue < BATCH_NAMES.Length)
{
return BATCH_NAMES[batchValue];
}
return batchValue.ToString();
}
private sealed class DecorateCostExcelRow
{
private readonly string[] fields;
public DecorateCostExcelRow(int rowIndex, string[] fields)
{
RowIndex = rowIndex;
this.fields = fields ?? new string[TOTAL_COL_COUNT];
}
public int RowIndex { get; }
public int AreaId => ParseInt(fields[COL_AREA_ID - 1]);
public int SortId => ParseInt(fields[COL_SORT_ID - 1]);
public string Title => fields[4];
public int CostCount
{
get => ParseInt(fields[COL_COST_COUNT - 1]);
set => fields[COL_COST_COUNT - 1] = value.ToString();
}
public string Pos
{
get => fields[COL_POS - 1] ?? string.Empty;
set => fields[COL_POS - 1] = value ?? string.Empty;
}
public int BatchValue
{
get => ParseBatchValue(Pos);
set => Pos = FormatBatchValue(value);
}
private static int ParseInt(string value)
{
return int.TryParse(value, out int result) ? result : 0;
}
}
}
/// <summary>
/// AreaId 输入窗口
/// </summary>
public class DecorateCostAreaInputWindow : EditorWindow
{
private Func<int, bool> onConfirm;
private string areaIdText = string.Empty;
public static void ShowWindow(int defaultAreaId, Func<int, bool> confirmCallback)
{
DecorateCostAreaInputWindow window = CreateInstance<DecorateCostAreaInputWindow>();
window.titleContent = new GUIContent("输入 AreaId");
window.minSize = new Vector2(320, 120);
window.maxSize = new Vector2(320, 120);
window.areaIdText = defaultAreaId > 0 ? defaultAreaId.ToString() : string.Empty;
window.onConfirm = confirmCallback;
window.ShowUtility();
}
private void OnGUI()
{
EditorGUILayout.Space(10);
EditorGUILayout.LabelField("请输入要编辑的 AreaId", EditorStyles.boldLabel);
EditorGUILayout.HelpBox("AreaId=1 不允许编辑AreaId=2-5 为 20 步AreaId>=6 为 25 步。", MessageType.Info);
GUI.SetNextControlName("AreaIdField");
areaIdText = EditorGUILayout.TextField("AreaId", areaIdText);
EditorGUILayout.Space(10);
EditorGUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button("确定", GUILayout.Width(90), GUILayout.Height(24)))
{
Confirm();
}
if (GUILayout.Button("取消", GUILayout.Width(90), GUILayout.Height(24)))
{
Close();
}
EditorGUILayout.EndHorizontal();
if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Return)
{
Confirm();
Event.current.Use();
}
}
private void OnFocus()
{
EditorGUI.FocusTextInControl("AreaIdField");
}
private void Confirm()
{
if (!int.TryParse(areaIdText, out int areaId))
{
EditorUtility.DisplayDialog("错误", "请输入有效的整数 AreaId。", "确定");
return;
}
if (onConfirm == null || onConfirm.Invoke(areaId))
{
Close();
}
}
}
/// <summary>
/// DecorateCost 独立的批量设置资源消耗弹窗。
/// </summary>
public class DecorateCostPlannerBatchCostWindow : EditorWindow
{
private int groupCount = 5;
private int stepCount = 25;
private IntegerField[] costFields = Array.Empty<IntegerField>();
private Action<int[]> onConfirm;
public static void ShowWindow(int stepCount, Action<int[]> confirmCallback)
{
DecorateCostPlannerBatchCostWindow window = CreateInstance<DecorateCostPlannerBatchCostWindow>();
window.titleContent = new GUIContent("批量设置资源消耗");
window.minSize = new Vector2(300, 250);
window.stepCount = Mathf.Max(1, stepCount);
window.groupCount = Mathf.CeilToInt(window.stepCount / 5f);
window.costFields = new IntegerField[window.groupCount];
window.onConfirm = confirmCallback;
window.ShowUtility();
}
private void CreateGUI()
{
VisualElement root = rootVisualElement;
root.Clear();
root.style.paddingTop = 10;
root.style.paddingBottom = 10;
root.style.paddingLeft = 10;
root.style.paddingRight = 10;
Label title = new Label($"输入{groupCount}组资源消耗数值\n每5个步骤使用同一数值当前共{stepCount}步)");
title.style.fontSize = 14;
title.style.marginBottom = 10;
title.style.unityTextAlign = TextAnchor.MiddleCenter;
root.Add(title);
for (int i = 0; i < groupCount; i++)
{
int startStep = i * 5 + 1;
int endStep = Mathf.Min((i + 1) * 5, stepCount);
IntegerField field = new IntegerField($"第{startStep}-{endStep}步:");
field.value = 0;
field.style.marginBottom = 5;
costFields[i] = field;
root.Add(field);
}
VisualElement buttonRow = new VisualElement();
buttonRow.style.flexDirection = FlexDirection.Row;
buttonRow.style.marginTop = 15;
UnityEngine.UIElements.Button confirmBtn = new UnityEngine.UIElements.Button(OnConfirmClicked) { text = "确定" };
confirmBtn.style.flexGrow = 1;
confirmBtn.style.marginRight = 5;
buttonRow.Add(confirmBtn);
UnityEngine.UIElements.Button cancelBtn = new UnityEngine.UIElements.Button(Close) { text = "取消" };
cancelBtn.style.flexGrow = 1;
buttonRow.Add(cancelBtn);
root.Add(buttonRow);
}
private void OnConfirmClicked()
{
int[] costs = new int[groupCount];
for (int i = 0; i < groupCount; i++)
{
costs[i] = costFields[i].value;
}
onConfirm?.Invoke(costs);
Close();
}
}
/// <summary>
/// DecorateCost 独立的批量设置步骤批次弹窗。
/// </summary>
public class DecorateCostPlannerBatchSkipWindow : EditorWindow
{
private int stepCount = 25;
private IntegerField[] skipFields = Array.Empty<IntegerField>();
private ScrollView scrollView;
private Action<int[]> onConfirm;
public static void ShowWindow(int stepCount, Action<int[]> confirmCallback)
{
DecorateCostPlannerBatchSkipWindow window = CreateInstance<DecorateCostPlannerBatchSkipWindow>();
window.titleContent = new GUIContent("批量设置批次");
window.minSize = new Vector2(350, 500);
window.stepCount = Mathf.Max(1, stepCount);
window.skipFields = new IntegerField[window.stepCount];
window.onConfirm = confirmCallback;
window.ShowUtility();
}
private void CreateGUI()
{
VisualElement root = rootVisualElement;
root.Clear();
root.style.paddingTop = 10;
root.style.paddingBottom = 10;
root.style.paddingLeft = 10;
root.style.paddingRight = 10;
Label title = new Label($"输入{stepCount}个数字设置批次\n0=空 1=first 2=second 3=third...");
title.style.fontSize = 14;
title.style.marginBottom = 10;
title.style.unityTextAlign = TextAnchor.MiddleCenter;
root.Add(title);
scrollView = new ScrollView();
scrollView.style.flexGrow = 1;
for (int i = 0; i < stepCount; i++)
{
IntegerField field = new IntegerField($"步骤{i + 1}:");
field.value = 0;
field.style.marginBottom = 3;
skipFields[i] = field;
scrollView.Add(field);
}
root.Add(scrollView);
VisualElement buttonRow = new VisualElement();
buttonRow.style.flexDirection = FlexDirection.Row;
buttonRow.style.marginTop = 10;
UnityEngine.UIElements.Button confirmBtn = new UnityEngine.UIElements.Button(OnConfirmClicked) { text = "确定" };
confirmBtn.style.flexGrow = 1;
confirmBtn.style.marginRight = 5;
buttonRow.Add(confirmBtn);
UnityEngine.UIElements.Button cancelBtn = new UnityEngine.UIElements.Button(Close) { text = "取消" };
cancelBtn.style.flexGrow = 1;
buttonRow.Add(cancelBtn);
root.Add(buttonRow);
}
private void OnConfirmClicked()
{
int[] skips = new int[stepCount];
for (int i = 0; i < stepCount; i++)
{
skips[i] = skipFields[i].value;
}
onConfirm?.Invoke(skips);
Close();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a80667981aa125e489cabc41b4db38c0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: