Documentation

What is Easy Editor ?

Quick start

Create a new Monobehaviour and call it EasyEditorEnnemy.cs. Copy the code below:


public class EasyEditorEnnemy: MonoBehaviour
{    
    public Color skinColor;    
    public float maxSpeed;    
    public float height = 3f;    
    public bool usePhysic = true;    
    public Vector3 initialPosition;	    
    public List<Bounds> listOfTarget;    
    public List<Collider> BodyColliders;
}

    

Supposing you tuned a bit the values of these fields, Unity editor should by default display :

shadowed image

Now, right click on EasyEditorEnnemy.cs and click on Customize Interface. Your interface should look like this :

shadowed image

Only few changes are noticeable : The two lists are now drawn in a very fancy way, Elements are interchangeable! This customization of the array objects is generously provided by the open source project from Rotorz.
It allows a better integration of the lists in the inspector and also a context menu to insert elements at a specific position in the list.

Now, let say that your enemy under some circumstances can get really angry and get into the fury state. You need a function that triggers this fury state. Here you are:


public void GetIntoFuryState()
{    
    Debug.Log("Here start the fury state !!!");
}                        

    

The problem is that in the game you need to collect 100 diamonds before the fury state is activated, and your game designer wants to visualize it while the game is playing, and want to visualize it several times in a roll. Wouldn't be cool to create a button that allows the game designer to trigger this function while the game is playing? Yes, but writing an editor script for that seems pretty annoying. Easy Editor brings you the fast way. Add [Inspector] on top of your function:


[Inspector]
public void GetIntoFuryState()
{    
    Debug.Log("Here start the fury state !!!");
}

        

This will automatically add the button that follows in the inspector. shadowed image The game designer just need to click on it to see the fury state !

But Easy Editor is not only about that. What follows will show to you all the features Easy Editor has.

What exactly does Easy Editor ?

Now, you probably wonder what is behind the hood. When you right click on your mono script and select Customize Interface in the context menu, an editor script is created for your monobehaviour/scriptable object. This editor script inherits from EasyEditorBase which is our main class to draw the inspector. From this new editor script you can enhance your interface in a very easy way.

Note that Easy Editor changes only the appearance of your fields and allows designing some interfaces that would require time to implement in an editor script. Also, the whole Unity serialization system is still in use which means:

  • The performance of your game will not change since Easy Editor code is executed only in the editor.

  • All the attributes [SerializeField], [HideInInspector], [Tooltip], [Range(0f, 1f)], [System.NonSerialized] can still be used with Easy Editor.

Now, let see the other possibilities.

Groups and order

Some scripts can contain a lot of settings in the inspector. There are some settings you want the game designers to play with, and others you don’t want. How would it look like if you could organize these settings in groups? Like this:

shadowed image

To add this group, you need first to define the groups in EasyEditorEnnemyEditor.cs in the order you want them to appear:


[EasyEditor.Groups("Game Designer Settings", "Basic Settings", "Advanced Settings")]
[CustomEditor(typeof(EasyEditorEnnemy))]
public class EasyEditorEnnemyEditor : EasyEditorBase
{
}

    

Then on top of each group of fields you want to display add [Inspector(group = "Name of the group")]


public class EasyEditorEnnemy : MonoBehaviour
{    
    [Inspector(group = "Game Designer Settings")]    
    public Color skinColor;    
    public float maxSpeed;    
    public float height = 3f;    
    
    [Inspector(group = "Basic Settings")]    
    public bool usePhysic = true;    
    public Vector3 initialPosition;    
    
    [Inspector(group = "Advanced Settings")]    
    public List<Bounds> listOfTarget;    
    public List<Collider> BodyColliders;    
    
    [Inspector(group = "Game Designer Settings")]    
    public void GetIntoFuryState()    
    {        
        Debug.Log("Here starts the fury state !!!");        
        GetComponent<Animation>().Play();    
    }
}

    

Every field below a field with an Inspector attribute and a specified group will belong to the same group. You always can re-specify a new group on top of any field to move it to a different group. Each field that does not belong to any group will be displayed on top.

If you wish to change the order in which fields are rendered, you can specify the order value: [Inspector(group = "", order = 1)];

By default, the order of each element you want to render is 100.

For example to place the button "Get Into Fury State" on top of the Game Designer Settings group you can write on top of it :

[Inspector(group = "Game Designer Settings", order = 1)]

You will get:

shadowed image

You can also add a boxed description of the group that will appear below it by specifying the groupDescription member of Inspector attribute.


[Inspector(group = "Game Designer Settings", 
    groupDescription = “These settings allows you to fine-tune some of the enemy characteristics“)]   
    

Informative UIs elements

Comments

Comments can be added below a property by using the attribute


[Comment("your comment")]                                    

                

It can also be used with custom editor script ( see section : Integrating Unity classic editor code ).

shadowed image

You can also display comments by using the attribute [Message(text = "your comment")]

But [Message] allows you to do much more !

You can display the message in 3 flavors by specifying the parameter messageType :

  • [Message(text = "your comment", messageType = MessageType.Info)] for comments.
  • [Message(text = "your comment", messageType = MessageType.Warning )] for warnings.
  • [Message(text = "your comment", messageType = MessageType.Error )] for errors.

You can also display messages under some conditions (useful for field that requires a parameters, or field that should show different message based on if they are in play mode or not for example).

For that, you can use either the parameters id and value :


[Message(text = "This field cannot be equal to 0", messageType = MessageType.Error, id = “speed”, value = 0f)]

                

or the parameter method :

[Message(text = "You need to assign the main camera of the scene.", method = IsNotMainCamera)]

In the first case, the message will be displayed if field with id id is equal to value

In the second case, the message will be displayed if the method return true

Tooltip

The default [Tooltip("your tooltip")] in Unity only works with fields. You can also display a tooltip on buttons rendered by Easy Editor by the using the attribute [EETooltip("your tooltip")]

shadowed image

Layout

Consecutive fields can be laid in an horizontal or vertical fashion with the attributes [BeginHorizontal], [EndHorizontal], [BeginVertical], [EndVertical].
Here an example :


[Inspector(group = "Sound Basic Parameters")]
[BeginHorizontal]
public float fadeInTime = 0f;
[EndHorizontal]
public float fadeOutTime = 0f;                                    

                
shadowed image

Hiding groups and fields

Groups and fields can be hidden in the editor script. This can be useful if you want to hide a group to some users, or if you want to display some fields under some conditions.

Let’s take an example.

You want to write a script that allows setting when the object should be render in the render queue. Several objects use this script, and you want to give the user the possibility to set this order based on an absolute int value, or an enum value that would tell you if the object is render at the same time as the main character, or after shadows, or after the terrain (this can be useful for effects like water riddles). Here what you want to get in the editor.

shadowed image
shadowed image

There are two ways of achieving this functionality. Let’s start with the most straightforward.

Hiding with attribute

You can use the attribute [Visibility(string id, object value)] on top of a field or [Visibility(string method)].

If the value of the field holding the id id is equal to value, then the field with attribute Visibility will be visible, otherwise it will not. Note that the default id of a field is its name. But you can change the id of a field by specifying it with the attribute :

[Inspector(id = "your custom id")]

Here is the code :


using UnityEngine;
using System.Collections;
public class SetRendererOrder : MonoBehaviour 
{
    public enum RenderOrderLabel    
    {            
        Shadow = 1998,            
        Terrain = 1999,            
        MainCharacter = 2001    
    }    
    
    public bool useLabel = true;    
    [Visibility("useLabel", true)]    
    [SerializeField] private RenderOrderLabel renderOrderLabel = RenderOrderLabel.MainCharacter;    
    [Visibility("useLabel", false)]    
    [SerializeField] private int renderOrderValue = 2000;
}

    

Now, in your project window, right-click on SetRendererOrder.cs and select Customize Interface. That’s it.

If instead of specifying an id and a value, you specify a method name in the Visibility attribute, this method will be looked-up in the class where the Visibility attribute is used (in the monobehviour/scriptable object, or the editor script, or in a serializable generic class or struct). If this method return true, the ui element will be rendered.

Hiding from the editor script

Easy Editor not only displays your monobehaviour/scriptable object scripts in the inspector but also can render some piece of custom editor script, or a button activating a method. You can do it directly from the editor script generated when you right-click on your script and select Customize Interface in the context menu.

You can use the function HideRenderer(string id) or ShowRenderer(string id). The id is the name of a field in your monobehaviour/scriptable object, or the name of a function if it is rendering a button or some custom editor scripts (see following sections).

Here the code that solves our previous case :


public class SetRendererOrderEditor : EasyEditorBase
{	
    public override void OnInspectorGUI ()	
    {		
        SetRendererOrder monobehaviour = (SetRendererOrder) target;		
        if(monobehaviour.useLabel)		
        {			
            HideRenderer("renderOrderValue");			
            ShowRenderer("renderOrderLabel");		
        }		
        else		
        {			
            HideRenderer("renderOrderLabel");			
            ShowRenderer("renderOrderValue");		
        }
        
        base.OnInspectorGUI ();	
    }
}
    

Hiding a group is pretty similar to hiding a field in the editor script, but instead of HideRenderer/ShowRenderer you need to call HideGroup/ShowGroup with the string name of the group as argument. It is illustrated in the following section.

Adding buttons to the editor script

Buttons can be added from the monobehaviour/scriptable object script by writing [Inspector] on top of any function. This works also in the editor script! Let’s say you want a button that hides or shows the advanced settings group.

shadowed image
shadowed image

You first need to declare a serialized field showAdvancedSettings in your monobehaviour to save the state show/hidden of the advanced setting group. Let’s do it in our EasyEditorEnnemy.cs script :


[HideInInspector] 
public bool showAdvancedSetting = false;    
[Inspector(group = "Advanced Settings")]    
public List<Bounds> listOfTarget;    
public List<Collider> BodyColliders;    
[Inspector(group = "Game Designer Settings", order = 1)]    
public void GetIntoFuryState()    
{        
    Debug.Log("Here start the fury state !!!");    
}

    

Now, in our editor script, we can write a function that will change the state of showAdvancedSettings and display it at the end of Basic Settings group, just on top of Advanced Settings group.


[EasyEditor.Groups("Game Designer Settings", "Basic Settings", "Advanced Settings")]
[CustomEditor(typeof(HideGroupEnnemy))]
public class HideGroupEnnemyEditor : EasyEditorBase
{	
    [Inspector(group = "Basic Settings")]	
    private void ToggleDisplayAdvancedSettings()	
    {        
        HideGroupEnnemy ennemy = (HideGroupEnnemy)target;	 
        ennemy.showAdvancedSetting = !ennemy.showAdvancedSetting;        
        if (ennemy.showAdvancedSetting)        
        {            
            ShowGroup("Advanced Settings");        
        }        
        else        
        {            
            HideGroup("Advanced Settings");        
        }	
    }
}

    

Et Voilà !

Integrating Unity classic editor code

PropertyDrawer

Easy Editor uses Unity property default drawer to render every field serialized by default. It means that if you define a property drawer, Easy Editor will render it as you specified it in the class inheriting from PropertyDrawer.

Custom editor code

Easy Editor helps you to render quickly and in an organized way every UI elements you mostly use. But you may wish adding your own custom piece of editor script to render some of your custom properties in one group at a specific position. To do so, you simply need to implement a function in your editor script and to add the attribute [Inspector(group = "Name of the group", rendererType = "CustomRenderer" )].

Let’s take an example. In part 2 we saw how to define groups for the fields of EasyEditorEnnemy.cs. Now, in the group "Advanced Settings" we want to add a progress bar indicating the level of the enemy armor. You just need to open EasyEditorEnnemyEditor.cs and add :


[Inspector(group = "Advanced Settings", rendererType = "CustomRenderer", order = 1)]
private void RenderProgressBar()
{
    Rect r = EditorGUILayout.BeginVertical();
    EditorGUI.ProgressBar(r, 0.8f, "Life");
    GUILayout.Space(18);
    EditorGUILayout.EndVertical();    
} 

    
shadowed image

Inline rendering of Monobehaviour, ScriptableObject, custom classes and structure

Easy Editor allows you to use Easy Editor attributes directly into a mono behaviour, scriptable object or custom class/struct and to render it in the inspector of the monobehaviour which hold it. To achieve it, you can add the attribute [Inspector(rendererType = "InlineClassRenderer" )]. This feature works also with nested classes.

Let’s illustrate it.

Here a custom class Weapon:


[System.Serializable]
public class Weapon
{
	[BeginHorizontal]
	public string name = "";
    [EndHorizontal]
	public float strength = 0f;
}

    

and here a custom class Bag that holds the class weapon.


[System.Serializable]
public class Bag
{
	[Range(1, 10)]
	public int weight;

	[Inspector(rendererType = "InlineClassRenderer")]
	public Weapon mainWeapon;

	public List otherWeapons;
}

    

Any monobehaviour with a member of type Bag with the attribute [Inspector(rendererType = "InlineClassRenderer" )] will see in its inspector :

shadowed image

Easy Editor API

InspectorAttribute

InspectorAttribute is the main used attribute in Easy Editor. It allows to describe how should be rendered a field or any other element in the inspector. Since Easy Editor can render a field but also a function in the editor, we will call any element that can be rendered a renderer.

Hereunder a list of the different parameters that can be used :

  • string group

    Indicates in which group the renderer belongs to. If the renderer is a field and is under another field with a group already specified, this last field will belong to the same group.

    Example :

    
    [Inspector(group = "Game Designer Settings")]
    public Color colorSkin; 
    
            

    Groups are declared with Groups attribute on top of a Monobehaviour/Scriptable Object editor script or on top of the declaration of a serializable class :

    On top of editor script :

    
    [Groups(“Game Designer Settings", "Basic Settings", "Advanced Settings")]
    [CustomEditor(typeof(EasyEditorEnnemy))]
    public class EasyEditorEnnemyEditor : EasyEditorBase
    
            

    On top of serializable class :

    
    [Groups("Basic Settings")]
    [System.Serializable]
    public class Bag
    {
    	[Range(1, 10)]
    	public int weight;
    
    	[Inspector(group = "Basic Settings”,rendererType = "InlineClassRenderer")]
    	public Weapon mainWeapon;
    
    	public List otherWeapons;
    } 
    
            

    If a renderer does not belong to any group or belongs to a group which is not declared, it will be rendered on top of every group in the inspector.

    The order in which groups are rendered in the inspector depends on the order they are declared in the attribute Group.

  • string groupDescription

    Render a description of the group just under its header.

    Example :

    
    [Inspector(group = "Game Designer Settings", groupDescription = "Game Designer should only modify the settings under this group”)]
    public Color skinColor;
    public float maxSpeed;
    
                
    shadowed image
  • bool displayHeader

    Hide the group header. Group description will not be displayed as well if this setting is set to false.

    
    [Inspector(group = "SpeedControl", displayHeader = false)]
    public float maxSpeed;
    public float minSpeed; 
    
                
  • bool foldable

    Allows to display a foldable group. This option cannot be used with displayHeader set to true, otherwise the group will be invisible.

    shadowed image
  • int order

    Specify at which position is render the renderer in the inspector inside the group it belongs to. The default order position is 100. In the example above, the button to reinitialise the speed, which order is equal to 1, will be rendered on top of maxSpeed which order is equal to 100.

    
    [Inspector(group = "Game Designer Settings")]
    public float maxSpeed;
    public float minSpeed;
    [Inspector(group = "Game Designer Settings", order = 1)]
    public void ReinitializeSpeed()
    {
    }  
    
                
  • string rendererType

    Each Renderer is actually a class which is fed with the field or method of the object rendered in the editor (Monobehaviour, ScriptableObject, serialisable class) and is in charge of rendering it in the inspector. Each type has a default renderer that renders it in a specific way. Other way can be specified if necessary with the parameter renderertType.

    Example :

    List and Array are rendered by default by the renderer ReorderableListRenderer. If you prefer to render a list as Unity does it by default, you can specify it as below :

    
    [InspectorAttribute(rendererType = "SerializedFieldRenderer")]
    public List BodyColliders;
    
                
    shadowed image

    shadowed image
  • string id

    The id allows to refer to a specific renderer. By default id is the name of the variable, so most of time it does not need to be specified.

    Example :

    
    [Inspector(id = "showString")]
    public bool stringDisplayed = true;
    
    [Visibility("showString", true)]
    public string theString = ““;  
    
                

    In the above example, we could have not defined any id and use :

    
    [Visibility("stringDisplayed", true)] 
    public string theString = ““;  
    
                    
    to hide or show the text field theString.

    to hide or show the text field theString.

Other Easy Editor Attributes

  • BeginHorizontal, EndHorizontal, BeginVertical, EndVertical

    [BeginHorizontal] start to layout ui element horizontally. It has to be followed by [EndHorizontal] to end the horizontal layout and come back to a vertical layout (default laying in Unity inspector).[BeginVertical] and [EndVertical] are the vertical counterpart of these settings.

    Example :

    
    [BeginHorizontal]
    public bool allowed = true;
    [EndHorizontal]
    public bool testMode = true; 
    
                
    shadowed image
  • Comment

    Allows to quickly add a comment under a ui element (no matter it is rendered from Editor Script, from a field or from a function).

    Example :

    
    [Comment(“If allowed, clamping won’t apply anymore.”)]
public bool allowed = true; 
    
                
    shadowed image
  • EETooltip

    allows to display a tooltip on a button.

    Example :

    
    [EETooltip(“Add a user to the pool list.”)]
    public void AddUser()
    {
    } 
    
                
  • MessageAttribute

    Allows to display a message in 3 flavors by specifying the parameter messageType :

    • [Message(text = "your comment", messageType = MessageType.Info)] for comments.
    • [Message(text = "your comment", messageType = MessageType.Warning )] for warnings.
    • [Message(text = "your comment", messageType = MessageType.Error )] for errors.

    You can also display messages under some conditions (useful for field that requires a parameters, or field that should show different message based on if they are in play mode or not for example).

    For that, you can use either the parameters id and value :

    
    [Message(text = "This field cannot be equal to 0", messageType = MessageType.Error, id = “speed”, value = 0f)]
    
                    

    or the parameter method :

    [Message(text = "You need to assign the main camera of the scene.", method = IsNotMainCamera)]

    In the first case, the message will be displayed if field with id id is equal to value

    In the second case, the message will be displayed if the method return true.

    shadowed image

    shadowed image

Property Attributes

  • EnumFlag

    Allows to display an enum as a list containing options that can be simultaneously selected. It is similar to the way Unity display LayerMask object. Internally, the value of the enum is an int which is the sum of each option selected. Because each item int value represent a bit position (1, 10, 100, 1000), it is very easy with some bit operation to check which values are selected.

    Example :

    
    public enum PlatformCompatibility
    {
       iOS             = 0x001,
       Android         = 0x002,
       WindowsPhone    = 0x004,
       PS4             = 0x008,
       Wii             = 0x010,
       XBoxOne         = 0x020,
       WindowsDesktop  = 0x040,
       Linux           = 0x080,
       MacOS           = 0x100
    }
    
    [EnumFlag]
    public PlatformCompatibility compatibleDevice; 
    
                
    shadowed image
    
    (int)compatibleDevice & (int)Compatibility.PS4; 
    
                

    If the previous value is equal to 0 it means that PS4 was not selected.

  • Path

    Allows you to drag any asset or folder on the field in the inspector to assign this asset/folder path to the string. It is very helpful when automising operation on assets in the inspector.

    Example :

    
    [Path]
    public string assetPath;
    
                
    shadowed image
  • ReadOnly

    A string with the attribute [ReadOnly] will prevent user from modifying a serialised value. It can be useful when you don’t want a variable to be easily modified by any user, or if you want to show in the inspector a value controlled by your game, without forcing people to switch to debug mode.

    Let’s say for example you are initialising a list when you start the game. To prevent people to have to open your script to understand that this list is initialised when the game is launched, you could display a ReadOnly list with a comment : "This list is initialised with its children object when the game start".

    Example :

    
    [ReadOnly]
    public List enemyList; 
    
                
  • ProgressBar

    Will display a float value as a progress bar. The maximum value of the progress bar is the one you specify as float parameter of the attribute.

    Example :

    
    [ProgressBarAttribute(10)]
    public float life = 6f;
    
                
    shadowed image
  • Image

    Allows you to display an image from a string and specify its alignment and size in the inspector.

    Example :

    
    [Image(alignement = ImageAlignement.Left, size = 40f)]
    public string positionImage1 = "Assets/Easy Editor/Examples/icon.png"; 
    
                
  • Popup

    Allows you to assign a string, int, float from a list specified in [Popup(list of int OR list of float OR list of string)].

    In Unity we usually use enum to select an identifier in the inspector. The advantage is that users cannot mistype the identifier name since it is selected from a list. But this enum value is dependent on the enum values order. If later you introduce a new value in the enum, all the identifier you already set will change.

    This is why, sometime you want to use a string identifier. But this identifier can be easily mistyped. Popup can help you to avoid mistakes in the string value by hard coding the possible value in a list. Changing the order of item in the list or adding new one will not influence the values you already assigned.

    Example :

    
    [Popup("Wizard Potion", "Warrior Potion", "Priest Potion")]
    public string potionType;
    
                

Customising Easy Editor default behaviour

Some of Easy Editor default rendering appearance can be changed in the file Settings.cs. You can change :

  • Indentation level for foldable groups and inline class.
  • If a group is foldable or not by default.
  • The position of Messages and Comments (Below or Above the field rendered).
  • If the classes rendered inline in the inspector should be unfolded or folded when displayed for the first time.