285 lines
11 KiB
C#
285 lines
11 KiB
C#
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<int> _tempPathPoints = new List<int>();
|
||
|
||
// 颜色预设
|
||
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<GridPathEditorWindow>("网格路径编辑器");
|
||
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();
|
||
}
|
||
|
||
/// <summary>判断两个点位是否上下左右相邻</summary>
|
||
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);
|
||
}
|
||
|
||
/// <summary>临时路径 → 箭头正式数据(自动生成direction、start/end)</summary>
|
||
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
|
||
}
|
||
} |