using UnityEditor; using UnityEngine; using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; namespace ChillConnect.Editor { /// /// 第三方关卡配置批量转换工具 /// 输入:文件夹内所有第三方单关JSON /// 输出:对应转换后的我方格式单关JSON /// public class LevelBatchConverter : EditorWindow { #region 数据结构定义 // 第三方单关结构(只声明需要的字段,多余自动忽略) [System.Serializable] private class ThirdPartyLevel { public Vector2Int size; public string name; public List arrows; } [System.Serializable] private class ThirdPartyArrow { public List nodes; public int color; } // 我方单关结构(和运行时对齐) [System.Serializable] public class ArrowConfig { public int id; public int startPoint; public List path = new List(); } [System.Serializable] public class LevelConfig { public int levelId; public string levelName; public int gridRows; public int gridCols; public int pointSpacing = 60; public List arrows = new List(); } #endregion private string _inputFolder = ""; private string _outputFolder = ""; private int _pointSpacing = 60; private Vector2 _scrollPos; private List _logList = new List(); [MenuItem("Window/Arrow Game/批量关卡转换工具")] public static void ShowWindow() { var window = GetWindow("批量关卡转换"); window.minSize = new Vector2(500, 400); } private void OnGUI() { EditorGUILayout.Space(10); // 输入文件夹 EditorGUILayout.LabelField("输入文件夹(第三方单关JSON)", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); _inputFolder = EditorGUILayout.TextField(_inputFolder); if (GUILayout.Button("选择", GUILayout.Width(60))) { string path = EditorUtility.OpenFolderPanel("选择输入文件夹", Application.dataPath, ""); if (!string.IsNullOrEmpty(path)) _inputFolder = path; } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(8); // 输出文件夹 EditorGUILayout.LabelField("输出文件夹(转换后JSON)", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); _outputFolder = EditorGUILayout.TextField(_outputFolder); if (GUILayout.Button("选择", GUILayout.Width(60))) { string path = EditorUtility.OpenFolderPanel("选择输出文件夹", Application.dataPath, ""); if (!string.IsNullOrEmpty(path)) _outputFolder = path; } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(8); // 基础配置 _pointSpacing = EditorGUILayout.IntField("默认点间距", _pointSpacing); EditorGUILayout.Space(10); // 转换按钮 if (GUILayout.Button("开始批量转换", GUILayout.Height(30))) { BatchConvert(); } EditorGUILayout.Space(10); // 日志区域 EditorGUILayout.LabelField("转换日志", EditorStyles.boldLabel); _scrollPos = EditorGUILayout.BeginScrollView(_scrollPos, GUILayout.ExpandHeight(true)); foreach (string log in _logList) { EditorGUILayout.LabelField(log); } EditorGUILayout.EndScrollView(); } /// /// 批量转换核心逻辑 /// private void BatchConvert() { _logList.Clear(); if (string.IsNullOrEmpty(_inputFolder) || !Directory.Exists(_inputFolder)) { _logList.Add("❌ 输入文件夹不存在"); return; } if (string.IsNullOrEmpty(_outputFolder)) { _logList.Add("❌ 请选择输出文件夹"); return; } // 创建输出目录 if (!Directory.Exists(_outputFolder)) { Directory.CreateDirectory(_outputFolder); } // 获取所有json文件 string[] files = Directory.GetFiles(_inputFolder, "*.json", SearchOption.TopDirectoryOnly); if (files.Length == 0) { _logList.Add("⚠️ 输入文件夹内未找到JSON文件"); return; } _logList.Add($"找到 {files.Length} 个JSON文件,开始转换..."); int successCount = 0; int failCount = 0; for (int i = 0; i < files.Length; i++) { string filePath = files[i]; string fileName = Path.GetFileNameWithoutExtension(filePath); try { // 1. 读取并解析第三方配置 string json = File.ReadAllText(filePath); ThirdPartyLevel thirdLevel = JsonUtility.FromJson(json); if (thirdLevel == null || thirdLevel.arrows == null) { _logList.Add($"❌ {fileName}:解析失败,格式不匹配"); failCount++; continue; } // 2. 转换为我方格式 LevelConfig level = ConvertLevel(thirdLevel, fileName, i + 1); // 3. 导出到输出文件夹 string outJson = JsonUtility.ToJson(level, true); string outPath = Path.Combine(_outputFolder, $"{fileName}.json"); File.WriteAllText(outPath, outJson); _logList.Add($"✅ {fileName}:转换成功 | {level.gridCols}×{level.gridRows} | {level.arrows.Count}个箭头"); successCount++; } catch (System.Exception e) { _logList.Add($"❌ {fileName}:转换异常 - {e.Message}"); failCount++; } } _logList.Add(""); _logList.Add($"===== 转换完成 ====="); _logList.Add($"成功:{successCount} 个"); _logList.Add($"失败:{failCount} 个"); _logList.Add($"输出路径:{_outputFolder}"); EditorUtility.DisplayDialog("批量转换完成", $"成功:{successCount}\n失败:{failCount}\n输出路径:{_outputFolder}", "确定"); AssetDatabase.Refresh(); } /// /// 单个关卡转换逻辑(和之前编辑器内转换完全一致) /// private LevelConfig ConvertLevel(ThirdPartyLevel thirdLevel, string fileName, int index) { LevelConfig level = new LevelConfig { levelId = index, levelName = string.IsNullOrEmpty(thirdLevel.name) ? fileName : thirdLevel.name, gridCols = thirdLevel.size.x, gridRows = thirdLevel.size.y, pointSpacing = _pointSpacing, arrows = new List() }; for (int i = 0; i < thirdLevel.arrows.Count; i++) { var thirdArrow = thirdLevel.arrows[i]; if (thirdArrow.nodes == null || thirdArrow.nodes.Count == 0) continue; ArrowConfig arrow = new ArrowConfig { id = i + 1, path = new List() }; // 起点转换:(x,y) → 点ID = y * 列数 + x Vector2Int startNode = thirdArrow.nodes[0]; arrow.startPoint = startNode.y * level.gridCols + startNode.x; // 路径转换:相邻节点计算方向 for (int j = 1; j < thirdArrow.nodes.Count; j++) { Vector2Int prev = thirdArrow.nodes[j - 1]; Vector2Int cur = thirdArrow.nodes[j]; int dx = cur.x - prev.x; int dy = cur.y - prev.y; if (dx == 1) arrow.path.Add("right"); else if (dx == -1) arrow.path.Add("left"); else if (dy == 1) arrow.path.Add("down"); else if (dy == -1) arrow.path.Add("up"); } level.arrows.Add(arrow); } return level; } } }