using System.Collections.Generic; using UnityEditor; using UnityEngine; namespace EditorTools { public class GridPathEditorWindow : EditorWindow { private EditorLevelData _levelData = new EditorLevelData(); // 绘制区域参数 private Vector2 _scrollPos; private const float CellSize = 24f; private const float DrawOffsetX = 20f; private const float DrawOffsetY = 20f; // 当前正在编辑的箭头 private int _curEditArrowIndex = -1; private List _tempPathPoints = new List(); // 颜色预设 private readonly Color _gridLineColor = new Color(0.4f, 0.4f, 0.4f); private readonly Color _startCellColor = new Color(0.2f, 0.8f, 0.2f); private readonly Color _pathCellColor = new Color(0.2f, 0.5f, 1f); private readonly Color _endCellColor = new Color(1f, 0.4f, 0.2f); [MenuItem("工具/网格路径配置编辑器")] public static void OpenWindow() { var win = GetWindow("网格路径编辑器"); win.minSize = new Vector2(600, 500); win.Show(); } private void OnGUI() { EditorGUILayout.BeginVertical("Box"); DrawLevelSetting(); EditorGUILayout.Space(); DrawArrowList(); EditorGUILayout.Space(); DrawGridCanvas(); EditorGUILayout.EndVertical(); } #region 1. 关卡基础设置 private void DrawLevelSetting() { GUILayout.Label("【关卡基础设置】", EditorStyles.boldLabel); _levelData.levelId = EditorGUILayout.IntField("关卡ID", _levelData.levelId); _levelData.levelName = EditorGUILayout.TextField("关卡名称", _levelData.levelName); EditorGUILayout.BeginHorizontal(); _levelData.gridRows = EditorGUILayout.IntField("网格行数", _levelData.gridRows); _levelData.gridCols = EditorGUILayout.IntField("网格列数", _levelData.gridCols); EditorGUILayout.EndHorizontal(); _levelData.pointSpacing = EditorGUILayout.IntField("点位间距(px)", _levelData.pointSpacing); EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("➕ 新增箭头")) { AddNewArrow(); } if (GUILayout.Button("💾 导出JSON")) { ExportJson(); } if (GUILayout.Button("🗑️ 清空当前路径")) { _tempPathPoints.Clear(); _curEditArrowIndex = -1; } EditorGUILayout.EndHorizontal(); } #endregion #region 2. 箭头列表 private void DrawArrowList() { GUILayout.Label("【箭头列表(选中后绘制路径)】", EditorStyles.boldLabel); _scrollPos = EditorGUILayout.BeginScrollView(_scrollPos, GUILayout.Height(120)); for (int i = 0; i < _levelData.arrows.Count; i++) { var arrow = _levelData.arrows[i]; EditorGUILayout.BeginHorizontal("Box"); if (GUILayout.Toggle(_curEditArrowIndex == i, $"ID:{arrow.arrowId}", GUILayout.Width(60))) { SelectArrow(i); } arrow.colorHex = EditorGUILayout.TextField(arrow.colorHex, GUILayout.Width(80)); EditorGUILayout.LabelField($"起点:{arrow.startPoint} 终点:{arrow.endPoint}", GUILayout.Width(160)); if (GUILayout.Button("删除", GUILayout.Width(50))) { _levelData.arrows.RemoveAt(i); if (_curEditArrowIndex >= _levelData.arrows.Count) _curEditArrowIndex = -1; break; } EditorGUILayout.EndHorizontal(); } EditorGUILayout.EndScrollView(); } private void AddNewArrow() { int newId = _levelData.arrows.Count + 1; _levelData.arrows.Add(new EditorArrowData { arrowId = newId, colorHex = "#FFFFFF" }); } private void SelectArrow(int idx) { _curEditArrowIndex = idx; _tempPathPoints.Clear(); var arr = _levelData.arrows[idx]; _tempPathPoints.AddRange(arr.pointIds); } #endregion #region 3. 网格画布 + 点击选点 private void DrawGridCanvas() { GUILayout.Label("【网格画布 - 点击格子绘制路径】", EditorStyles.boldLabel); int rows = _levelData.gridRows; int cols = _levelData.gridCols; Rect totalRect = EditorGUILayout.GetControlRect(false, (rows + 1) * CellSize); float startX = totalRect.x + DrawOffsetX; float startY = totalRect.y + DrawOffsetY; // 绘制网格 + 监听点击 for (int r = 0; r < rows; r++) { for (int c = 0; c < cols; c++) { int pointId = LevelJsonExporter.RowColToPointId(r, c, cols); Rect cellRect = new Rect( startX + c * CellSize, startY + r * CellSize, CellSize - 2, CellSize - 2 ); // 格子背景色 Color cellColor = Color.white; if (_tempPathPoints.Count > 0) { if (_tempPathPoints[0] == pointId) cellColor = _startCellColor; else if (_tempPathPoints[_tempPathPoints.Count - 1] == pointId) cellColor = _endCellColor; else if (_tempPathPoints.Contains(pointId)) cellColor = _pathCellColor; } // 绘制格子底色 EditorGUI.DrawRect(cellRect, cellColor); // ===== 纯GUI绘制边框,全版本通用 ===== Color oldColor = GUI.color; GUI.color = _gridLineColor; // 上边框 DrawLineGUI(new Vector2(cellRect.xMin, cellRect.yMin), new Vector2(cellRect.xMax, cellRect.yMin)); // 右边框 DrawLineGUI(new Vector2(cellRect.xMax, cellRect.yMin), new Vector2(cellRect.xMax, cellRect.yMax)); // 下边框 DrawLineGUI(new Vector2(cellRect.xMax, cellRect.yMax), new Vector2(cellRect.xMin, cellRect.yMax)); // 左边框 DrawLineGUI(new Vector2(cellRect.xMin, cellRect.yMax), new Vector2(cellRect.xMin, cellRect.yMin)); GUI.color = oldColor; // 点位ID文字 GUI.color = Color.black; GUI.Label(cellRect, pointId.ToString(), EditorStyles.miniLabel); GUI.color = Color.white; // 鼠标点击 if (Event.current.type == EventType.MouseDown && cellRect.Contains(Event.current.mousePosition)) { OnCellClick(pointId); Event.current.Use(); } } } } // 纯GUI线条绘制(兼容所有Unity版本) private void DrawLineGUI(Vector2 p1, Vector2 p2) { Handles.color = GUI.color; Handles.DrawAAPolyLine(1, p1, p2); } private void OnCellClick(int clickPointId) { // 必须先选中一个箭头才能画路径 if (_curEditArrowIndex < 0 || _curEditArrowIndex >= _levelData.arrows.Count) { EditorUtility.DisplayDialog("提示", "请先在上方选中一个箭头", "确定"); return; } // 1. 空路径 = 设为起点 // 2. 已有点位 = 追加下一个路径点(只能相邻移动) if (_tempPathPoints.Count == 0) { _tempPathPoints.Add(clickPointId); } else { int lastId = _tempPathPoints[_tempPathPoints.Count - 1]; if (IsAdjacent(lastId, clickPointId, _levelData.gridCols)) { _tempPathPoints.Add(clickPointId); } else { EditorUtility.DisplayDialog("提示", "只能点击相邻格子!", "确定"); } } // 实时同步到当前箭头数据 SyncTempPathToArrow(); } /// 判断两个点位是否上下左右相邻 private bool IsAdjacent(int idA, int idB, int totalCol) { LevelJsonExporter.PointIdToRowCol(idA, totalCol, out int r1, out int c1); LevelJsonExporter.PointIdToRowCol(idB, totalCol, out int r2, out int c2); int dr = Mathf.Abs(r1 - r2); int dc = Mathf.Abs(c1 - c2); return (dr == 1 && dc == 0) || (dr == 0 && dc == 1); } /// 临时路径 → 箭头正式数据(自动生成direction、start/end) private void SyncTempPathToArrow() { var arrow = _levelData.arrows[_curEditArrowIndex]; arrow.pointIds.Clear(); arrow.pathDirs.Clear(); arrow.pointIds.AddRange(_tempPathPoints); if (_tempPathPoints.Count == 0) return; arrow.startPoint = _tempPathPoints[0]; arrow.endPoint = _tempPathPoints[_tempPathPoints.Count - 1]; // 逐段生成方向列表 for (int i = 0; i < _tempPathPoints.Count - 1; i++) { string dir = LevelJsonExporter.GetDirection(_tempPathPoints[i], _tempPathPoints[i + 1], _levelData.gridCols); if (!string.IsNullOrEmpty(dir)) arrow.pathDirs.Add(dir); } } #endregion #region 4. 导出JSON private void ExportJson() { if (_levelData.arrows.Count == 0) { EditorUtility.DisplayDialog("提示", "暂无箭头数据", "确定"); return; } string json = LevelJsonExporter.BuildLevelJson(_levelData); LevelJsonExporter.SaveToStreamingAssets(json); EditorUtility.DisplayDialog("导出完成", "JSON 已生成到 StreamingAssets/level_1001.json", "确定"); } #endregion } }