En nøgle til at øge hastigheden på spiloprettelsen er at oprette brugerdefinerede editorer til almindeligt anvendte komponenter. For eksemplets skyld bruger vi dette meget enkle script, der altid lader et objekt se på et punkt. Tilføj dette script til dit projekt, og placer det på et cube gameobject i din scene. Scriptet skal hedde “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);}
Dette vil holde et objekt orienteret mod et punkt i verdensrummet. På nuværende tidspunkt vil dette script kun blive aktivt i play mode, dvs. når spillet kører. Når man skriver editor-scripts er det ofte nyttigt at have visse scripts, der også udføres i redigeringstilstand, mens spillet ikke kører. Du kan gøre dette ved at tilføje en ExecuteInEditMode-attribut til det:
//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);}
Nu, hvis du flytter objektet, som har dette script, rundt i editoren, eller ændrer værdierne for “Look At Point” i inspektøren – selv når det ikke er i spiltilstand – vil objektet opdatere sin orientering tilsvarende, så det fortsat kigger på målpunktet i verdensrummet.
Makning af en brugerdefineret editor
Overstående demonstrerer, hvordan du kan få simple scripts til at køre under redigeringstid, men dette alene giver dig ikke mulighed for at skabe dine egne editor-værktøjer. Det næste skridt er at oprette en Custom Editor til det script, vi lige har oprettet.
Når du opretter et script i Unity, arver det som standard fra MonoBehaviour, og er derfor en Component, som kan placeres på et spilobjekt. Når den er placeret på et spilobjekt, viser Inspector en standardgrænseflade til visning og redigering af alle offentlige variabler, der kan vises – såsom integers, floats, strings, Vector3’s osv.
Sådan ser standardinspektøren ud for vores ovenstående script:
En brugerdefineret editor er et separat script, som erstatter dette standardlayout med de editor-kontroller, som du vælger.
For at begynde at oprette den brugerdefinerede editor til vores LookAtPoint-script skal du oprette et andet script med samme navn, men med “Editor” tilføjet. Så for vores eksempel: “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(); }}
Denne klasse skal aflede fra Editor. CustomEditor-attributten oplyser Unity om, hvilken komponent den skal fungere som editor for. Attributten CanEditMultipleObjects fortæller Unity, at du kan vælge flere objekter med denne editor og ændre dem alle på samme tid.
Koden i OnInspectorGUI udføres, når Unity viser editoren i inspektøren. Du kan sætte enhver GUI-kode ind her – den fungerer ligesom OnGUI gør for spil, men den køres inde i Inspector. Editor definerer den target-egenskab, som du kan bruge til at få adgang til det objekt, der inspiceres. Sådan ser vores brugerdefinerede inspektor ud:
Det er ikke særlig interessant, for det eneste vi har gjort indtil videre er at genskabe Vector3-feltet, præcis som standardinspektøren viser os, så resultatet ligner meget (selv om feltet “Script” nu ikke er til stede, fordi vi ikke har tilføjet nogen inspektørkode til at vise det).
Men nu, hvor du har kontrol over, hvordan inspektøren vises i et Editor-script, kan du bruge hvilken som helst kode, du vil, til at lægge inspektørfelterne ud, give brugeren mulighed for at justere værdierne og endda vise grafik eller andre visuelle elementer. Faktisk er alle de inspektører, du ser i Unity Editor, herunder de mere komplekse inspektører som f.eks. terrænsystemet og indstillingerne for animationsimport, alle lavet ved hjælp af den samme API, som du har adgang til, når du opretter dine egne brugerdefinerede Editors.
Her er et simpelt eksempel, som udvider dit editor-script til at vise en meddelelse, der angiver, om målpunktet er over eller under gameobjectet:
//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)"); } }}
Så nu har vi et nyt element til vores inspektor, som udskriver en meddelelse, der viser, om målpunktet er over eller under gameobjectet.
Dette er blot at skrabe på overfladen af, hvad du kan gøre med Editor-scripting. Du har fuld adgang til alle IMGUI-kommandoer til at tegne enhver type grænseflade, herunder rendering af scener ved hjælp af et kamera i editorvinduer.
Scene View Additions
Du kan tilføje ekstra kode til Scene View ved at implementere en OnSceneGUI i din brugerdefinerede editor.
OnSceneGUI fungerer ligesom OnInspectorGUI – bortset fra at den bliver kørt i scenevisningen. For at hjælpe dig med at lave dine egne redigeringskontroller i scenevisningen kan du bruge de funktioner, der er defineret i Handles-klassen. Alle funktioner deri er designet til at arbejde i 3D-scenevisninger.
//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(); } }}
Hvis du ønsker at placere 2D GUI-objekter (GUI, EditorGUI og venner), skal du pakke dem ind i kald til Handles.BeginGUI() og Handles.EndGUI().