En nyckel till att öka hastigheten på spelskapandet är att skapa anpassade redigerare för vanliga komponenter. Som exempel använder vi det här mycket enkla skriptet som alltid ser till att ett objekt tittar på en punkt. Lägg till det här skriptet i ditt projekt och placera det på ett cube gameobject i din scen. Skriptet ska heta ”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);}
Detta kommer att hålla ett objekt orienterat mot en punkt i världsrymden. För närvarande blir det här skriptet endast aktivt i spelläget, det vill säga när spelet körs. När man skriver redigeringsskript är det ofta användbart att ha vissa skript som exekveras under redigeringsläget också, medan spelet inte körs. Du kan göra detta genom att lägga till ett attribut ExecuteInEditMode till 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);}
Om du nu flyttar runt objektet som har det här skriptet i editorn, eller ändrar värdena för ”Look At Point” i inspektorn – även när det inte är i spelläge – kommer objektet att uppdatera sin orientering på motsvarande sätt, så att det fortsätter att titta på målpunkten i världsrymden.
Makning av en egen editor
Ovanstående visar hur du kan få enkla skript att köras under redigeringstid, men detta i sig gör det inte möjligt att skapa egna editorverktyg. Nästa steg är att skapa en Custom Editor för skriptet vi just skapat.
När du skapar ett skript i Unity ärver det som standard från MonoBehaviour och är därför en Component som kan placeras på ett spelobjekt. När den placeras på ett spelobjekt visar Inspector ett standardgränssnitt för visning och redigering av alla offentliga variabler som kan visas – t.ex. heltal, floats, strängar, Vector3:s osv.
Så här ser standardinspektorn ut för vårt skript ovan:
En anpassad redigerare är ett separat skript som ersätter den här standardlayouten med de redigeringskontroller som du väljer.
För att börja skapa den anpassade redigeraren för vårt LookAtPoint-skript bör du skapa ett annat skript med samma namn, men med ”Editor” tillagt. Så för vårt exempel: ”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(); }}
Denna klass måste härstamma från Editor. Egenskapen CustomEditor informerar Unity om vilken komponent den ska fungera som redaktör för. Attributet CanEditMultipleObjects talar om för Unity att du kan välja flera objekt med den här editorn och ändra dem alla samtidigt.
Koden i OnInspectorGUI exekveras när Unity visar editorn i inspektorn. Du kan lägga in vilken GUI-kod som helst här – den fungerar precis som OnGUI gör för spel, men körs inne i inspektorn. Editor definierar den målegenskap som du kan använda för att komma åt det objekt som inspekteras. Så här ser vår anpassade inspektor ut:
Det är inte särskilt intressant eftersom allt vi har gjort hittills är att återskapa Vector3-fältet, precis som standardinspektören visar oss, så resultatet ser mycket likadant ut (även om ”Script”-fältet nu inte finns med, eftersom vi inte lagt till någon inspektörskod för att visa det).
Men nu när du har kontroll över hur inspektorn visas i ett Editor-skript kan du använda vilken kod du vill för att lägga ut inspektorfälten, låta användaren justera värdena och till och med visa grafik eller andra visuella element. Faktum är att alla inspektörer som du ser i Unity Editor, inklusive de mer komplexa inspektörerna som t.ex. terrängsystemet och importinställningarna för animationer, alla görs med hjälp av samma API som du har tillgång till när du skapar dina egna anpassade Editors.
Här är ett enkelt exempel som utökar ditt editorscript för att visa ett meddelande som visar om målpunkten är över eller under gameobject:
//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 ett nytt element till vår inspektor som skriver ut ett meddelande som visar om målpunkten är över eller under gameobject.
Det här är bara att skrapa på ytan av vad du kan göra med Editor scripting. Du har full tillgång till alla IMGUI-kommandon för att rita alla typer av gränssnitt, inklusive rendering av scener med hjälp av en kamera i redigeringsfönstren.
Scenvyns tillägg
Du kan lägga till extra kod till scenvyn genom att implementera en OnSceneGUI i din anpassade editor.
OnSceneGUI fungerar precis som OnInspectorGUI – förutom att den körs i scenvyn. För att hjälpa dig att skapa egna redigeringskontroller i scenvyn kan du använda de funktioner som definieras i klassen Handles. Alla funktioner där är utformade för att arbeta i 3D-scenevyer.
//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(); } }}
Om du vill placera 2D GUI-objekt (GUI, EditorGUI och vänner) måste du linda in dem i anrop till Handles.BeginGUI() och Handles.EndGUI().