Tutorial: CustomEditor

02 November 2014 Written by 
Published in Unity

English

With this tutorial we will try to explain how to start to use CustomEditor with Lists

A CustomEditor allow us to change the representation of our classes into the Unity Inspector. It makes easier to interact with the script classes associated to Gameobjects, prefabs, etc...

listbefore

Component without CustomEditor

 

imageafter

Component with CustomEditor

 

Our first step is to create a folder named Editor. It is a special Unity folder name, Unity will automatically load all scripts that modify the behaviour of UnityEditor from this folder. This scripts will NOT be included in final game build, only will be used by the UnityEditor

 

We will create two more folders: Scripts and Scenes to store the rest of scripts and the scene to save the work

The directory path look like this:

Assets
  |_Editor
  |_Scripts
  |_Scenes

We start with two simple classes, first we create a new script named Data.cs in our folder Scripts and add the following classes:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class BinarySequence
{
	public int numBits = 5;
	public List<bool> bitList;
}

public class Data : MonoBehaviour
{
	public BinarySequence sequence;
}

BinarySequence will represent a list of bits

We have clases to be able to be serializated. To do this we add the tag [System.Serializable] above classes. We can extract the attributes in our editor class in the next step.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;


//The Serializable attribute lets you embed a class with sub properties in the inspector.
[System.Serializable]
public class BinarySequence
{
	public int numBits = 5;
	public List<bool> bitList;
}

[System.Serializable]
public class Data : MonoBehaviour
{
	public BinarySequence sequence;
}

Now we make our custom editor class, creates a new script on Editor named DataEditor and we import the needed editor class width using UnityEditor;.

  • We add the tag [CustomEditor(typeof(Data))] to say that we will define the representation of the class Data into the editor
  • DataEditor inherits Editor

Override OnInspectorGUI(), this method will be called with each editor event 

using UnityEngine;
using UnityEditor;
using System.Collections;

[CustomEditor(typeof(Data))]
public class DataEditor : Editor 
{
	/** Update with each inspector event*/
	public override void OnInspectorGUI () 
	{
		//Insert code here
	}
}

Our first task is to add:

		serializedObject.Update();  //update the serializazed object of Data
// Insert code here
serializedObject.ApplyModifiedProperties(); //apply property modifications

Now we can continue with the GUI

Add an info text with LabelField

EditorGUILayout.LabelField("Binary sequence");

Extract the attribute 'sequence' using the attribute name with the serialized object and FindProperty

SerializedProperty sequenceProperty = serializedObject.FindProperty("sequence");

To extract the BinarySequence attributes we can use the attribute name and FindPropertyRelative because of we will use the previous extracted property.

SerializedProperty bitListProperty = sequenceProperty.FindPropertyRelative("bitList");
SerializedProperty newSizeList = sequenceProperty.FindPropertyRelative("numBits");

If we add now the script Data to an object the list will be created with size 0 and we can not see anything. To change this we will override the size using the numBits attribute of BinarySequence.

The variable bitListProperty contain a serialized object of type List, therefore we can access to the attributes of the class List using FindPropertyRelative the same way we did before

/** set default size */
bitListProperty.FindPropertyRelative("Array.size").intValue = newSizeList.intValue;
int size = bitListProperty.FindPropertyRelative("Array.size").intValue;

To draw our list we begin with a horizontal Layout and add a flexible spaces to each of the sides, so items will remain together even if we change the size of the editor.

EditorGUILayout.BeginHorizontal();	
GUILayout.FlexibleSpace();
//Insert code here
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();

Our last step is to add the list elements, to do that we will use a toggle for each element. The value of the toggle must ve reasigned to store the new value each time we check it into the editor.

EditorGUIUtility.labelWidth = 2;
for (int i = 0; i < size ; ++i)
{
	bitListProperty.GetArrayElementAtIndex(i).boolValue = EditorGUILayout.Toggle(" ",bitListProperty.GetArrayElementAtIndex(i).boolValue);
}

Five toggles will be created without name. By default the inspector reserve the name space even if we put it empty, to minimize the space reserve we can use labelWidth with a small value.

Finally this is the DataEditor code:

using UnityEngine;
using UnityEditor;
using System.Collections;

[CustomEditor(typeof(Data))]
public class DataEditor : Editor 
{
	/** Update with each inspector event*/
	public override void OnInspectorGUI () 
	{
	
		serializedObject.Update();
		EditorGUILayout.LabelField("Binary sequence");
		SerializedProperty sequenceProperty = serializedObject.FindProperty("sequence");
		
		SerializedProperty bitListProperty = sequenceProperty.FindPropertyRelative("bitList");
		SerializedProperty newSizeList = sequenceProperty.FindPropertyRelative("numBits");
		
		/** set default size */
		bitListProperty.FindPropertyRelative("Array.size").intValue = newSizeList.intValue;
		int size = bitListProperty.FindPropertyRelative("Array.size").intValue;
		
		EditorGUIUtility.labelWidth = 2;
		EditorGUILayout.BeginHorizontal();
		
		GUILayout.FlexibleSpace();
		for (int i = 0; i < size ; ++i)
		{
			bitListProperty.GetArrayElementAtIndex(i).boolValue = EditorGUILayout.Toggle(" ",bitListProperty.GetArrayElementAtIndex(i).boolValue);
		}
		GUILayout.FlexibleSpace();
		EditorGUILayout.EndHorizontal();

		serializedObject.ApplyModifiedProperties();
	}
}

Now, every time that we add the script Data to an object we can see:

customeditorlist2

 

download
Download

Spanish

En este tutorial vamos a explicar de manera sencilla como empezar un CustomEditor para Unity

Pero.. ¿cual es su utilidad?, ¿para que nos va a servir en nuestro proyecto?. Pues bien, un CustomEditor nos va a permitir modificar la representación que tiene nuestras clases en el Inspector de Unity. Esto nos va a facilitar trabajar con la clase del script que se asocia a los Gameobjects, prefabs, etc...

listbefore

Componente sin CustomEditor

 

imageafter

Componente con CustomEditor

 

Lo primero que hay que hacer, si es que no la tenemos ya, es crear una carpeta llamada Editor. Es una carpeta especial de Unity y de la que cargará automaticamente los scripts que van a modificar el comportamiento del UnityEditor. Los scripts que se incluyen en esta carpeta no se incluiran cuando generemos el juego, solo seran utilizados por el UnityEditor.

Vamos a crear otras cuantas carpetas a las que llamaremos Scripts y Scenes para ir dejando los scripts que si se van a utilizar en el juego y la escena en la que vamos guardando nuestro avance.

La estructura de directorios va a quedar asi:

Assets
  |_Editor
  |_Scripts
  |_Scenes

Empezaremos con un par de clases sencillas para ver como funciona el tema. Creamos un script nuevo en nuestra carpeta Scripts al que vamos a llamar Data.cs y le añadimos un par de clases 

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class BinarySequence
{
	public int numBits = 5;
	public List<bool> bitList;
}

public class Data : MonoBehaviour
{
	public BinarySequence sequence;
}

BinarySequence va a representar una lista de bits

Lo primero que necesitamos es hacer que la clase sea serializable, para ello añadimos la etiqueta [System.Serializable] encima de las clases, esto nos permitirá recuperar los atributos mas tarde en la clase del editor

using UnityEngine;
using System.Collections;
using System.Collections.Generic;


//The Serializable attribute lets you embed a class with sub properties in the inspector.
[System.Serializable]
public class BinarySequence
{
	public int numBits = 5;
	public List<bool> bitList;
}

[System.Serializable]
public class Data : MonoBehaviour
{
	public BinarySequence sequence;
}

Ahora nos ponemos por fin con nuestro custom editor.  Creamos un nuevo script en la carpeta Editor que llamaremos DataEditor y le añadimos using UnityEditor;.

  • Añadimos la etiqueta [CustomEditor(typeof(Data))] Con esta etiqueta le estamos diciendo que vamos a definir como se repreesenta la clase Data en el editor
  • Hacemos que al clase DataEditor herede de Editor

Ahora sobreescribimos OnInspectorGUI(), se le llamará si se produce un evento en el inspector:

using UnityEngine;
using UnityEditor;
using System.Collections;

[CustomEditor(typeof(Data))]
public class DataEditor : Editor 
{
	/** Update with each inspector event*/
	public override void OnInspectorGUI () 
	{
		//Insert code here
	}
}

Lo primero que añadimos al metodo sera:

		serializedObject.Update();  //actualiza el objeto en el que está serializado el objeto Data
// Insert code here
serializedObject.ApplyModifiedProperties(); //aplica las modificaciones que se le hallan hecho

Ya nos podemos poner con la GUI

Añadimos un texto informativo con LabelField

EditorGUILayout.LabelField("Binary sequence");

Accedemos al atributo sequence utilizando el nombre que le hemos dado al atributo con el objeto serializo y FindProperty

SerializedProperty sequenceProperty = serializedObject.FindProperty("sequence");

Para sacar los atributos de BinarySequence usamos el nombre del atributo pero esta vez FindPropertyRelative ya que vamos a utilizar la propiedad extraida anteriormente

SerializedProperty bitListProperty = sequenceProperty.FindPropertyRelative("bitList");
SerializedProperty newSizeList = sequenceProperty.FindPropertyRelative("numBits");

Al añadir el script Data a un objeto la lista se creará vacia y no veremos nada. Para cambiar esto le vamos a dar un tamaño inicial usando el atributo numBits de la clase BinarySequence.

La variable bitListProperty contiene un objeto serializado de tipo List, por lo tanto podemos acceder a atributos de List utilizando FindPropertyRelative de la misma manera que hemos hecho antes.

/** set default size */
bitListProperty.FindPropertyRelative("Array.size").intValue = newSizeList.intValue;
int size = bitListProperty.FindPropertyRelative("Array.size").intValue;

Para pintar la lista empezamos creando un Layout horizontal al que vamos a poner un espacio flexible a cada lado, de esta manera aunque cambie el tamaño del inspector los elementos de la lista se mantendrán juntos.

EditorGUILayout.BeginHorizontal();	
GUILayout.FlexibleSpace();
//Insert code here
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();

Por ultimo solo queda añadir los elementos de la lista, para ello vamos a utilizar un toggle por cada uno, sin olvidar que hay que asignarle el valor para que cuando seleccionemos el toggle este cambie su valor y se guarde.

EditorGUIUtility.labelWidth = 2;
for (int i = 0; i < size ; ++i)
{
	bitListProperty.GetArrayElementAtIndex(i).boolValue = EditorGUILayout.Toggle(" ",bitListProperty.GetArrayElementAtIndex(i).boolValue);
}

Con esto se crearan 5 toggles sin nombre. Por defecto el inspector reservará el espacio para el nombre aunque se lo pongamos vacio, para minimizarlo le definimos el labelWidth a un valor pequeño para que no ponga tanto espacio.

Finalmente DataEditor nos queda asi:

using UnityEngine;
using UnityEditor;
using System.Collections;

[CustomEditor(typeof(Data))]
public class DataEditor : Editor 
{
	/** Update with each inspector event*/
	public override void OnInspectorGUI () 
	{
	
		serializedObject.Update();
		EditorGUILayout.LabelField("Binary sequence");
		SerializedProperty sequenceProperty = serializedObject.FindProperty("sequence");
		
		SerializedProperty bitListProperty = sequenceProperty.FindPropertyRelative("bitList");
		SerializedProperty newSizeList = sequenceProperty.FindPropertyRelative("numBits");
		
		/** set default size */
		bitListProperty.FindPropertyRelative("Array.size").intValue = newSizeList.intValue;
		int size = bitListProperty.FindPropertyRelative("Array.size").intValue;
		
		EditorGUIUtility.labelWidth = 2;
		EditorGUILayout.BeginHorizontal();
		
		GUILayout.FlexibleSpace();
		for (int i = 0; i < size ; ++i)
		{
			bitListProperty.GetArrayElementAtIndex(i).boolValue = EditorGUILayout.Toggle(" ",bitListProperty.GetArrayElementAtIndex(i).boolValue);
		}
		GUILayout.FlexibleSpace();
		EditorGUILayout.EndHorizontal();

		serializedObject.ApplyModifiedProperties();
	}
}

Ahora cada vez que añadamos el script Data a un objeto veremos lo siguiente

customeditorlist2

 

download
Download

 

 

Read 1598 times Last modified on Sunday, 30 November 2014 11:10
Login to post comments

We use cookies to ensure that we give you the best experience on our website. If you continue without changing your settings, we'll assume that you are happy to receive all cookies. View policy