Une clé pour augmenter la vitesse de création d’un jeu est de créer des éditeurs personnalisés pour les composants couramment utilisés. Pour les besoins de l’exemple, nous utiliserons ce script très simple qui garde toujours un objet regardant un point. Ajoutez ce script à votre projet, et placez-le sur un objet de jeu de type cube dans votre scène. Le script doit être nommé « 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);}
Ceci gardera un objet orienté vers un point de l’espace mondial. Actuellement, ce script ne sera actif qu’en mode jeu, c’est-à-dire lorsque le jeu est en cours d’exécution. Lorsque vous écrivez des scripts d’éditeur, il est souvent utile de faire en sorte que certains scripts s’exécutent également en mode édition, lorsque le jeu n’est pas en cours d’exécution. Vous pouvez le faire en lui ajoutant un attribut 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);}
Maintenant, si vous déplacez l’objet qui a ce script dans l’éditeur, ou si vous changez les valeurs de « Look At Point » dans l’inspecteur – même quand il n’est pas en mode jeu – l’objet mettra à jour son orientation en conséquence pour qu’il continue à regarder le point cible dans l’espace monde.
Faire un éditeur personnalisé
Ce qui précède démontre comment vous pouvez obtenir des scripts simples s’exécutant pendant le temps d’édition, cependant cela seul ne vous permet pas de créer vos propres outils d’éditeur. L’étape suivante consiste à créer un éditeur personnalisé pour le script que nous venons de créer.
Lorsque vous créez un script dans Unity, par défaut il hérite de MonoBehaviour, et est donc un composant qui peut être placé sur un objet de jeu. Lorsqu’il est placé sur un objet de jeu, l’inspecteur affiche une interface par défaut pour visualiser et modifier toutes les variables publiques qui peuvent être affichées – comme les entiers, les flottants, les chaînes de caractères, les Vector3, etc.
Voici à quoi ressemble l’inspecteur par défaut pour notre script ci-dessus :
Un éditeur personnalisé est un script séparé qui remplace cette disposition par défaut avec n’importe quels contrôles d’éditeur que vous choisissez.
Pour commencer à créer l’éditeur personnalisé pour notre script LookAtPoint, vous devez créer un autre script avec le même nom, mais avec « Editor » en annexe. Donc, pour notre exemple : « 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(); }}
Cette classe doit dériver de Editor. L’attribut CustomEditor informe Unity du composant pour lequel elle doit agir en tant qu’éditeur. L’attribut CanEditMultipleObjects indique à Unity que vous pouvez sélectionner plusieurs objets avec cet éditeur et les modifier tous en même temps.
Le code dans OnInspectorGUI est exécuté chaque fois que Unity affiche l’éditeur dans l’inspecteur. Vous pouvez mettre n’importe quel code d’interface graphique ici – il fonctionne exactement comme OnGUI pour les jeux, mais il est exécuté à l’intérieur de l’Inspecteur. L’éditeur définit la propriété cible que vous pouvez utiliser pour accéder à l’objet inspecté. Voici à quoi ressemble notre inspecteur personnalisé :
Ce n’est pas très intéressant car tout ce que nous avons fait jusqu’à présent est de recréer le champ Vector3, exactement comme l’inspecteur par défaut nous le montre, donc le résultat est très similaire (bien que le champ « Script » ne soit maintenant pas présent, car nous n’avons pas ajouté de code d’inspecteur pour le montrer).
Mais maintenant que vous avez le contrôle sur la façon dont l’inspecteur est affiché dans un script d’éditeur, vous pouvez utiliser le code que vous voulez pour disposer les champs de l’inspecteur, permettre à l’utilisateur d’ajuster les valeurs, et même afficher des graphiques ou d’autres éléments visuels. En fait, tous les inspecteurs que vous voyez dans l’éditeur Unity, y compris les inspecteurs plus complexes tels que le système de terrain et les paramètres d’importation d’animation, sont tous réalisés en utilisant la même API à laquelle vous avez accès lorsque vous créez vos propres éditeurs personnalisés.
Voici un exemple simple qui étend votre script d’éditeur pour afficher un message indiquant si le point cible est au-dessus ou en dessous de l’objet de jeu:
//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)"); } }}
Donc maintenant nous avons un nouvel élément à notre inspecteur qui imprime un message montrant si le point cible est au-dessus ou en dessous de l’objet de jeu.
Ce n’est qu’effleurer la surface de ce que vous pouvez faire avec le script d’éditeur. Vous avez un accès complet à toutes les commandes IMGUI pour dessiner n’importe quel type d’interface, y compris le rendu de scènes en utilisant une caméra dans les fenêtres de l’éditeur.
Ajouts à la vue de la scène
Vous pouvez ajouter du code supplémentaire à la vue de la scène en implémentant un OnSceneGUI dans votre éditeur personnalisé.
OnSceneGUI fonctionne exactement comme OnInspectorGUI – sauf qu’il est exécuté dans la vue de la scène. Pour vous aider à faire vos propres contrôles d’édition dans la vue de la scène, vous pouvez utiliser les fonctions définies dans la classe Handles. Toutes les fonctions qui s’y trouvent sont conçues pour travailler dans des vues de scènes 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(); } }}
Si vous voulez mettre des objets d’interface graphique 2D (GUI, EditorGUI et amis), vous devez les envelopper dans des appels à Handles.BeginGUI() et Handles.EndGUI().