Ein Schlüssel zur Erhöhung der Geschwindigkeit bei der Erstellung von Spielen ist die Erstellung von benutzerdefinierten Editoren für häufig verwendete Komponenten. Als Beispiel verwenden wir dieses sehr einfache Skript, das ein Objekt immer auf einen Punkt zeigt. Fügen Sie dieses Skript zu Ihrem Projekt hinzu und platzieren Sie es auf einem Würfel-Spielobjekt in Ihrer Szene. Das Skript sollte den Namen „LookAtPoint“
//C# Example (LookAtPoint.cs)using UnityEngine;public class LookAtPoint : MonoBehaviour{ public Vector3 lookAtPoint = Vector3.zero; void Update() { transform.LookAt(lookAtPoint); }}
//JS Example (LookAtPoint.js)#pragma strictvar lookAtPoint = Vector3.zero;function Update(){ transform.LookAt(lookAtPoint);}
Damit wird ein Objekt immer auf einen Punkt im Weltraum ausgerichtet. Derzeit wird dieses Skript nur im Spielmodus aktiv, d.h. wenn das Spiel läuft. Beim Schreiben von Editor-Skripten ist es oft nützlich, dass bestimmte Skripte auch im Bearbeitungsmodus ausgeführt werden, während das Spiel nicht läuft. Man kann dies erreichen, indem man ein ExecuteInEditMode-Attribut hinzufügt:
//C# Example (LookAtPoint.cs)using UnityEngine;public class LookAtPoint : MonoBehaviour{ public Vector3 lookAtPoint = Vector3.zero; void Update() { transform.LookAt(lookAtPoint); }}
//JS Example (LookAtPoint.js)#pragma strict@script ExecuteInEditMode()var lookAtPoint = Vector3.zero;function Update(){ transform.LookAt(lookAtPoint);}
Wenn man nun das Objekt, das dieses Skript enthält, im Editor verschiebt oder die Werte von „Look At Point“ im Inspektor ändert – auch wenn es sich nicht im Spielmodus befindet – wird das Objekt seine Ausrichtung entsprechend aktualisieren, so dass es weiterhin auf den Zielpunkt im Weltraum schaut.
Einen eigenen Editor erstellen
Das obige Beispiel zeigt, wie man einfache Skripte während des Editierens laufen lassen kann, aber das allein erlaubt es nicht, eigene Editor-Tools zu erstellen. Der nächste Schritt besteht darin, einen benutzerdefinierten Editor für das soeben erstellte Skript zu erstellen.
Wenn Sie ein Skript in Unity erstellen, erbt es standardmäßig von MonoBehaviour und ist daher eine Komponente, die auf einem Spielobjekt platziert werden kann. Wenn es auf einem Spielobjekt platziert wird, zeigt der Inspektor eine Standardschnittstelle zum Anzeigen und Bearbeiten aller öffentlichen Variablen an, die angezeigt werden können – wie Integer, Floats, Strings, Vector3s usw.
So sieht der Standard-Inspector für unser obiges Skript aus:
Ein benutzerdefinierter Editor ist ein separates Skript, das dieses Standard-Layout durch beliebige Editor-Steuerelemente ersetzt.
Um mit der Erstellung des benutzerdefinierten Editors für unser LookAtPoint-Skript zu beginnen, sollten Sie ein weiteres Skript mit demselben Namen, aber mit angehängtem „Editor“ erstellen. Also für unser Beispiel: „LookAtPointEditor“.
//c# Example (LookAtPointEditor.cs)using UnityEngine;using UnityEditor;public class LookAtPointEditor : Editor { SerializedProperty lookAtPoint; void OnEnable() { lookAtPoint = serializedObject.FindProperty("lookAtPoint"); } public override void OnInspectorGUI() { serializedObject.Update(); EditorGUILayout.PropertyField(lookAtPoint); serializedObject.ApplyModifiedProperties(); }}
//JS Example (LookAtPointEditor.js)#pragma strict@CustomEditor(LookAtPoint)@CanEditMultipleObjectsclass LookAtPointEditor extends Editor { var lookAtPoint : SerializedProperty; function OnEnable() { lookAtPoint = serializedObject.FindProperty("lookAtPoint"); } function OnInspectorGUI() { serializedObject.Update(); EditorGUILayout.PropertyField(lookAtPoint); serializedObject.ApplyModifiedProperties(); }}
Diese Klasse muss von Editor abgeleitet werden. Das Attribut CustomEditor teilt Unity mit, für welche Komponente sie als Editor fungieren soll. Das CanEditMultipleObjects-Attribut teilt Unity mit, dass man mit diesem Editor mehrere Objekte auswählen und sie alle gleichzeitig ändern kann.
Der Code in OnInspectorGUI wird immer dann ausgeführt, wenn Unity den Editor im Inspector anzeigt. Sie können hier jeden beliebigen GUI-Code einfügen – er funktioniert genauso wie OnGUI für Spiele, wird aber innerhalb des Inspectors ausgeführt. Editor definiert die Zieleigenschaft, mit der Sie auf das zu inspizierende Objekt zugreifen können. So sieht unser benutzerdefinierter Inspektor aus:
Es ist nicht sehr interessant, denn alles, was wir bisher getan haben, ist, das Vector3-Feld neu zu erstellen, genau wie der Standard-Inspektor es uns zeigt, so dass das Ergebnis sehr ähnlich aussieht (obwohl das „Script“-Feld jetzt nicht vorhanden ist, weil wir keinen Inspektor-Code hinzugefügt haben, um es anzuzeigen).
Da Sie nun die Kontrolle darüber haben, wie der Inspektor in einem Editor-Skript angezeigt wird, können Sie jeden beliebigen Code verwenden, um die Inspektorfelder anzuordnen, dem Benutzer die Möglichkeit zu geben, die Werte anzupassen, und sogar Grafiken oder andere visuelle Elemente anzuzeigen. Alle Inspektoren, die im Unity-Editor angezeigt werden, einschließlich der komplexeren Inspektoren wie das Terrainsystem und die Einstellungen für den Animationsimport, werden über dieselbe API erstellt, auf die Sie Zugriff haben, wenn Sie Ihre eigenen benutzerdefinierten Editoren erstellen.
Hier ist ein einfaches Beispiel, das dein Editor-Skript erweitert, um eine Nachricht anzuzeigen, die angibt, ob sich der Zielpunkt über oder unter dem Spielobjekt befindet:
//c# Example (LookAtPointEditor.cs)using UnityEngine;using UnityEditor;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)"); } }}
//JS Example (LookAtPointEditor.js)#pragma strict@CustomEditor(LookAtPoint)@CanEditMultipleObjectsclass LookAtPointEditor extends Editor { var lookAtPoint : SerializedProperty; function OnEnable() { lookAtPoint = serializedObject.FindProperty("lookAtPoint"); } function 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, jetzt haben wir ein neues Element in unserem Inspektor, das eine Nachricht ausgibt, die anzeigt, ob sich der Zielpunkt über oder unter dem Spielobjekt befindet.
Dies ist nur ein kleiner Ausschnitt dessen, was du mit Editor-Skripten machen kannst. Sie haben vollen Zugriff auf alle IMGUI-Befehle, um jede Art von Oberfläche zu zeichnen, einschließlich des Renderns von Szenen mit einer Kamera innerhalb von Editor-Fenstern.
Szenenansicht-Ergänzungen
Sie können der Szenenansicht zusätzlichen Code hinzufügen, indem Sie ein OnSceneGUI in Ihrem benutzerdefinierten Editor implementieren.
OnSceneGUI funktioniert genauso wie OnInspectorGUI – nur wird es in der Szenenansicht ausgeführt. Um Ihnen zu helfen, Ihre eigenen Bearbeitungssteuerungen in der Szenenansicht zu erstellen, können Sie die in der Handles-Klasse definierten Funktionen verwenden. Alle darin enthaltenen Funktionen sind für die Arbeit in 3D-Szenenansichten konzipiert.
//C# Example (LookAtPointEditor.cs)using UnityEngine;using UnityEditor;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(); } }}
//JS Example (LookAtPointEditor.js)#pragma strict@CustomEditor(LookAtPointJS)@CanEditMultipleObjectsclass LookAtPointEditorJS extends Editor { var lookAtPoint : SerializedProperty; function OnEnable() { lookAtPoint = serializedObject.FindProperty("lookAtPoint"); } function OnInspectorGUI() { serializedObject.Update(); EditorGUILayout.PropertyField(lookAtPoint); serializedObject.ApplyModifiedProperties(); if (lookAtPoint.vector3Value.y > (target as LookAtPointJS).transform.position.y) { EditorGUILayout.LabelField("(Above this object)"); } if (lookAtPoint.vector3Value.y < (target as LookAtPointJS).transform.position.y) { EditorGUILayout.LabelField("(Below this object)"); } } function OnSceneGUI() { var t : LookAtPointJS = (target as LookAtPointJS); EditorGUI.BeginChangeCheck(); var pos = Handles.PositionHandle(t.lookAtPoint, Quaternion.identity); if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(target, "Move point"); t.lookAtPoint = pos; t.Update(); } }}
Wenn Sie 2D-GUI-Objekte (GUI, EditorGUI und Freunde) einfügen möchten, müssen Sie sie in Aufrufe von Handles.BeginGUI() und Handles.EndGUI() verpacken.