Zoeken…


Syntaxis

  • [MenuItem (string itemName)]
  • [MenuItem (string itemName, bool isValidateFunction)]
  • [MenuItem (string itemName, bool isValidateFunction, int prioriteit)]
  • [ContextMenu (stringnaam)]
  • [ContextMenuItem (stringnaam, stringfunctie)]
  • [DrawGizmo (GizmoType gizmo)]
  • [DrawGizmo (GizmoType gizmo, Type drawnGizmoType)]

parameters

Parameter Details
MenuCommand MenuCommand wordt gebruikt om de context voor een MenuItem te extraheren
MenuCommand.context Het object dat het doel is van de menuopdracht
MenuCommand.userData Een int voor het doorgeven van aangepaste informatie aan een menu-item

Aangepaste inspecteur

Met een aangepaste infovenster kunt u de manier wijzigen waarop een script wordt getekend in de infovenster. Soms wilt u extra informatie in de infovenster voor uw script toevoegen die niet mogelijk is met een aangepaste eigenschappenlade.

Hieronder ziet u een eenvoudig voorbeeld van een aangepast object dat met behulp van een aangepaste inspecteur meer nuttige informatie kan weergeven.

using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

public class InspectorExample : MonoBehaviour {

    public int Level;
    public float BaseDamage;

    public float DamageBonus {
        get {
            return Level / 100f * 50;
        }
    }

    public float ActualDamage {
        get {
            return BaseDamage + DamageBonus;
        }
    }
}

#if UNITY_EDITOR
[CustomEditor( typeof( InspectorExample ) )]
public class CustomInspector : Editor {

    public override void OnInspectorGUI() {
        base.OnInspectorGUI();

        var ie = (InspectorExample)target;

        EditorGUILayout.LabelField( "Damage Bonus", ie.DamageBonus.ToString() );
        EditorGUILayout.LabelField( "Actual Damage", ie.ActualDamage.ToString() );
    }
}
#endif

Eerst definiëren we ons aangepaste gedrag met sommige velden

public class InspectorExample : MonoBehaviour {
    public int Level;
    public float BaseDamage;
}

De hierboven weergegeven velden worden automatisch getekend (zonder aangepaste inspector) wanneer u het script in het Inspector-venster bekijkt.

public float DamageBonus {
    get {
        return Level / 100f * 50;
    }
}

public float ActualDamage {
    get {
        return BaseDamage + DamageBonus;
    }
}

Deze eigenschappen worden niet automatisch door Unity getekend. Om deze eigenschappen in de Inspector-weergave te tonen, moeten we onze Custom Inspector gebruiken.

We moeten eerst onze aangepaste inspecteur als volgt definiëren

[CustomEditor( typeof( InspectorExample ) )]
public class CustomInspector : Editor {

De aangepaste inspector moet afkomstig zijn van Editor en heeft het kenmerk CustomEditor nodig . De parameter van het kenmerk is het type object waarvoor deze aangepaste infovenster moet worden gebruikt.

De volgende stap is de OnInspectorGUI-methode. Deze methode wordt aangeroepen wanneer het script in het infovenster wordt weergegeven.

public override void OnInspectorGUI() {
    base.OnInspectorGUI();
}

We doen een beroep op base.OnInspectorGUI () om Unity de andere velden in het script te laten behandelen. Als we dit niet zouden noemen, zouden we zelf meer werk moeten doen.

Hierna volgen onze aangepaste eigenschappen die we willen laten zien

var ie = (InspectorExample)target;

EditorGUILayout.LabelField( "Damage Bonus", ie.DamageBonus.ToString() );
EditorGUILayout.LabelField( "Actual Damage", ie.ActualDamage.ToString() );

We moeten een tijdelijke variabele maken die het doel cast voor ons aangepaste type (doel is beschikbaar omdat we het hebben van Editor).

Vervolgens kunnen we beslissen hoe onze eigenschappen worden getekend, in dit geval zijn twee labelfields voldoende, omdat we alleen de waarden willen tonen en ze niet kunnen bewerken.

Resultaat

Voordat

resultaat eerder

Na

resultaat na

Aangepaste eigenschappenlade

Soms hebt u aangepaste objecten die gegevens bevatten, maar niet afkomstig zijn van MonoBehaviour. Het toevoegen van deze objecten als een veld in een klasse die MonoBehaviour is, heeft geen visueel effect, tenzij u uw eigen aangepaste eigenschappenlade schrijft voor het type object.

Hieronder is een eenvoudig voorbeeld van een aangepast object, toegevoegd aan MonoBehaviour, en een aangepaste eigenschappenlade voor het aangepaste object.

public enum Gender {
    Male,
    Female,
    Other
}

// Needs the Serializable attribute otherwise the CustomPropertyDrawer wont be used
[Serializable]
public class UserInfo {
    public string Name;
    public int Age;
    public Gender Gender;
}

// The class that you can attach to a GameObject
public class PropertyDrawerExample : MonoBehaviour {
    public UserInfo UInfo;
}

[CustomPropertyDrawer( typeof( UserInfo ) )]
public class UserInfoDrawer : PropertyDrawer {

    public override float GetPropertyHeight( SerializedProperty property, GUIContent label ) {
        // The 6 comes from extra spacing between the fields (2px each)
        return EditorGUIUtility.singleLineHeight * 4 + 6;
    }

    public override void OnGUI( Rect position, SerializedProperty property, GUIContent label ) {
        EditorGUI.BeginProperty( position, label, property );

        EditorGUI.LabelField( position, label );

        var nameRect = new Rect( position.x, position.y + 18, position.width, 16 );
        var ageRect = new Rect( position.x, position.y + 36, position.width, 16 );
        var genderRect = new Rect( position.x, position.y + 54, position.width, 16 );

        EditorGUI.indentLevel++;

        EditorGUI.PropertyField( nameRect, property.FindPropertyRelative( "Name" ) );
        EditorGUI.PropertyField( ageRect, property.FindPropertyRelative( "Age" ) );
        EditorGUI.PropertyField( genderRect, property.FindPropertyRelative( "Gender" ) );

        EditorGUI.indentLevel--;

        EditorGUI.EndProperty();
    }
}

Eerst definiëren we het aangepaste object met al zijn vereisten. Gewoon een eenvoudige klasse die een gebruiker beschrijft. Deze klasse wordt gebruikt in onze PropertyDrawerExample-klasse die we kunnen toevoegen aan een GameObject.

public enum Gender {
    Male,
    Female,
    Other
}

[Serializable]
public class UserInfo {
    public string Name;
    public int Age;
    public Gender Gender;
}

public class PropertyDrawerExample : MonoBehaviour {
    public UserInfo UInfo;
}

De aangepaste klasse heeft het kenmerk Serializable nodig, anders wordt de CustomPropertyDrawer niet gebruikt

De volgende stap is de CustomPropertyDrawer

Eerst moeten we een klasse definiëren die afkomstig is van PropertyDrawer. De klassedefinitie heeft ook het kenmerk CustomPropertyDrawer nodig. De doorgegeven parameter is het type object waarvoor u deze lade wilt gebruiken.

[CustomPropertyDrawer( typeof( UserInfo ) )]
public class UserInfoDrawer : PropertyDrawer {

Vervolgens negeren we de functie GetPropertyHeight. Hiermee kunnen we een aangepaste hoogte voor ons eigendom definiëren. In dit geval weten we dat ons eigendom uit vier delen zal bestaan: label, naam, leeftijd en geslacht. Daarom gebruiken we EditorGUIUtility.singleLineHeight * 4 , we voegen nog 6 pixels toe omdat we elk veld met twee pixels ertussen willen plaatsen.

public override float GetPropertyHeight( SerializedProperty property, GUIContent label ) {
    return EditorGUIUtility.singleLineHeight * 4 + 6;
}

Hierna volgt de werkelijke OnGUI-methode. We beginnen met EditorGUI.BeginProperty ([...]) en eindigen de functie met EditorGUI.EndProperty () . We doen dit zodat als deze eigenschap onderdeel zou zijn van een prefab, de werkelijke prefab-overheersende logica zou werken voor alles tussen deze twee methoden.

public override void OnGUI( Rect position, SerializedProperty property, GUIContent label ) {
    EditorGUI.BeginProperty( position, label, property );

Daarna tonen we een label met de naam van het veld en definiëren we al de rechthoeken voor onze velden.

EditorGUI.LabelField( position, label );

var nameRect = new Rect( position.x, position.y + 18, position.width, 16 );
var ageRect = new Rect( position.x, position.y + 36, position.width, 16 );
var genderRect = new Rect( position.x, position.y + 54, position.width, 16 );

Elk veld wordt op een afstand van 16 + 2 pixels geplaatst en de hoogte is 16 (wat hetzelfde is als EditorGUIUtility.singleLineHeight)

Vervolgens laten we de gebruikersinterface inspringen met één tabblad voor een iets mooiere lay-out, geven de eigenschappen weer, laten de GUI niet meer inspringen en eindigen met EditorGUI.EndProperty .

EditorGUI.indentLevel++;

EditorGUI.PropertyField( nameRect, property.FindPropertyRelative( "Name" ) );
EditorGUI.PropertyField( ageRect, property.FindPropertyRelative( "Age" ) );
EditorGUI.PropertyField( genderRect, property.FindPropertyRelative( "Gender" ) );

EditorGUI.indentLevel--;

EditorGUI.EndProperty();

We tonen de velden met behulp van EditorGUI.PropertyField waarvoor een rechthoek nodig is voor de positie en een SerializedProperty om de eigenschap weer te geven. We verwerven de eigenschap door FindPropertyRelative ("...") aan te roepen op de eigenschap die is doorgegeven in de functie OnGUI . Merk op dat dit hoofdlettergevoelig is en dat niet-openbare eigenschappen niet kunnen worden gevonden!

Voor dit voorbeeld sla ik de eigenschappen-return van property.FindPropertyRelative ("...") niet op. U moet deze opslaan in privévelden in de klas om onnodige oproepen te voorkomen

Resultaat

Voordat

Resultaat eerder

Na

Resultaat na

Menu-items zijn een geweldige manier om aangepaste acties toe te voegen aan de editor. U kunt menu-items toevoegen aan de menubalk, ze laten klikken als context-klikken op specifieke componenten, of zelfs als context-klikken op velden in uw scripts.

Hieronder ziet u een voorbeeld van hoe u menu-items kunt toepassen.

public class MenuItemsExample : MonoBehaviour {

    [MenuItem( "Example/DoSomething %#&d" )]
    private static void DoSomething() {
        // Execute some code
    }

    [MenuItem( "Example/DoAnotherThing", true )]
    private static bool DoAnotherThingValidator() {
        return Selection.gameObjects.Length > 0;
    }

    [MenuItem( "Example/DoAnotherThing _PGUP", false )]
    private static void DoAnotherThing() {
        // Execute some code
    }

    [MenuItem( "Example/DoOne %a", false, 1 )]
    private static void DoOne() {
        // Execute some code
    }

    [MenuItem( "Example/DoTwo #b", false, 2 )]
    private static void DoTwo() {
        // Execute some code
    }

    [MenuItem( "Example/DoFurther &c", false, 13 )]
    private static void DoFurther() {
        // Execute some code
    }

    [MenuItem( "CONTEXT/Camera/DoCameraThing" )]
    private static void DoCameraThing( MenuCommand cmd ) {
        // Execute some code
    }

    [ContextMenu( "ContextSomething" )]
    private void ContentSomething() {
        // Execute some code
    }

    [ContextMenuItem( "Reset", "ResetDate" )]
    [ContextMenuItem( "Set to Now", "SetDateToNow" )]
    public string Date = "";

    public void ResetDate() {
        Date = "";
    }

    public void SetDateToNow() {
        Date = DateTime.Now.ToString();
    }
}

Dat ziet er zo uit

werkbalkmenu

Laten we het basismenu-item doornemen. Zoals u hieronder kunt zien, moet u een statische functie definiëren met een kenmerk MenuItem , waaraan u een string doorgeeft als titel voor het menu-item. U kunt uw menu-item meerdere niveaus diep zetten door een / in de naam toe te voegen.

[MenuItem( "Example/DoSomething %#&d" )]
private static void DoSomething() {
    // Execute some code
}

U kunt geen menu-item op het hoogste niveau hebben. Uw menu-items moeten in een submenu staan!

De speciale tekens aan het einde van de naam van het menu-item zijn voor sneltoetsen, dit zijn geen vereisten.

Er zijn speciale tekens die u kunt gebruiken voor uw sneltoetsen, deze zijn:

  • % - Ctrl op Windows, Cmd op OS X
  • # - Shift
  • & - Alt

Dat betekent dat de snelkoppeling % # & d staat voor ctrl + shift + alt + D op Windows en cmd + shift + alt + D op OS X.

Als u een sneltoets zonder speciale toetsen wilt gebruiken, dus bijvoorbeeld alleen de 'D'-toets, kunt u het teken _ (onderstrepingsteken) voor de sneltoets plaatsen die u wilt gebruiken.

Er zijn enkele andere speciale toetsen die worden ondersteund, zoals:

  • LINKS, RECHTS, OMHOOG, OMLAAG - voor de pijltjestoetsen
  • F1..F12 - voor de functietoetsen
  • HOME, END, PGUP, PGDN - voor de navigatietoetsen

Sneltoetsen moeten worden gescheiden van andere tekst met een spatie

Hierna volgen validator menu-items. Met Validator-menu-items kunnen menu-items worden uitgeschakeld (grijs, niet klikbaar) wanneer niet aan de voorwaarde is voldaan. Een voorbeeld hiervan kan zijn dat uw menu-item werkt op de huidige selectie van GameObjects, die u kunt controleren in het menu-item van de validator.

[MenuItem( "Example/DoAnotherThing", true )]
private static bool DoAnotherThingValidator() {
    return Selection.gameObjects.Length > 0;
}

[MenuItem( "Example/DoAnotherThing _PGUP", false )]
private static void DoAnotherThing() {
    // Execute some code
}

Om een menu-item van de validator te laten werken, moet u twee statische functies maken, beide met het kenmerk MenuItem en dezelfde naam (sneltoets maakt niet uit). Het verschil is dat u ze markeert als een validatorfunctie of niet door een booleaanse parameter door te geven.

U kunt ook de volgorde van de menu-items definiëren door een prioriteit toe te voegen. De prioriteit wordt gedefinieerd door een geheel getal dat u als derde parameter doorgeeft. Hoe kleiner het getal hoe hoger in de lijst, hoe groter het getal hoe lager in de lijst. U kunt een scheidingsteken tussen twee menu-items toevoegen door ervoor te zorgen dat er ten minste 10 cijfers tussen de prioriteit van de menu-items staan.

[MenuItem( "Example/DoOne %a", false, 1 )]
private static void DoOne() {
    // Execute some code
}

[MenuItem( "Example/DoTwo #b", false, 2 )]
private static void DoTwo() {
    // Execute some code
}

[MenuItem( "Example/DoFurther &c", false, 13 )]
private static void DoFurther() {
    // Execute some code
}

Als u een menulijst hebt met een combinatie van items met prioriteit en niet-prioriteit, worden de niet-prioriteit gescheiden van de prioriteit.

Vervolgens wordt een menu-item toegevoegd aan het contextmenu van een reeds bestaand onderdeel. U moet de naam van het menu-item starten met CONTEXT (hoofdlettergevoelig) en uw functie een parameter MenuCommand laten opnemen.

Het volgende fragment voegt een contextmenu-item toe aan de component Camera.

[MenuItem( "CONTEXT/Camera/DoCameraThing" )]
private static void DoCameraThing( MenuCommand cmd ) {
    // Execute some code
}

Dat ziet er zo uit

Camera context menu-item

De parameter MenuCommand geeft u toegang tot de componentwaarde en alle gebruikersgegevens die ermee worden verzonden.

U kunt ook een contextmenu-item toevoegen aan uw eigen componenten met behulp van het kenmerk ContextMenu. Dit kenmerk heeft alleen een naam, geen validatie of prioriteit en moet deel uitmaken van een niet-statische methode.

[ContextMenu( "ContextSomething" )]
private void ContentSomething() {
    // Execute some code
}

Dat ziet er zo uit

Aangepast contextmenu-item

U kunt ook contextmenu-items toevoegen aan velden in uw eigen component. Deze menu-items verschijnen wanneer u met de context klikt op het veld waartoe ze behoren en methoden kunt uitvoeren die u in die component hebt gedefinieerd. Op deze manier kunt u bijvoorbeeld standaardwaarden of de huidige datum toevoegen, zoals hieronder weergegeven.

[ContextMenuItem( "Reset", "ResetDate" )]
[ContextMenuItem( "Set to Now", "SetDateToNow" )]
public string Date = "";

public void ResetDate() {
    Date = "";
}

public void SetDateToNow() {
    Date = DateTime.Now.ToString();
}

Dat ziet er zo uit

voer hier de afbeeldingsbeschrijving in

Gizmos

Gizmos wordt gebruikt voor het tekenen van vormen in de scèneweergave. Je kunt deze vormen gebruiken om extra informatie over je GameObjects te tekenen, bijvoorbeeld de afgeknotte ze of het detectiebereik.

Hieronder staan twee voorbeelden om dit te doen

Voorbeeld één

In dit voorbeeld worden de methoden OnDrawGizmos en OnDrawGizmosSelected (magic) gebruikt.

public class GizmoExample : MonoBehaviour {

    public float GetDetectionRadius() {
        return 12.5f;
    }

    public float GetFOV() {
        return 25f;
    }

    public float GetMaxRange() {
        return 6.5f;
    }

    public float GetMinRange() {
        return 0;
    }

    public float GetAspect() {
        return 2.5f;
    }

    public void OnDrawGizmos() {
        var gizmoMatrix = Gizmos.matrix;
        var gizmoColor = Gizmos.color;

        Gizmos.matrix = Matrix4x4.TRS( transform.position, transform.rotation, transform.lossyScale );
        Gizmos.color = Color.red;
        Gizmos.DrawFrustum( Vector3.zero, GetFOV(), GetMaxRange(), GetMinRange(), GetAspect() );

        Gizmos.matrix = gizmoMatrix;
        Gizmos.color = gizmoColor;
    }

    public void OnDrawGizmosSelected() {
        Handles.DrawWireDisc( transform.position, Vector3.up, GetDetectionRadius() );
    }
}

In dit voorbeeld hebben we twee methoden voor het tekenen van gadgets, een die tekent wanneer het object actief is (OnDrawGizmos) en een voor wanneer het object in de hiërarchie is geselecteerd (OnDrawGizmosSelected).

public void OnDrawGizmos() {
    var gizmoMatrix = Gizmos.matrix;
    var gizmoColor = Gizmos.color;

    Gizmos.matrix = Matrix4x4.TRS( transform.position, transform.rotation, transform.lossyScale );
    Gizmos.color = Color.red;
    Gizmos.DrawFrustum( Vector3.zero, GetFOV(), GetMaxRange(), GetMinRange(), GetAspect() );

    Gizmos.matrix = gizmoMatrix;
    Gizmos.color = gizmoColor;
}

Eerst slaan we de Gizmo-matrix en -kleur op, omdat we deze gaan wijzigen en terug willen zetten wanneer we klaar zijn om geen enkele andere Gizmo-tekening te beïnvloeden.

Vervolgens willen we de frustum tekenen die ons object heeft, maar we moeten de Gizmos-matrix wijzigen zodat deze overeenkomt met de positie, rotatie en schaal. We hebben ook de kleur van de Gizmos ingesteld op rood om de frustum te benadrukken. Als dit is gebeurd, kunnen we Gizmos.DrawFrustum aanroepen om de frustum in de scèneweergave te tekenen.

Als we klaar zijn met tekenen wat we willen tekenen, stellen we de matrix en kleur van de Gizmos opnieuw in.

public void OnDrawGizmosSelected() {
    Handles.DrawWireDisc( transform.position, Vector3.up, GetDetectionRadius() );
}

We willen ook een detectiebereik tekenen wanneer we ons GameObject selecteren. Dit wordt gedaan via de klasse Handles , aangezien de Gizmos- klasse geen methoden voor schijven heeft.

Het gebruik van deze vorm van het tekenen van gadgets resulteert in de hieronder getoonde uitvoer.

Voorbeeld twee

In dit voorbeeld wordt het kenmerk DrawGizmo gebruikt.

public class GizmoDrawerExample {

    [DrawGizmo( GizmoType.Selected | GizmoType.NonSelected, typeof( GizmoExample ) )]
    public static void DrawGizmo( GizmoExample obj, GizmoType type ) {
        var gizmoMatrix = Gizmos.matrix;
        var gizmoColor = Gizmos.color;

        Gizmos.matrix = Matrix4x4.TRS( obj.transform.position, obj.transform.rotation, obj.transform.lossyScale );
        Gizmos.color = Color.red;
        Gizmos.DrawFrustum( Vector3.zero, obj.GetFOV(), obj.GetMaxRange(), obj.GetMinRange(), obj.GetAspect() );

        Gizmos.matrix = gizmoMatrix;
        Gizmos.color = gizmoColor;

        if ( ( type & GizmoType.Selected ) == GizmoType.Selected ) {
            Handles.DrawWireDisc( obj.transform.position, Vector3.up, obj.GetDetectionRadius() );
        }
    }
}

Op deze manier kunt u de gizmo-aanroepen van uw script scheiden. De meeste hiervan gebruiken dezelfde code als het andere voorbeeld, behalve twee dingen.

[DrawGizmo( GizmoType.Selected | GizmoType.NonSelected, typeof( GizmoExample ) )]
public static void DrawGizmo( GizmoExample obj, GizmoType type ) {

U moet het DrawGizmo-attribuut gebruiken dat het enum GizmoType als de eerste parameter neemt en een Type als de tweede parameter. Het type moet het type zijn dat u wilt gebruiken om de gizmo te tekenen.

De methode voor het tekenen van de gizmo moet statisch, openbaar of niet-openbaar zijn en kan worden genoemd wat u maar wilt. De eerste parameter is het type, dat moet overeenkomen met het doorgegeven type als de tweede parameter in het kenmerk, en de tweede parameter is het enum GizmoType dat de huidige status van uw object beschrijft.

if ( ( type & GizmoType.Selected ) == GizmoType.Selected ) {
    Handles.DrawWireDisc( obj.transform.position, Vector3.up, obj.GetDetectionRadius() );
}

Het andere verschil is dat om te controleren wat het GizmoType van het object is, u een EN-controle moet uitvoeren op de parameter en het gewenste type.

Resultaat

Niet geselecteerd

voorbeeld één niet geselecteerd

Geselecteerd

voorbeeld één geselecteerd

Editor-venster

Waarom een editorvenster?

Zoals u misschien hebt gezien, kunt u veel dingen doen in een aangepaste inspecteur (als u niet weet wat een aangepaste inspecteur is, bekijk dan het voorbeeld hier: http://www.riptutorial.com/unity3d/topic/2506 / uitbreiding van de editor . Maar op een gegeven moment wilt u misschien een configuratiepaneel of een aangepast activapalet implementeren. In die gevallen gaat u een EditorWindow gebruiken . Unity UI zelf bestaat uit Editor Windows; u kunt ze openen (meestal via de bovenste balk), tab ze, etc.

Maak een eenvoudige EditorWindow

Eenvoudig voorbeeld

Het maken van een aangepast editorvenster is vrij eenvoudig. Het enige dat u hoeft te doen is de klasse EditorWindow uitbreiden en de methoden Init () en OnGUI () gebruiken. Hier is een eenvoudig voorbeeld:

using UnityEngine;
using UnityEditor;

public class CustomWindow : EditorWindow
{
    // Add menu named "Custom Window" to the Window menu
    [MenuItem("Window/Custom Window")]
    static void Init()
    {
        // Get existing open window or if none, make a new one:
        CustomWindow window = (CustomWindow) EditorWindow.GetWindow(typeof(CustomWindow));
        window.Show();
    }

    void OnGUI()
    {
        GUILayout.Label("This is a custom Editor Window", EditorStyles.boldLabel);
    }
}

De 3 belangrijke punten zijn:

  1. Vergeet niet om EditorWindow uit te breiden
  2. Gebruik de Init () zoals in het voorbeeld. EditorWindow.GetWindow controleert of er al een CustomWindow is gemaakt. Als dit niet het geval is, wordt een nieuwe instantie gemaakt. Hiermee zorg je ervoor dat je niet meerdere exemplaren van je venster tegelijkertijd hebt
  3. Gebruik OnGUI () zoals gewoonlijk om informatie in uw venster weer te geven

Het uiteindelijke resultaat ziet er als volgt uit:

Eenvoudige aangepaste editor Windows

Dieper gaan

Natuurlijk wilt u sommige activa waarschijnlijk beheren of wijzigen met behulp van dit EditorWindow. Hier is een voorbeeld met de klasse Selection (om de actieve Selection te krijgen) en de geselecteerde activumeigenschappen te wijzigen via SerializedObject en SerializedProperty .

    using System.Linq;
    using UnityEngine;
    using UnityEditor;
    
    public class CustomWindow : EditorWindow
    {
        private AnimationClip _animationClip;
        private SerializedObject _serializedClip;
        private SerializedProperty _events;
    
        private string _text = "Hello World";
    
        // Add menu named "Custom Window" to the Window menu
        [MenuItem("Window/Custom Window")]
        static void Init()
        {
            // Get existing open window or if none, make a new one:
            CustomWindow window = (CustomWindow) EditorWindow.GetWindow(typeof(CustomWindow));
            window.Show();
        }
    
        void OnGUI()
        {
            GUILayout.Label("This is a custom Editor Window", EditorStyles.boldLabel);
    
            // You can use EditorGUI, EditorGUILayout and GUILayout classes to display anything you want
            // A TextField example
            _text = EditorGUILayout.TextField("Text Field", _text);
    
            // Note that you can modify an asset or a gameobject using an EditorWindow. Here is a quick example with an AnimationClip asset
            // The _animationClip, _serializedClip and _events are set in OnSelectionChange()
    
            if (_animationClip == null || _serializedClip == null || _events == null) return;
    
            // We can modify our serializedClip like we would do in a Custom Inspector. For example we can grab its events and display their information
    
            GUILayout.Label(_animationClip.name, EditorStyles.boldLabel);
    
            for (var i = 0; i < _events.arraySize; i++)
            {
                EditorGUILayout.BeginVertical();
    
                EditorGUILayout.LabelField(
                    "Event : " + _events.GetArrayElementAtIndex(i).FindPropertyRelative("functionName").stringValue,
                    EditorStyles.boldLabel);
                EditorGUILayout.PropertyField(_events.GetArrayElementAtIndex(i).FindPropertyRelative("time"), true,
                    GUILayout.ExpandWidth(true));
                EditorGUILayout.PropertyField(_events.GetArrayElementAtIndex(i).FindPropertyRelative("functionName"),
                    true, GUILayout.ExpandWidth(true));
                EditorGUILayout.PropertyField(_events.GetArrayElementAtIndex(i).FindPropertyRelative("floatParameter"),
                    true, GUILayout.ExpandWidth(true));
                EditorGUILayout.PropertyField(_events.GetArrayElementAtIndex(i).FindPropertyRelative("intParameter"),
                    true, GUILayout.ExpandWidth(true));
                EditorGUILayout.PropertyField(
                    _events.GetArrayElementAtIndex(i).FindPropertyRelative("objectReferenceParameter"), true,
                    GUILayout.ExpandWidth(true));
    
                EditorGUILayout.Separator();
                EditorGUILayout.EndVertical();
            }
    
            // Of course we need to Apply the modified properties. We don't our changes won't be saved
            _serializedClip.ApplyModifiedProperties();
        }
    
        /// This Message is triggered when the user selection in the editor changes. That's when we should tell our Window to Repaint() if the user selected another AnimationClip
        private void OnSelectionChange()
        {
            _animationClip =
                Selection.GetFiltered(typeof(AnimationClip), SelectionMode.Assets).FirstOrDefault() as AnimationClip;
            if (_animationClip == null) return;
    
            _serializedClip = new SerializedObject(_animationClip);
            _events = _serializedClip.FindProperty("m_Events");
            Repaint();
        }
    }

Hier is het resultaat:
Aangepaste Editor-venster AnimationClip

Geavanceerde onderwerpen

U kunt een aantal echt geavanceerde dingen doen in de editor, en de klasse EditorWindow is perfect voor het weergeven van een grote hoeveelheid informatie. De meeste geavanceerde middelen in de Unity Asset Store (zoals NodeCanvas of PlayMaker) gebruiken EditorWindow voor weergave voor aangepaste weergaven.

Tekening in de SceneView

Een interessant ding om te doen met een EditorWindow is om informatie direct in uw SceneView weer te geven. Op deze manier kunt u een volledig aangepaste kaart- / wereldeditor maken, bijvoorbeeld door uw aangepaste EditorWindow als een activapalet te gebruiken en naar klikken in de SceneView te luisteren om nieuwe objecten te instantiëren. Hier is een voorbeeld :

using UnityEngine;
using System;
using UnityEditor;

public class CustomWindow : EditorWindow {

    private enum Mode {
        View = 0,
        Paint = 1,
        Erase = 2
    }

    private Mode CurrentMode = Mode.View;

    [MenuItem ("Window/Custom Window")]
    static void Init () {
        // Get existing open window or if none, make a new one:
        CustomWindow window = (CustomWindow)EditorWindow.GetWindow (typeof (CustomWindow));
        window.Show();
    }

    void OnGUI () {
        GUILayout.Label ("This is a custom Editor Window", EditorStyles.boldLabel);
    }

    void OnEnable() {
        SceneView.onSceneGUIDelegate = SceneViewGUI;
        if (SceneView.lastActiveSceneView) SceneView.lastActiveSceneView.Repaint();
    }

    void SceneViewGUI(SceneView sceneView) {
        Handles.BeginGUI();
        // We define the toolbars' rects here
        var ToolBarRect = new Rect((SceneView.lastActiveSceneView.camera.pixelRect.width / 6), 10, (SceneView.lastActiveSceneView.camera.pixelRect.width * 4 / 6) , SceneView.lastActiveSceneView.camera.pixelRect.height / 5);
        GUILayout.BeginArea(ToolBarRect);
        GUILayout.BeginHorizontal();
        GUILayout.FlexibleSpace();
         CurrentMode = (Mode) GUILayout.Toolbar(
            (int) CurrentMode,
            Enum.GetNames(typeof(Mode)),
            GUILayout.Height(ToolBarRect.height));
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
        GUILayout.EndArea();
        Handles.EndGUI();
    }
}

Hiermee wordt de werkbalk rechtstreeks in uw SceneView weergegeven SceneView UI van EditorWindow

Hier is een kort overzicht van hoe ver je kunt gaan:

Map Editor Editor Windows



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow