Personalizando nuestro editor - Unity

Un CustomEditor nos permite cambiar la representación visual de nuestras clases en el Unity Inspector. Hace más sencillo interactuar con las script clases asociadas a Gameobjects, prefabs, etc…

/img/c/cusomeditoruni.png
.
/img/c/cusomeditoruni2.png
.

Nuestro primer paso es crear una carpeta con el nombre Editor. Para Unity es un nombre de carpeta muy especial, Unity carga automáticamente todos los scripts que modifican el comportamiento del UnityEditor desde esta carpeta. Estos scripts NO serán incluidos en el empaquetado final del juego, solo serán usado por el UnityEditor.

Creamos dos carpetas más: Scripts y Scenes para guardar el resto de scripts y la escena que tendrá nuestro trabajo

El árbol de directorios nos queda así:


.
Assets   
└───NombreProyecto
Editor
Scripts
Scenes 

Empezaremos con dos clases muy simples, primero creamos un nuevo script con el nombre de Unidad.cs en nuestra carpeta Scripts y añadimos las siguientes clases:


//                                  ┌∩┐(◣_◢)┌∩┐
//																				\\
// Unidad.cs (24/01/2019)														\\
// Autor: Antonio Mateo (.\Moon Antonio) 	antoniomt.moon@gmail.com			\\
// Descripcion:		Clase que contiene la informacion de una unidad.			\\
// Fecha Mod:		24/01/2019													\\
// Ultima Mod:		Version Inicial.											\\
//******************************************************************************\\

#region Librerias
using UnityEngine;
#endregion

namespace MoonAntonio
{
	/// <summary>
	/// <para>Clase que contiene la informacion de una unidad.</para>
	/// </summary>
	[HelpURL("https://moonantonio.github.io/"), AddComponentMenu("MoonAntonio/Unidad"), System.Serializable]
	public class Unidad : MonoBehaviour 
	{
		#region Variables Publicas
		public Data data;
		#endregion

		#region Dev
		[ContextMenu("Dev")]
	    protected void DevScript()
	    {
	        Debug.Log("<color=green>Unidad :: DevScript()</color> >> Inicializado.");
	    }
	    #endregion
	}

	[System.Serializable]
	public class Data
	{
		#region Variables Publicas
		public float vida = 0.0f;
		public float mana = 0.0f;
		public bool isVivo = false;
		#endregion
	}
}

Data representará la información de la unidad.

Queremos clases capaces de ser serializadas. Para hacer esto añadimos la etiqueta [System.Serializable] sobre la declaración de las clases.

/img/c/cusomeditoruni.png
.

Ahora crearemos nuestra clase editor personalizada, creamos un nuevo script en la carpeta Editor llamado UnidadInspector e importamos la clase editor usada por el UnityEditor.

Añadimos la etiqueta [CustomEditor(typeof(Unidad))] para indicar que vamos a definir la representación de la clase Unidad en el editor. UnidadInspector hereda de Editor. Sobreescribimos OnInspectorGUI(), este método será llamado con cada evento del editor.


//                                  ┌∩┐(◣_◢)┌∩┐
//																				\\
// UnidadInspector.cs (24/01/2019)												\\
// Autor: Antonio Mateo (.\Moon Antonio) 	antoniomt.moon@gmail.com			\\
// Descripcion:		Inspector de la clase Unidad.								\\
// Fecha Mod:		24/01/2019													\\
// Ultima Mod:		Version Inicial.											\\
//******************************************************************************\\

#region Librerias
using UnityEngine;
using UnityEditor;
#endregion

namespace MoonAntonio
{
	/// <summary>
	/// <para>Inspector de la clase <see cref="Unidad"/>.</para>
	/// </summary>
	[HelpURL("https://moonantonio.github.io/"), AddComponentMenu("MoonAntonio/UnidadInspector"), CustomEditor(typeof(Unidad))]
	public class UnidadInspector : Editor 
	{
		public override void OnInspectorGUI()
		{
			// TODO
		}

		#region Dev
		[ContextMenu("Dev")]
	    protected void DevScript()
	    {
	        Debug.Log("<color=green>UnidadInspector :: DevScript()</color> >> Inicializado.");
	    }
	    #endregion
	}
}

La primera tarea es añadir en TODO lo siguiente:


serializedObject.Update(); 

// TODO
							
serializedObject.ApplyModifiedProperties();

Ahora podemos continuar con la interfaz gráfica

Podemos añadir etiquetas de texto usando LabelField, donde esta TODO :


EditorGUILayout.LabelField("Datos Unidad");

Extraer los atributos de ‘data’ usando el nombre del atributo con el objecto serializado y FindProperty:


SerializedProperty dataProperty = serializedObject.FindProperty("data");

Para extraer los atributos de Data podemos usar el nombre del atributo con FindPropertyRelative porque usaremos la propiedad extraída previamente.


SerializedProperty vidaProperty = dataProperty.FindPropertyRelative("vida");
SerializedProperty manaProperty = dataProperty.FindPropertyRelative("mana");
SerializedProperty isVivoProperty = dataProperty.FindPropertyRelative("isVivo");

Para dibujar nuestra lista empezamos añadiendo una linea horizontal y espacios flexibles a cada uno de los lados, así los elementos se mantendrán juntos incluso si se cambia el tamaño del editor.


EditorGUILayout.BeginHorizontal();
// TODO
EditorGUILayout.EndHorizontal();

Al final quedara algo asi:


//                                  ┌∩┐(◣_◢)┌∩┐
//																				\\
// UnidadInspector.cs (24/01/2019)												\\
// Autor: Antonio Mateo (.\Moon Antonio) 	antoniomt.moon@gmail.com			\\
// Descripcion:		Inspector de la clase Unidad.								\\
// Fecha Mod:		24/01/2019													\\
// Ultima Mod:		Version Inicial.											\\
//******************************************************************************\\

#region Librerias
using UnityEngine;
using UnityEditor;
#endregion

namespace MoonAntonio
{
	/// <summary>
	/// <para>Inspector de la clase <see cref="Unidad"/>.</para>
	/// </summary>
	[HelpURL("https://moonantonio.github.io/"), AddComponentMenu("MoonAntonio/UnidadInspector"), CustomEditor(typeof(Unidad))]
	public class UnidadInspector : Editor 
	{
		public override void OnInspectorGUI()
		{
			serializedObject.Update();

			EditorGUILayout.LabelField("Datos Unidad");
			SerializedProperty dataProperty = serializedObject.FindProperty("data");
			SerializedProperty vidaProperty = dataProperty.FindPropertyRelative("vida");
			SerializedProperty manaProperty = dataProperty.FindPropertyRelative("mana");
			SerializedProperty isVivoProperty = dataProperty.FindPropertyRelative("isVivo");

			EditorGUILayout.BeginHorizontal("box");
			vidaProperty.floatValue = EditorGUILayout.FloatField("HP", vidaProperty.floatValue);
			manaProperty.floatValue = EditorGUILayout.FloatField("MP" ,manaProperty.floatValue);
			EditorGUILayout.EndHorizontal();

			EditorGUILayout.BeginHorizontal("box");
			isVivoProperty.boolValue = EditorGUILayout.Toggle("Alive", isVivoProperty.boolValue);
			EditorGUILayout.EndHorizontal();

			serializedObject.ApplyModifiedProperties();
		}

		#region Dev
		[ContextMenu("Dev")]
	    protected void DevScript()
	    {
	        Debug.Log("<color=green>UnidadInspector :: DevScript()</color> >> Inicializado.");
	    }
	    #endregion
	}
}

/img/c/cusomeditoruni2.png
.
GitHub
/img/ref.png
.