添加工具,优化配置
This commit is contained in:
229
unity/Assets/Editor/ElementsAligner.cs
Normal file
229
unity/Assets/Editor/ElementsAligner.cs
Normal file
@@ -0,0 +1,229 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
/// <summary>
|
||||
/// Elements底对齐工具 - 将Elements下所有物体底对齐到Y=0平面
|
||||
/// </summary>
|
||||
public class ElementsAligner : Editor
|
||||
{
|
||||
[MenuItem("Tools/Elements/底对齐到地面 (Y=0)")]
|
||||
public static void AlignElementsToGround()
|
||||
{
|
||||
GameObject elements = GameObject.Find("Elements");
|
||||
|
||||
if (elements == null)
|
||||
{
|
||||
EditorUtility.DisplayDialog("错误", "找不到场景中的 'Elements' 物体", "确定");
|
||||
return;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
Undo.SetCurrentGroupName("Align Elements to Ground");
|
||||
|
||||
for (int i = 0; i < elements.transform.childCount; i++)
|
||||
{
|
||||
Transform child = elements.transform.GetChild(i);
|
||||
|
||||
// 记录到Undo栈
|
||||
Undo.RecordObject(child, $"Align {child.name}");
|
||||
|
||||
// 获取物体的包围盒
|
||||
Bounds bounds = GetObjectBounds(child);
|
||||
|
||||
if (bounds.size == Vector3.zero)
|
||||
{
|
||||
Debug.LogWarning($"跳过 {child.name} - 无法计算包围盒");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 计算需要移动的距离:让物体底部对齐到Y=0
|
||||
float bottomY = bounds.min.y;
|
||||
Vector3 newPosition = child.position;
|
||||
newPosition.y = child.position.y - bottomY;
|
||||
|
||||
child.position = newPosition;
|
||||
|
||||
count++;
|
||||
Debug.Log($"✓ 对齐 {child.name}: 底部Y从 {bottomY:F3} 到 0");
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(
|
||||
UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene()
|
||||
);
|
||||
|
||||
EditorUtility.DisplayDialog("完成", $"已对齐 {count} 个物体到地面 (Y=0)", "确定");
|
||||
Debug.Log($"完成!对齐了 {count} 个物体");
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("Tools/Elements/底对齐到指定高度")]
|
||||
public static void AlignElementsToCustomHeight()
|
||||
{
|
||||
string input = EditorInputDialog.Show("对齐到指定高度", "请输入目标Y坐标:", "0");
|
||||
|
||||
if (input == null) return; // 用户取消
|
||||
|
||||
if (!float.TryParse(input, out float targetY))
|
||||
{
|
||||
EditorUtility.DisplayDialog("错误", "请输入有效的数字", "确定");
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject elements = GameObject.Find("Elements");
|
||||
|
||||
if (elements == null)
|
||||
{
|
||||
EditorUtility.DisplayDialog("错误", "找不到场景中的 'Elements' 物体", "确定");
|
||||
return;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
Undo.SetCurrentGroupName("Align Elements to Custom Height");
|
||||
|
||||
for (int i = 0; i < elements.transform.childCount; i++)
|
||||
{
|
||||
Transform child = elements.transform.GetChild(i);
|
||||
Undo.RecordObject(child, $"Align {child.name}");
|
||||
|
||||
Bounds bounds = GetObjectBounds(child);
|
||||
|
||||
if (bounds.size == Vector3.zero)
|
||||
{
|
||||
Debug.LogWarning($"跳过 {child.name} - 无法计算包围盒");
|
||||
continue;
|
||||
}
|
||||
|
||||
float bottomY = bounds.min.y;
|
||||
Vector3 newPosition = child.position;
|
||||
newPosition.y = child.position.y - bottomY + targetY;
|
||||
|
||||
child.position = newPosition;
|
||||
|
||||
count++;
|
||||
Debug.Log($"✓ 对齐 {child.name}: 底部Y从 {bottomY:F3} 到 {targetY:F3}");
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(
|
||||
UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene()
|
||||
);
|
||||
|
||||
EditorUtility.DisplayDialog("完成", $"已对齐 {count} 个物体到 Y={targetY}", "确定");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取物体的世界空间包围盒(包括所有子物体和渲染器)
|
||||
/// </summary>
|
||||
private static Bounds GetObjectBounds(Transform obj)
|
||||
{
|
||||
Renderer[] renderers = obj.GetComponentsInChildren<Renderer>();
|
||||
|
||||
if (renderers.Length == 0)
|
||||
{
|
||||
// 如果没有渲染器,使用碰撞体或transform位置
|
||||
Collider[] colliders = obj.GetComponentsInChildren<Collider>();
|
||||
if (colliders.Length > 0)
|
||||
{
|
||||
Bounds bounds = colliders[0].bounds;
|
||||
for (int i = 1; i < colliders.Length; i++)
|
||||
{
|
||||
bounds.Encapsulate(colliders[i].bounds);
|
||||
}
|
||||
return bounds;
|
||||
}
|
||||
|
||||
// 都没有,返回以物体为中心的小包围盒
|
||||
return new Bounds(obj.position, Vector3.one * 0.1f);
|
||||
}
|
||||
|
||||
// 使用第一个渲染器初始化
|
||||
Bounds result = renderers[0].bounds;
|
||||
|
||||
// 合并所有渲染器的包围盒
|
||||
for (int i = 1; i < renderers.Length; i++)
|
||||
{
|
||||
result.Encapsulate(renderers[i].bounds);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 简单的输入对话框(用于自定义高度)
|
||||
/// </summary>
|
||||
public class EditorInputDialog : EditorWindow
|
||||
{
|
||||
private string _title;
|
||||
private string _message;
|
||||
private string _inputText;
|
||||
private bool _confirmed = false;
|
||||
|
||||
public static string Show(string title, string message, string defaultValue)
|
||||
{
|
||||
EditorInputDialog window = CreateInstance<EditorInputDialog>();
|
||||
window.titleContent = new GUIContent(title);
|
||||
window._title = title;
|
||||
window._message = message;
|
||||
window._inputText = defaultValue;
|
||||
window._confirmed = false;
|
||||
window.minSize = new Vector2(300, 120);
|
||||
window.maxSize = new Vector2(300, 120);
|
||||
window.ShowModal();
|
||||
|
||||
return window._confirmed ? window._inputText : null;
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
GUILayout.Space(10);
|
||||
GUILayout.Label(_message, EditorStyles.wordWrappedLabel);
|
||||
GUILayout.Space(5);
|
||||
|
||||
GUI.SetNextControlName("InputField");
|
||||
_inputText = GUILayout.TextField(_inputText);
|
||||
|
||||
if (Event.current.type == EventType.Repaint && GUI.GetNameOfFocusedControl() != "InputField")
|
||||
{
|
||||
EditorGUI.FocusTextInControl("InputField");
|
||||
}
|
||||
|
||||
// 支持回车确认
|
||||
if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Return)
|
||||
{
|
||||
_confirmed = true;
|
||||
Close();
|
||||
Event.current.Use();
|
||||
}
|
||||
|
||||
// 支持ESC取消
|
||||
if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Escape)
|
||||
{
|
||||
_confirmed = false;
|
||||
Close();
|
||||
Event.current.Use();
|
||||
}
|
||||
|
||||
GUILayout.Space(10);
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
if (GUILayout.Button("确定", GUILayout.Width(80)))
|
||||
{
|
||||
_confirmed = true;
|
||||
Close();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("取消", GUILayout.Width(80)))
|
||||
{
|
||||
_confirmed = false;
|
||||
Close();
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user