using System; using UnityEngine; using Object = UnityEngine.Object; #if UNITY_EDITOR using UnityEditor; #endif namespace Mountools.Tools { // Mountools 编辑器相关 public static class MountoolsEditor { public static string rootPath = "Assets/Mountools"; // 设置已修改 (任何时候) public static void SetDirty(Object obj) { #if UNITY_EDITOR if (Application.isPlaying) { EditorUtility.SetDirty(obj); } #endif } // 创建游戏对象 public static GameObject CreateEmptyGameObject(string name = "New Game Object", bool moveToView = true) { var obj = new GameObject(name); #if UNITY_EDITOR if (! Application.isPlaying) { if (moveToView) SceneView.lastActiveSceneView.MoveToView(obj.transform); obj.transform.parent = Selection.gameObjects.Length > 0 ? Selection.gameObjects[0].transform : null; SetDirty(obj); Undo.RegisterCreatedObjectUndo(obj, $"Create GameObject \"{name}\""); } #endif return obj; } // 创建带组件的游戏对象 public static T CreateGameObject (string name = "", bool moveToView = true) where T : Component { var obj = new GameObject(name == "" ? typeof(T).Name : name); var component = obj.AddComponent(); #if UNITY_EDITOR if (! Application.isPlaying) { if (moveToView) SceneView.lastActiveSceneView.MoveToView(obj.transform); obj.transform.parent = Selection.gameObjects.Length > 0 ? Selection.gameObjects[0].transform : null; SetDirty(obj); Undo.RegisterCreatedObjectUndo(obj, $"Create {typeof(T).Name}"); } #endif return component; } // 获得脚本模板内容 public static string ScriptTemplate(string templateName) { var result = ""; #if UNITY_EDITOR var fullName = $"{rootPath}/_RESOURCES/SCRIPT_TEMPLATE/" + templateName.Trim() + "Template.txt"; TextAsset templateText = AssetDatabase.LoadAssetAtPath(fullName); result = templateText.text; #endif return result.Trim(); } // 通过路径计算命名空间 public static string GetNamespaceByPath(string pathName) { var start = pathName.IndexOf('/') + 1; return pathName.Substring (start, pathName.LastIndexOf('/') - start) .Replace("/", "."); } public static void FoldoutMenu(ref bool fold, string title, Action layout) { #if UNITY_EDITOR EditorGUILayout.BeginHorizontal("FrameBox"); { EditorGUILayout.LabelField("", GUILayout.Width(20)); fold = ! EditorGUILayout.Foldout(! fold, title); } EditorGUILayout.EndHorizontal(); if (! fold) { EditorGUI.indentLevel++; EditorGUILayout.BeginVertical("OL box NoExpand"); { layout.Invoke(); } EditorGUILayout.EndVertical(); EditorGUI.indentLevel--; EditorGUILayout.Space(); } #endif } public static void FoldoutMenuWithToggle(ref bool fold, ref bool toggle, string title, Action layout) { #if UNITY_EDITOR EditorGUILayout.BeginHorizontal("FrameBox"); { EditorGUILayout.LabelField("", GUILayout.Width(20)); fold = ! EditorGUILayout.Foldout(! fold, title); toggle = EditorGUILayout.Toggle("", toggle, GUILayout.Width(20)); } EditorGUILayout.EndHorizontal(); if (! fold) { EditorGUI.BeginDisabledGroup(! toggle); { EditorGUI.indentLevel++; EditorGUILayout.BeginVertical("OL box NoExpand"); { layout.Invoke(); } EditorGUILayout.EndVertical(); EditorGUI.indentLevel--; } EditorGUI.EndDisabledGroup(); EditorGUILayout.Space(); } #endif } public static class GUIStyles { public static GUIStyle titleStyleLarge => new() { normal = { textColor = GUI.contentColor }, fontStyle = FontStyle.Bold, fontSize = 16 }; public static GUIStyle titleStyleSmall => new() { normal = { textColor = GUI.contentColor }, fontStyle = FontStyle.Bold }; public static GUIStyle contentStyleItalic => new() { normal = { textColor = GUI.contentColor }, fontStyle = FontStyle.Italic }; } } // Mountools 数据 // 可视化 Vector2 范围 [Serializable] public struct Vector2Square { public float x; public float y; public Vector2Square(float x = 0.5f, float y = 0.5f) { this.x = x; this.y = y; } } #if UNITY_EDITOR [CustomPropertyDrawer(typeof(Vector2Square))] public class Vector2SquarePropertyDrawer : PropertyDrawer { private Rect drawerPosition; public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { drawerPosition = position; EditorGUI.BeginProperty(position, label, property); { // xy的参数 var xValue = (float) typeof(Vector2Square).GetField("x").GetValue(property.boxedValue); var yValue = (float) typeof(Vector2Square).GetField("y").GetValue(property.boxedValue); // 自身对象 var selfObject = (Vector2Square) property.boxedValue; // 事件 Event currentEvent = Event.current; { // ----------- 绘制部分 // 绘制文本 position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label); position.y += 25; // 绘制方块 var size = drawerPosition.width / 3; var squareRect = new Rect(new Vector2(20, position.y), size * Vector2.one); EditorGUI.HelpBox(squareRect, "", MessageType.None); // position.x += size; // 绘制点 var pointSize = 2; var pointRect = new Rect( new Vector2( Mathf.Lerp(squareRect.xMin, squareRect.xMax, xValue), Mathf.Lerp(squareRect.yMax, squareRect.yMin, yValue) ), pointSize * Vector2.one ); EditorGUI.DrawRect(pointRect, Color.white); // 绘制数值拖动条 EditorGUI.BeginChangeCheck(); { selfObject.x = EditorGUI.Slider(position, "", xValue, 0, 1); position.y += 35; selfObject.y = EditorGUI.Slider(position, "", yValue, 0, 1); } if (EditorGUI.EndChangeCheck()) { property.boxedValue = selfObject; property.serializedObject.ApplyModifiedProperties(); } // ----------- 数值更改部分 // 鼠标点击 if ((currentEvent.type == EventType.MouseDrag || currentEvent.type == EventType.MouseDown) && currentEvent.button == 0) { // 鼠标位置 var pos = currentEvent.mousePosition; // 若在范围 if ( MountoolsMath.IsInRange(pos.x, squareRect.xMin - 5, squareRect.xMax + 5) && MountoolsMath.IsInRange(pos.y, squareRect.yMin - 5, squareRect.yMax + 5) ) { var newX = Mathf.Lerp(0, 1, Mathf.InverseLerp(squareRect.xMin, squareRect.xMax, pos.x)); var newY = Mathf.Lerp(0, 1, Mathf.InverseLerp(squareRect.yMax, squareRect.yMin, pos.y)); selfObject.x = newX; selfObject.y = newY; property.boxedValue = selfObject; property.serializedObject.ApplyModifiedProperties(); } } } } EditorGUI.EndProperty(); } public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { var height = 0f; height += 25; // 第一行 height += drawerPosition.width / 3; // 方块 height += 5; return height; } } #endif }