Files
ArrowBeatTap-Gp/Assets/Editor/GridPathEditorWindow.cs
T

285 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
}
}