当前位置:   article > 正文

unity编辑器扩展#1 自定义窗口、面板、和属性_unity editorwindow自定义class

unity editorwindow自定义class

撸一遍unity官方文档的给的三个案例:https://docs.unity3d.com/2017.4/Documentation/Manual/editor-EditorWindows.html

自定义窗口

首先,要注意和编辑器相关的脚本都应该把放到Editor文件夹里,可以有多个Editor文件夹。

然后创建一个继承自EditorWindow的类

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEditor;
  5. //要创建的编辑器窗口类应该继承EditorWindow;
  6. public class OneEditorWindow : EditorWindow
  7. {
  8. //MenuItem是一个特性,会在顶部按路径生成选项,点击就会调用下面的方法,也就是打开窗口
  9. [MenuItem("Unity编辑器/OneEditorWindow")]
  10. public static void OpenWindow()
  11. {
  12. //打开窗口的方法 注释掉的方法你可以设置打开的窗口的位置和大小
  13. //可以直接用没参数的重载方法,参数用来设置窗口名称,是否用标签窗口形式之类的
  14. EditorWindow.GetWindow<OneEditorWindow>(false,"一个窗口");
  15. //EditorWindow.GetWindowWithRect<MyFirstWindow>(new Rect(0f, 0f, 500, 500));
  16. }
  17. private Color col;
  18. private float f;
  19. //OnGUI里写你想绘制在窗口里的内容
  20. private void OnGUI()
  21. {
  22. EditorGUILayout.LabelField("一个label");
  23. f = EditorGUILayout.FloatField("一个数字框", f);
  24. col=EditorGUILayout.ColorField("一个颜色选择框",col);
  25. }
  26. }

就好了~

  

自定义类和成员的显示

这里提到的脚本不需要放到Editor文件夹里,因为他只是修改原有的显示而已

修改类实例的的显示

        

红色框的就是我们要修改的类 Ingredient在Inspector面板上的显示,左边是Unity默认的显示,右边是修改后的。

首先是用于实验的类

  1. public class Recipe: MonoBehaviour
  2. {
  3. public Ingredient PotionResult;
  4. public Ingredient[] PotionIngredients;
  5. }
  6. public enum IngredientUnit {Cup,Bowl,Spoon,Piece}
  7. [Serializable]//这个特性表示该类可以被序列化,但是不加好像也没关系
  8. public class Ingredient {
  9. //需要重新设计属性面板的类
  10. public string Name;
  11. public int Amount;
  12. public IngredientUnit Unit;
  13. }

接下来就是写可以修改显示的类

修改显示的类应该继承:PropertyDrawer

用特性[CustomPropertyDrawer(typeof(type))]表明它是用来针对修改哪个类的

和窗口一样,在OnGUI里写绘制的代码,

方法提供来三个参数,Rect是位置和宽高;property里面存着类的相关信息,可以用FindPropertyRelative(name)来找类成员;label就是名字;

在BeginProperty()和EndProperty()里写可以确保布局的整齐

  1. [CustomPropertyDrawer(typeof(Ingredient))]
  2. public class IngredientDrawer:PropertyDrawer
  3. {
  4. //重新绘制面板
  5. public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
  6. {
  7. EditorGUI.BeginProperty(position, label, property);
  8. //每个实例的名字 本来应该是Element0123 ,但这里显示了Name字符串
  9. position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
  10. //本来是1层,要缩进,设置成0和他的上级size同级,使之与其对齐;
  11. var index = EditorGUI.indentLevel;
  12. EditorGUI.indentLevel = 0;
  13. //给三个属性安排位置
  14. var amountRect = new Rect(position.x, position.y, 30, position.height);
  15. var unitRect = new Rect(position.x + 35, position.y, 50, position.height);
  16. var nameRect = new Rect(position.x + 90, position.y, position.width - 90, position.height);
  17. //绘制属性
  18. EditorGUI.PropertyField(amountRect, property.FindPropertyRelative("Amount"), GUIContent.none);
  19. EditorGUI.PropertyField(unitRect, property.FindPropertyRelative("Unit"), GUIContent.none);
  20. EditorGUI.PropertyField(nameRect, property.FindPropertyRelative("Name"), GUIContent.none);
  21. //重新设置为原来的层级
  22. EditorGUI.indentLevel = index;
  23. EditorGUI.EndProperty();
  24. }
  25. }

修改类中成员的显示

修改类成员的显示通过给成员添加属性特性(Property Attributes)来实现,像unity自带的[Range(min,max)]就是一个特性,这里实现一个自己的Range来作为例子

先定义一个特性类,继承:PropertyAttribute

  1. public class MyRangeAttribute : PropertyAttribute
  2. {
  3. public float min;
  4. public float max;
  5. public MyRangeAttribute(float min, float max)
  6. {
  7. this.min = min;
  8. this.max = max;
  9. }
  10. }

然后和修改类的显示类似,写一个继承PropertyDrawer的类,在OnGUI里写显示的代码

  1. [CustomPropertyDrawer(typeof(MyRangeAttribute))]
  2. public class RangeDrawer : PropertyDrawer
  3. {
  4. public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
  5. {
  6. MyRangeAttribute range = (MyRangeAttribute) attribute;
  7. if (property.propertyType == SerializedPropertyType.Float)
  8. EditorGUI.Slider(position, property, range.min, range.max, label);
  9. else if (property.propertyType == SerializedPropertyType.Integer)
  10. EditorGUI.IntSlider(position, property, (int) range.min, (int) range.max, label);
  11. else
  12. EditorGUI.LabelField(position, label.text, "Use MyRange with float or int.");
  13. }
  14. }

attribute是PropertyDrawer里的成员,存储了所对应的特性类,强转出真正的特性。 然后就是读取attribute和property里的数据生成slider控件了,关于GUI里的各种控件看#2.

自定义编辑器

就是像游戏中的地形系统啊、布料系统啊,你添加组件到游戏物体,然后就可以在编辑状态,在Sence或者哪里里做各种修改和操作。

首先是写一个用于实验的类,因为要在编辑模式也能运行,所以加了个[ExecuteInEditMode]的特性

  1. [ExecuteInEditMode]
  2. public class LookAtPoint : MonoBehaviour
  3. {
  4. public Transform lookPoint;
  5. public Vector3 lookPos;
  6. public void Update()
  7. {
  8. if (lookPoint)
  9. {
  10. transform.LookAt(lookPos);
  11. }
  12. }
  13. }

接下来就是重要的编辑器类了,继承:Editor,要放在Editor文件夹里

  1. [CustomEditor(typeof(LookAtPoint))]
  2. [CanEditMultipleObjects]
  3. public class LookAtPointEditor : Editor
  4. {
  5. private SerializedProperty lookAtPoint;
  6. private SerializedProperty lookPos;
  7. private void OnEnable()
  8. {
  9. lookAtPoint = serializedObject.FindProperty("lookPoint");
  10. lookPos = serializedObject.FindProperty("lookPos");
  11. }
  12. //调整在Inspector上的布局
  13. public override void OnInspectorGUI()
  14. {
  15. serializedObject.Update();//更新面板显示
  16. //选择的transform
  17. EditorGUILayout.PropertyField(lookPos);
  18. serializedObject.ApplyModifiedProperties();//将面板值应用到属性
  19. /*
  20. //转化成实际的类型
  21. Transform a=(Transform)lookAtPoint.objectReferenceValue;
  22. if (a.position.y > ((LookAtPoint)target).transform.position.y)
  23. {
  24. EditorGUILayout.LabelField("(Above this object)");
  25. }
  26. if (a.position.y < ((LookAtPoint)target).transform.position.y)
  27. {
  28. EditorGUILayout.LabelField("(Below this object)");
  29. }
  30. */
  31. }
  32. //在Scene场景里添加绘制一些需要的UI布局
  33. public void OnSceneGUI()
  34. {
  35. var t = (target as LookAtPoint);
  36. EditorGUI.BeginChangeCheck();
  37. //绘制一个图形(移动物体的那个三箭头),位置对应lookPos
  38. Vector3 pos = Handles.PositionHandle(t.lookPos, Quaternion.identity);
  39. if (EditorGUI.EndChangeCheck())
  40. {//有调整就修改数值
  41. Undo.RecordObject(target, "Move point");
  42. t.lookPos = pos;
  43. t.Update();
  44. }
  45. }
  46. //protected override void OnHeaderGUI();
  47. //public override void OnPreviewGUI(Rect r, GUIStyle background)
  48. //public override void OnInteractivePreviewGUI(Rect r, GUIStyle background)
  49. }

首先是两个特性,[CustomEditor(typeof(type))]和前面的类似,用来表示你这个Editor管的是哪个组件,这里就是我们的LookAtPoint,[CanEditMultipleObjects]则表示该编辑器可以支持多个物体。

用serializedObject.FindProperty来找需要的数据

这里用到了两个显示的函数,一个处理Inspector上脚本的显示,一个处理Scene场景中的显示,后面还注释了几个没用到的。

记得把SerializedProperty转化成正确的类型,一般的数据结构它独有对应的属性,像lookAtPoint.doubleValue就会返回double,当然lookAtPoint不是double类型,会报错,对于引用类型,用.objectReferenceValue,然后再转一下,像文中注释的部分一样

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/106525
推荐阅读
相关标签
  

闽ICP备14008679号