Una clave para aumentar la velocidad de creación de juego es crear editores personalizados para los componentes más utilizados. Por el bien del ejemplo, vamos a utilizar este simple script que siempre mantiene un objeto que mira un punto.
//C# Example (LookAtPoint.cs)
using UnityEngine;
public class LookAtPoint : MonoBehaviour
{
public Vector3 lookAtPoint = Vector3.zero;
void Update()
{
transform.LookAt(lookAtPoint);
}
}
This will keep an object oriented towards a world-space point. Currently this script will only become active in play mode, that is, when the game is running. When writing editor scripts it’s often useful to have certain scripts execute during edit mode too, while the game is not running. You can do this by adding an ExecuteInEditMode attribute to it:
//C# Example (LookAtPoint.cs)
using UnityEngine;
[ExecuteInEditMode]
public class LookAtPoint : MonoBehaviour
{
public Vector3 lookAtPoint = Vector3.zero;
void Update()
{
transform.LookAt(lookAtPoint);
}
}
Now if you move the object which has this script around in the editor, or change the values of “Look At Point” in the inspector - even when not in play mode - the object will update its orientation correspondingly so it remains looking at the target point in world space.
The above demonstrates how you can get simple scripts running during edit-time, however this alone does not allow you to create your own editor tools. The next step is to create a Custom Editor for script we just created.
When you create a script in Unity, by default it inherits from MonoBehaviour, and therefore is a Component which can be placed on a game object. When placed on a game object, the Inspector displays a default interface for viewing and editing all public variables that can be shown - such as integers, floats, strings, Vector3’s, etc.
Here’s how the default inspector looks for our script above:
A custom editor is a separate script which replaces this default layout with any editor controls that you choose.
To begin creating the custom editor for our LookAtPoint script, you should create another script with the same name, but with “Editor” appended. So for our example: “LookAtPointEditor”.
//c# Example (LookAtPointEditor.cs)
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(LookAtPoint))]
[CanEditMultipleObjects]
public class LookAtPointEditor : Editor
{
SerializedProperty lookAtPoint;
void OnEnable()
{
lookAtPoint = serializedObject.FindProperty("lookAtPoint");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(lookAtPoint);
serializedObject.ApplyModifiedProperties();
}
}
Esta clase debe derivar del Editor. El atributo @CustomEditor le informa a Unity qué componente debe actuar como un editor.
El código en el OnInspectorGUI es ejecutado cuándo Unity muestra el editor en el Inspector. Usted puede colocar cualquier código GUI aquí - funciona igual que OnGui hace para los juegos, pero se ejecuta en el interior del inspector. El Editor define la propiedad objetivo que usted puede utilizar para acceder el objeto siendo inspeccionado.
It’s not very interesting because all we have done so far is to recreate the Vector3 field, exactly like the default inspector shows us, so the result looks very similar (although the “Script” field is now not present, because we didn’t add any inspector code to show it).
However now that you have control over how the inspector is displayed in an Editor script, you can use any code you like to lay out the inspector fields, allow the user to adjust the values, and even display graphics or other visual elements. In fact all of the inspectors you see within the Unity Editor including the more complex inspectors such as the terrain system and animation import settings, are all made using the same API that you have access to when creating your own custom Editors.
Here’s a simple example which extends your editor script to display a message indicating whether the target point is above or below the gameobject:
//c# Example (LookAtPointEditor.cs)
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(LookAtPoint))]
[CanEditMultipleObjects]
public class LookAtPointEditor : Editor
{
SerializedProperty lookAtPoint;
void OnEnable()
{
lookAtPoint = serializedObject.FindProperty("lookAtPoint");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(lookAtPoint);
serializedObject.ApplyModifiedProperties();
if (lookAtPoint.vector3Value.y > (target as LookAtPoint).transform.position.y)
{
EditorGUILayout.LabelField("(Above this object)");
}
if (lookAtPoint.vector3Value.y < (target as LookAtPoint).transform.position.y)
{
EditorGUILayout.LabelField("(Below this object)");
}
}
}
So now we have an new element to our inspector which prints a message showing if the target point is above or below the gameobject.
This is just scratching the surface of what you can do with Editor scripting. You have full access to all the IMGUI commands to draw any type of interface, including rendering scenes using a camera within editor windows.
Usted puede agregar código adicional para el Scene View por la implementación de un OnSceneGUI en tu editor personalizado. En este caso, vamos a añadir un segundo juego de manillas de posición, dejando que los usuarios arrastren el puesto de observación en el punto alrededor del Scene View.
OnSceneGui funciona igual que OnInspectorGUI - excepto que es ejecutado en el scene view. Para ayudarlo hacer su interfaz de edición, usted puede utilizar las funciones definidas en la clase Handles. Todas las funciones ahí están diseñadas para trabajar en Scene Views 3D.
//C# Example (LookAtPointEditor.cs)
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(LookAtPoint))]
[CanEditMultipleObjects]
public class LookAtPointEditor : Editor
{
SerializedProperty lookAtPoint;
void OnEnable()
{
lookAtPoint = serializedObject.FindProperty("lookAtPoint");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(lookAtPoint);
if (lookAtPoint.vector3Value.y > (target as LookAtPoint).transform.position.y)
{
EditorGUILayout.LabelField("(Above this object)");
}
if (lookAtPoint.vector3Value.y < (target as LookAtPoint).transform.position.y)
{
EditorGUILayout.LabelField("(Below this object)");
}
serializedObject.ApplyModifiedProperties();
}
public void OnSceneGUI()
{
var t = (target as LookAtPoint);
EditorGUI.BeginChangeCheck();
Vector3 pos = Handles.PositionHandle(t.lookAtPoint, Quaternion.identity);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(target, "Move point");
t.lookAtPoint = pos;
t.Update();
}
}
}
Si usted quiere color objetos 2D GUI (GUI, EditorGUI y amigos), usted necesita envolverlos en llamadas a Handles.BeginGUI() y Handles.EndGUI().