Unity customization, exposing attributes to the Inspector panel, unityinspector
Sun Guangdong 2015, 7, 12
Many editor functions of Unity are implemented through feature Attribute.
We need to expand the Inspector by ourselves and write the Attribute by ourselves.
First, why?
In order to write Object-oriented Programs, encapsulation features are more elegant. The following script enables the attributes (I .e. members of getter/setter) to be displayed on the Inspector of Unity.
In this way, you can keep the fields of the class confidential and restrict all external access. You can only access the fields through attributes,
Look at the code!
using System; [AttributeUsage(AttributeTargets.Property)] public class ExposePropertyAttribute : Attribute {}
Scripts in "Assets/Editor"
using UnityEditor;using UnityEngine;using System;using System.Collections;using System.Collections.Generic;using System.Reflection; public static class ExposeProperties{public static void Expose(PropertyField[] properties){var emptyOptions = new GUILayoutOption[0];EditorGUILayout.BeginVertical(emptyOptions);foreach (PropertyField field in properties){EditorGUILayout.BeginHorizontal(emptyOptions);if (field.Type == SerializedPropertyType.Integer){var oldValue = (int)field.GetValue();var newValue = EditorGUILayout.IntField(field.Name, oldValue, emptyOptions);if (oldValue != newValue)field.SetValue(newValue);}else if (field.Type == SerializedPropertyType.Float){var oldValue = (float)field.GetValue();var newValue = EditorGUILayout.FloatField(field.Name, oldValue, emptyOptions);if (oldValue != newValue)field.SetValue(newValue);}else if (field.Type == SerializedPropertyType.Boolean){var oldValue = (bool)field.GetValue();var newValue = EditorGUILayout.Toggle(field.Name, oldValue, emptyOptions);if (oldValue != newValue)field.SetValue(newValue);}else if (field.Type == SerializedPropertyType.String){var oldValue = (string)field.GetValue();var newValue = EditorGUILayout.TextField(field.Name, oldValue, emptyOptions);if (oldValue != newValue)field.SetValue(newValue);}else if (field.Type == SerializedPropertyType.Vector2){var oldValue = (Vector2)field.GetValue();var newValue = EditorGUILayout.Vector2Field(field.Name, oldValue, emptyOptions);if (oldValue != newValue)field.SetValue(newValue);}else if (field.Type == SerializedPropertyType.Vector3){var oldValue = (Vector3)field.GetValue();var newValue = EditorGUILayout.Vector3Field(field.Name, oldValue, emptyOptions);if (oldValue != newValue)field.SetValue(newValue);}else if (field.Type == SerializedPropertyType.Enum){var oldValue = (Enum)field.GetValue();var newValue = EditorGUILayout.EnumPopup(field.Name, oldValue, emptyOptions);if (oldValue != newValue)field.SetValue(newValue);}else if (field.Type == SerializedPropertyType.ObjectReference){UnityEngine.Object oldValue = (UnityEngine.Object)field.GetValue();UnityEngine.Object newValue = EditorGUILayout.ObjectField(field.Name, oldValue, field.Info.PropertyType, emptyOptions);if (oldValue != newValue)field.SetValue(newValue);}EditorGUILayout.EndHorizontal();}EditorGUILayout.EndVertical();} public static PropertyField[] GetProperties(object obj){var fields = new List<PropertyField>(); PropertyInfo[] infos = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (PropertyInfo info in infos){if (!(info.CanRead && info.CanWrite))continue; object[] attributes = info.GetCustomAttributes(true); bool isExposed = false;foreach (object o in attributes)if (o.GetType() == typeof(ExposePropertyAttribute)){isExposed = true;break;}if (!isExposed)continue; var type = SerializedPropertyType.Integer;if (PropertyField.GetPropertyType(info, out type)){var field = new PropertyField(obj, info, type);fields.Add(field);}} return fields.ToArray();}} public class PropertyField{object obj;PropertyInfo info;SerializedPropertyType type; MethodInfo getter;MethodInfo setter; public PropertyInfo Info{get { return info; }} public SerializedPropertyType Type{get { return type; }} public String Name{get { return ObjectNames.NicifyVariableName(info.Name); }} public PropertyField(object obj, PropertyInfo info, SerializedPropertyType type){this.obj = obj;this.info = info;this.type = type; getter = this.info.GetGetMethod();setter = this.info.GetSetMethod();} public object GetValue() { return getter.Invoke(obj, null); }public void SetValue(object value) { setter.Invoke(obj, new[] {value}); } public static bool GetPropertyType(PropertyInfo info, out SerializedPropertyType propertyType){Type type = info.PropertyType;propertyType = SerializedPropertyType.Generic;if (type == typeof(int))propertyType = SerializedPropertyType.Integer;else if (type == typeof(float))propertyType = SerializedPropertyType.Float;else if (type == typeof(bool))propertyType = SerializedPropertyType.Boolean;else if (type == typeof(string))propertyType = SerializedPropertyType.String;else if (type == typeof(Vector2))propertyType = SerializedPropertyType.Vector2;else if (type == typeof(Vector3))propertyType = SerializedPropertyType.Vector3;else if (type.IsEnum)propertyType = SerializedPropertyType.Enum;else if (typeof(MonoBehaviour).IsAssignableFrom(type))propertyType = SerializedPropertyType.ObjectReference;return propertyType != SerializedPropertyType.Generic;}}
using UnityEngine; public class ExposableMonobehaviour : MonoBehaviour {}
Scripts in the "Assets/Editor" folder
using UnityEditor;using UnityEngine;using System.Collections; [CustomEditor(typeof(ExposableMonoBehaviour), true)] public class ExposableMonobehaviourEditor : Editor{ExposableMonoBehaviour m_Instance;PropertyField[] m_fields; public virtual void OnEnable(){m_Instance = target as ExposableMonoBehaviour;m_fields = ExposeProperties.GetProperties(m_Instance);} public override void OnInspectorGUI(){if (m_Instance == null)return;this.DrawDefaultInspector();ExposeProperties.Expose(m_fields);}}
[Note]
This will allow classes to inherit from ExposableMonobehaviour, and will enhance the exposure of setter and getter methods. No obvious performance problems.
As you may have seen in the code above, only the following types are currently exposed (although it is easy to implement other types ):
- Integer- Float- Boolean- String- Vector2- Vector3- Enum- Object Reference (Monobehavior)
[Use :]
Create a class extension ExposableMonobehaviour and use the attributes. The property must have the getter and setter accessors and [ExposeProperty] attribute settings. Otherwise, the property will not be displayed.
When you play, to save the attribute value, you must add [SerializeField] To the attribute field. Unfortunately, this field is exposed to the editor, so you must explicitly hide it using [HideInInspector].
Example: Hanging on an object
using UnityEngine; public class MyType : ExposableMonoBehaviour{[HideInInspector, SerializeField] int m_SomeInt;[HideInInspector, SerializeField] float m_SomeFloat;[HideInInspector, SerializeField] bool m_SomeBool;[HideInInspector, SerializeField] string m_Etc; [HideInInspector, SerializeField] MonoBehaviour m_Obj; [ExposeProperty] public int SomeInt{get { return m_SomeInt; }set { m_SomeInt = value; }} [ExposeProperty] public float SomeFloat{get { return m_SomeFloat; }set { m_SomeFloat = value; }} [ExposeProperty] public bool SomeBool{get { return m_SomeBool; }set { m_SomeBool = value; }} [ExposeProperty] public string SomeString{get { return m_Etc; }set { m_Etc = value; }} [ExposeProperty] public MonoBehaviour SomeScript{get { return m_Obj; }set { m_Obj = value; }}}
Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.