Skip to content

Instantly share code, notes, and snippets.

@YN-Studio
Created October 14, 2023 03:10
Show Gist options
  • Save YN-Studio/e8592708130681db053a3f74659443f1 to your computer and use it in GitHub Desktop.
Save YN-Studio/e8592708130681db053a3f74659443f1 to your computer and use it in GitHub Desktop.
基于Odin Inspector的Unity2D测量工具。Unity2D measure tool using Odin Inspector
using System.Collections.Generic;
using Sirenix.OdinInspector;
using Sirenix.OdinInspector.Editor;
using UnityEditor;
using UnityEngine;
/// <summary>
/// 地编中使用的测量工具(2D)
/// </summary>
public class MeasureToolEditor : OdinEditorWindow
{
#if UNITY_EDITOR
private bool startMeasure;
[BoxGroup("测量状态")]
[HideIf("@startMeasure")]
[PropertyOrder(-1)]
[Button("开始测量", ButtonSizes.Large), GUIColor(0, 1, 0)]
public void StartMeasure()
{
startMeasure = true;
}
[BoxGroup("测量状态")]
[HideIf("@!startMeasure")]
[PropertyOrder(-1)]
[Button("停止测量", ButtonSizes.Large), GUIColor(1, 0, 0)]
public void StopMeasure()
{
startMeasure = false;
measuring = false;
}
[BoxGroup("测量状态")]
[LabelWidth(150)]
public bool snap = true;
[BoxGroup("测量状态")]
[ShowIf("@snap")]
[LabelWidth(150)]
public float snapDistance = 0.25f;
[BoxGroup("显示具体的数值")]
[LabelText("显示坐标")]
[LabelWidth(150)]
public bool showCoordinate;
[BoxGroup("显示具体的数值")]
[LabelText("显示距离")]
[LabelWidth(150)]
public bool showDis;
//[BoxGroup("显示具体的数值")]
[Button("增加新list", ButtonSizes.Large), GUIColor(0.3f, 0.8f, 0.8f)]
[ButtonGroup("显示具体的数值/")]
public void AddListButton()
{
AddNewList();
}
[Button("清除所有List", ButtonSizes.Large), GUIColor(1, 0, 0)]
[ButtonGroup("显示具体的数值/")]
public void CleanAllList()
{
measurePointList.Clear();
closestList = 0;
}
[BoxGroup("UI参数")]
[LabelWidth(150)]
public float unfocusLineWidth = 1f;
[BoxGroup("UI参数")]
[LabelWidth(150)]
public float focusLineWidth = 2f;
[BoxGroup("UI参数")]
[LabelWidth(150)]
public int fontSize = 15;
private Color[] colorArray;
private bool measuring;
private Vector3 pos;
private int closestList;
private int currentAddList;
public List<List<Vector3>> measurePointList;
private Vector3 closestPoint;
private float rightClickTimer;
[Tooltip("Scene View摄像机的Z轴坐标")]
private float distanceToSceneCamera;
#region 系统
[MenuItem("工具/测量工具 %m")]
private static void OpenWindow()
{
GetWindow<MeasureToolEditor>("测量工具").Show();
}
protected override void OnEnable()
{
SceneView.duringSceneGui -= OnSceneGUI;
SceneView.duringSceneGui += OnSceneGUI;
if (measurePointList == null)
{
measurePointList = new List<List<Vector3>>();
measurePointList.Add(new List<Vector3>());
}
foreach (var colorPalette in ColorPaletteManager.Instance.ColorPalettes)
{
if (colorPalette.Name == "Measure Tool")
{
colorArray = colorPalette.Colors.ToArray();
}
}
closestList = 0;
}
protected override void OnDestroy()
{
SceneView.duringSceneGui -= OnSceneGUI;
measuring = false;
}
private void OnSceneGUI(SceneView sceneView)
{
if (sceneAssetData != null)
{
if (sceneAssetData.measurePointsList != null)
{
measurePointList = sceneAssetData.measurePointsList;
}
}
if(startMeasure)
{
Event currentEvent = Event.current;
pos = HandleUtility.GUIPointToWorldRay(currentEvent.mousePosition).origin;
pos.z = 0;
distanceToSceneCamera = SceneView.currentDrawingSceneView.camera.transform.position.z;
if (snap)
{
pos.x = snapDistance * Mathf.Round(pos.x / snapDistance);
pos.y = snapDistance * Mathf.Round(pos.y / snapDistance);
}
DebugExtension.DebugCircle(pos, Vector3.forward, Color.green, 0.1f);
GetClosestPoint(out closestPoint, out closestList);
measuring = true;
}
if (measuring)
{
AddMeasurePoint();
RemovePoint();
}
if (measurePointList != null && measurePointList.Count > 0 && measurePointList[closestList] != null)
{
for (int i = 0; i < measurePointList.Count; i++)
{
DrawMeasurePoint(measurePointList[i], colorArray[i < colorArray.Length ? i : 0]);
DrawLineBetweenPoints(measurePointList[i], colorArray[i < colorArray.Length ? i : 0], (closestList == i && startMeasure) ? focusLineWidth : unfocusLineWidth);
}
}
}
private void AddMeasurePoint()
{
if (Event.current.type == EventType.MouseDown && Event.current.button == 0)
{
if (measurePointList.Count == 0)
{
measurePointList.Add(new List<Vector3>());
currentAddList = 0;
}
measurePointList[currentAddList].Add(pos);
Repaint();
}
}
/// <summary>
/// 鼠标右键(去除点)
/// </summary>
private void RemovePoint()
{
if (Event.current.type == EventType.MouseDown && Event.current.button == 1)
{
//用一个Timer来避免与长按鼠标右键的操作(拖动SceneView)重合
rightClickTimer = (float)EditorApplication.timeSinceStartup;
}
if (Event.current.type == EventType.MouseUp && Event.current.button == 1)
{
float timeDiff = (float)EditorApplication.timeSinceStartup - rightClickTimer;
//如果按下按键的时间小于0.4秒,则去除
if (timeDiff < 0.4f)
{
if (measurePointList.Count > 0 && measurePointList[closestList] != null)
{
RemoveClosestPoint();
}
}
}
}
/// <summary>
/// 增加新的测量路径
/// </summary>
private void AddNewList()
{
measurePointList.Add(new List<Vector3>());
currentAddList = measurePointList.Count - 1;
}
#endregion
private void GetClosestPoint(out Vector3 closestPoint, out int closestPointList)
{
Event currentEvent = Event.current;
var tempPos = HandleUtility.GUIPointToWorldRay(currentEvent.mousePosition).origin;
var closestDistance = Mathf.Infinity;
closestPoint = new Vector3();
closestPointList = 0;
//找到离鼠标最近的点
for (var index = 0; index < measurePointList.Count; index++)
{
var pointList = measurePointList[index];
for (var i = 0; i < pointList.Count; i++)
{
var point = pointList[i];
Vector3 direction = point - tempPos;
float distanceSqr = direction.sqrMagnitude;
if (distanceSqr < closestDistance)
{
closestDistance = distanceSqr;
closestPoint = point;
closestPointList = index;
}
}
}
}
/// <summary>
/// 移除离鼠标位置最近的点
/// </summary>
private void RemoveClosestPoint()
{
measurePointList[closestList].Remove(closestPoint);
}
/// <summary>
/// 绘制点和坐标
/// </summary>
private void DrawMeasurePoint(List<Vector3> listToDraw, Color distanceColor)
{
if (listToDraw.Count > 0)
{
foreach (var point in listToDraw)
{
DebugExtension.DebugPoint(point, distanceColor, 0.5f);
if (showCoordinate)
{
//根据sceneCamera的位置,调整字的位置
/*float dist = Vector3.Distance(UnityEngine.Camera.main.transform.position, point);
var newScale = dist / 10 * 3;*/
DrawCoordinate(point + new Vector3(0, 0.4f, 0), point, distanceColor);
}
}
}
}
/// <summary>
/// 绘制点与点之间的距离
/// </summary>
private void DrawLineBetweenPoints(List<Vector3> listToDraw, Color color, float lineWidth)
{
if (listToDraw.Count >= 2)
{
for (int i = 0; i < listToDraw.Count - 1; i++)
{
var arrowDirection = (listToDraw[i + 1] - listToDraw[i]).normalized;
var pointDis = Vector3.Distance(listToDraw[i], listToDraw[i + 1]);
Vector3 midPoint = new Vector3((listToDraw[i].x + listToDraw[i + 1].x) / 2,
(listToDraw[i].y + listToDraw[i + 1].y) / 2);
var xDis = Mathf.Abs(listToDraw[i].x - listToDraw[i + 1].x);
var yDis = Mathf.Abs(listToDraw[i].y - listToDraw[i + 1].y);
if (showDis)
{
DrawDistance(midPoint + new Vector3(0, 1.5f, 0), xDis, yDis, color);
}
Handles.color = color;
Handles.DrawLine(listToDraw[i], listToDraw[i + 1], lineWidth);
}
}
}
GUIStyle style = new GUIStyle();
private void DrawDistance(Vector3 textPosition, float xDis, float yDis, Color textColor)
{
style.fontSize = fontSize;
style.normal.textColor = textColor;
Handles.Label(textPosition, "X: " + xDis + "\nY: " + yDis, style);
}
private void DrawCoordinate(Vector3 textPosition, Vector3 pos, Color textColor)
{
style.fontSize = fontSize;
style.normal.textColor = textColor;
Handles.Label(textPosition, "Position: " + pos, style);
}
#endif
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment