fix:1、添加项目。2、基本箭头生成
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace EditorTools
|
||||
{
|
||||
/// <summary>
|
||||
/// 编辑器内单个箭头数据
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class EditorArrowData
|
||||
{
|
||||
public int arrowId;
|
||||
public int startPoint;
|
||||
public int endPoint;
|
||||
public string colorHex = "#FFFFFF";
|
||||
public List<string> pathDirs = new List<string>();
|
||||
|
||||
// 路径点位序列 (ID列表)
|
||||
public List<int> pointIds = new List<int>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关卡总配置(编辑器用)
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class EditorLevelData
|
||||
{
|
||||
public int levelId = 1001;
|
||||
public string levelName = "可视化编辑关卡";
|
||||
public int gridRows = 10;
|
||||
public int gridCols = 10;
|
||||
public int pointSpacing = 60;
|
||||
public List<EditorArrowData> arrows = new List<EditorArrowData>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a26e6efd7d7cca34ab027117de8c8caf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,285 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c9307857b7d4263a329a46d2dda9a31
|
||||
timeCreated: 1781254588
|
||||
@@ -0,0 +1,106 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace EditorTools
|
||||
{
|
||||
// 导出JSON 根实体
|
||||
[System.Serializable]
|
||||
public class ExportLevelRoot
|
||||
{
|
||||
public int levelId;
|
||||
public string levelName;
|
||||
public int gridRows;
|
||||
public int gridCols;
|
||||
public int pointSpacing;
|
||||
public List<ExportArrowItem> arrows;
|
||||
}
|
||||
|
||||
// 导出JSON 单条箭头实体
|
||||
[System.Serializable]
|
||||
public class ExportArrowItem
|
||||
{
|
||||
public int id;
|
||||
public int startPoint;
|
||||
public int endPoint;
|
||||
public string color;
|
||||
public List<string> path;
|
||||
}
|
||||
|
||||
public static class LevelJsonExporter
|
||||
{
|
||||
/// <summary>
|
||||
/// 行列转点位ID(和游戏代码完全一致)
|
||||
/// </summary>
|
||||
public static int RowColToPointId(int row, int col, int totalCol)
|
||||
{
|
||||
return row * totalCol + col;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 点位ID转行列(和游戏代码完全一致)
|
||||
/// </summary>
|
||||
public static void PointIdToRowCol(int pointId, int totalCol, out int row, out int col)
|
||||
{
|
||||
row = pointId / totalCol;
|
||||
col = pointId % totalCol;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据前后两个点位,计算移动方向
|
||||
/// </summary>
|
||||
public static string GetDirection(int fromId, int toId, int totalCol)
|
||||
{
|
||||
PointIdToRowCol(fromId, totalCol, out int fRow, out int fCol);
|
||||
PointIdToRowCol(toId, totalCol, out int tRow, out int tCol);
|
||||
|
||||
if (tRow < fRow) return "up";
|
||||
if (tRow > fRow) return "down";
|
||||
if (tCol < fCol) return "left";
|
||||
if (tCol > fCol) return "right";
|
||||
return "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成最终JSON字符串(纯实体类序列化,全版本兼容)
|
||||
/// </summary>
|
||||
public static string BuildLevelJson(EditorLevelData levelData)
|
||||
{
|
||||
ExportLevelRoot root = new ExportLevelRoot();
|
||||
root.levelId = levelData.levelId;
|
||||
root.levelName = levelData.levelName;
|
||||
root.gridRows = levelData.gridRows;
|
||||
root.gridCols = levelData.gridCols;
|
||||
root.pointSpacing = levelData.pointSpacing;
|
||||
|
||||
root.arrows = new List<ExportArrowItem>();
|
||||
foreach (var editorArr in levelData.arrows)
|
||||
{
|
||||
ExportArrowItem item = new ExportArrowItem();
|
||||
item.id = editorArr.arrowId;
|
||||
item.startPoint = editorArr.startPoint;
|
||||
item.endPoint = editorArr.endPoint;
|
||||
item.color = editorArr.colorHex;
|
||||
item.path = new List<string>(editorArr.pathDirs);
|
||||
root.arrows.Add(item);
|
||||
}
|
||||
|
||||
return JsonUtility.ToJson(root, prettyPrint: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存JSON到StreamingAssets
|
||||
/// </summary>
|
||||
public static bool SaveToStreamingAssets(string json, string fileName = "level_1001.json")
|
||||
{
|
||||
string folder = Application.streamingAssetsPath;
|
||||
if (!Directory.Exists(folder))
|
||||
Directory.CreateDirectory(folder);
|
||||
|
||||
string fullPath = Path.Combine(folder, fileName);
|
||||
File.WriteAllText(fullPath, json);
|
||||
Debug.Log($"[导出成功] {fullPath}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d01c5dd341d401bac259daf47388bee
|
||||
timeCreated: 1781254572
|
||||
Reference in New Issue
Block a user