Una chiave per aumentare la velocità di creazione del gioco è creare editor personalizzati per i componenti comunemente usati. Per fare un esempio, useremo questo script molto semplice che mantiene sempre un oggetto in un punto. Aggiungete questo script al vostro progetto e posizionatelo su un gameobject cubo nella vostra scena. Lo script dovrebbe chiamarsi “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);}
Questo terrà un oggetto orientato verso un punto dello spazio-mondo. Attualmente questo script sarà attivo solo in modalità di gioco, cioè quando il gioco è in esecuzione. Quando si scrivono gli script dell’editor è spesso utile far eseguire certi script anche durante la modalità di modifica, mentre il gioco non è in esecuzione. Puoi farlo aggiungendo un attributo ExecuteInEditMode:
//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);}
Ora se sposti l’oggetto che ha questo script nell’editor, o cambi i valori di “Look At Point” nell’ispettore – anche quando non è in modalità di gioco – l’oggetto aggiornerà il suo orientamento di conseguenza, in modo che continui a guardare il punto di destinazione nello spazio del mondo.
Creare un editor personalizzato
Quanto detto sopra dimostra come puoi far girare semplici script durante la modifica, tuttavia questo da solo non ti permette di creare i tuoi strumenti editor. Il prossimo passo è quello di creare un editor personalizzato per lo script appena creato.
Quando si crea uno script in Unity, per default eredita da MonoBehaviour, e quindi è un componente che può essere posizionato su un oggetto di gioco. Quando è posizionato su un oggetto di gioco, l’Inspector mostra un’interfaccia predefinita per visualizzare e modificare tutte le variabili pubbliche che possono essere mostrate – come interi, float, stringhe, Vector3, ecc.
Ecco come appare l’Inspector di default per il nostro script sopra:
Un editor personalizzato è uno script separato che sostituisce questo layout di default con qualsiasi controllo editor che si sceglie.
Per iniziare a creare l’editor personalizzato per il nostro script LookAtPoint, si dovrebbe creare un altro script con lo stesso nome, ma con “Editor” aggiunto. Così per il nostro esempio: “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(); }}
Questa classe deve derivare da Editor. L’attributo CustomEditor informa Unity per quale componente dovrebbe agire come editor. L’attributo CanEditMultipleObjects dice a Unity che puoi selezionare più oggetti con questo editor e cambiarli tutti allo stesso tempo.
Il codice in OnInspectorGUI viene eseguito ogni volta che Unity visualizza l’editor nell’Inspector. Puoi mettere qualsiasi codice GUI qui dentro – funziona proprio come OnGUI per i giochi, ma viene eseguito all’interno dell’Inspector. Editor definisce la proprietà di destinazione che è possibile utilizzare per accedere all’oggetto ispezionato. Ecco come appare il nostro ispettore personalizzato:
Non è molto interessante perché tutto quello che abbiamo fatto finora è stato ricreare il campo Vector3, esattamente come ci mostra l’ispettore predefinito, quindi il risultato sembra molto simile (anche se il campo “Script” ora non è presente, perché non abbiamo aggiunto alcun codice dell’ispettore per mostrarlo).
Ora però che hai il controllo su come l’ispettore viene mostrato in uno script Editor, puoi usare qualsiasi codice tu voglia per disporre i campi dell’ispettore, permettere all’utente di regolare i valori e persino mostrare grafici o altri elementi visivi. Infatti tutti gli ispettori che vedete all’interno dell’Editor di Unity, compresi gli ispettori più complessi come il sistema del terreno e le impostazioni di importazione delle animazioni, sono tutti realizzati utilizzando la stessa API a cui avete accesso quando create i vostri editor personalizzati.
Ecco un semplice esempio che estende lo script dell’editor per mostrare un messaggio che indica se il punto di destinazione è sopra o sotto l’oggetto del gioco:
//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)"); } }}
Ora abbiamo un nuovo elemento per il nostro ispettore che stampa un messaggio che mostra se il punto di destinazione è sopra o sotto l’oggetto del gioco.
Questo è solo un esempio di ciò che si può fare con lo script dell’editor. Hai pieno accesso a tutti i comandi IMGUI per disegnare qualsiasi tipo di interfaccia, incluso il rendering delle scene usando una telecamera all’interno delle finestre dell’editor.
Addizioni alla Vista Scena
Puoi aggiungere codice extra alla Vista Scena implementando un OnSceneGUI nel tuo editor personalizzato.
OnSceneGUI funziona proprio come OnInspectorGUI – tranne che viene eseguito nella vista scena. Per aiutarvi a creare i vostri controlli di editing nella vista della scena, potete usare le funzioni definite nella classe Handles. Tutte le funzioni lì dentro sono progettate per lavorare nelle viste di scena 3D.
//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(); } }}
Se vuoi mettere oggetti GUI 2D (GUI, EditorGUI e amici), devi avvolgerli nelle chiamate a Handles.BeginGUI() e Handles.EndGUI().