Search code examples
c#unity-game-engineunity-editor

Can I set the sort order of subfolders within CreateAssetMenu?


Is it possible to set the order of folders when using CreateAssetMenu for scriptable objects?

For example, if I have these classes

[CreateAssetMenu(menuName = "My Objects/First Thing", order = 1)]
public class FirstThing : ScriptableObject
{
}

[CreateAssetMenu(menuName = "My Objects/Second Thing", order = 2)]
public class SecondThing : ScriptableObject
{
}

[CreateAssetMenu(menuName = "My Objects/Third Thing", order = 3)]
public class ThirdThing : ScriptableObject
{
}

Then when I right click in the Project window and select Create, the context menu shows my menu options in this order

Create -> My Objects -> First Thing
          |-----------> Second Thing
          |-----------> Third Thing

However, once I start organizing my menu options into subfolders, I can't find a way to control the order of subfolders. For instance, if I now have this

[CreateAssetMenu(menuName = "My Objects/Things/First Thing", order = 1)]
public class FirstThing : ScriptableObject
{
}

[CreateAssetMenu(menuName = "My Objects/Things/Second Thing", order = 2)]
public class SecondThing : ScriptableObject
{
}

[CreateAssetMenu(menuName = "My Objects/Things/Third Thing", order = 3)]
public class ThirdThing : ScriptableObject
{
}

[CreateAssetMenu(menuName = "My Objects/Widgets/First Widget", order = 1)]
public class FirstWidget: ScriptableObject
{
}

[CreateAssetMenu(menuName = "My Objects/Widgets/Second Widget", order = 2)]
public class SecondWidget: ScriptableObject
{
}

Now the Create context menu looks like this

Create -> My Objects -> Things --> First Thing
          |             |--------> Second Thing
          |             |--------> Third Thing
          |-----------> Widgets -> First Widget
                        |--------> Second Widget

Is there a way to control the order of the Things and Widgets folders similarly to how I can control the order of First Thing, Second Thing, etc. within their parent folders?


Solution

  • From this post which spreads some details about the sorting order in Unity menus under Sorting Details further below you can find that:

    Sort priority for custom submenu groups themselves (as opposed to the menu item) is a bit tricky. A submenu group will be sorted at whatever priority the custom menu item had when it was first created.

    Or in other words: Subfolders are sorted by the order value of the first element within them.

    Since both your subfolders start with the order 1 they are sorted alphabetic as fallback.

    So in order to bring the Things menu under the Widgets folder simply make sure the elements have an absolute higher value like e.g.

    [CreateAssetMenu(menuName = "My Objects/Things/First Thing", order = 11)]
    public class FirstThing : ScriptableObject
    {
    }
    
    [CreateAssetMenu(menuName = "My Objects/Things/Second Thing", order = 12)]
    public class SecondThing : ScriptableObject
    {
    }
    
    [CreateAssetMenu(menuName = "My Objects/Things/Third Thing", order = 13)]
    public class ThirdThing : ScriptableObject
    {
    }
    
    [CreateAssetMenu(menuName = "My Objects/Widgets/First Widget", order = 1)]
    public class FirstWidget: ScriptableObject
    {
    }
    
    [CreateAssetMenu(menuName = "My Objects/Widgets/Second Widget", order = 2)]
    public class SecondWidget: ScriptableObject
    {
    }
    

    Maybe it would even be enough to instead make it 2, 3, 4 on the Things items ;)

    This should result in

    Create -> My Objects -> Widgets -> First Widget
              |             |--------> Second Widget
              |
              |-----------> Things --> First Thing
                            |--------> Second Thing
                            |--------> Third Thing
    

    Additionally note

    If your item has a priority of 11 or more than the previous item, Unity will create a separator before your item

    And careful:

    As a quick aside, if you change a menu item’s existing sort priority, you may not see it reflected in the Menus. I think Unity is caching the value, so to get it to update you can either restart your Editor, or do some gymnastics where you first remove the Priority from your attribute, compile, then add the new priority.


    Little pro tip: To make maintenance easier I usually would have a central class with some constants and doing e.g.

    public static class Constants
    {
        public static string MENU = "My Objects/";
        public static string MENU_THINGS = MENU + "Things/";
        public static string MENU_WIDGETS = MENU + "Widgets/";
    
        public static int ORDER_WIDGETS = 0;
        public static int ORDER_THINGS = 10;
    }
    

    and then do

    [CreateAssetMenu(menuName = Constants.MENU_THINGS + "First Thing", order = Constants.ORDER_THINGS + 1)]
    public class FirstThing : ScriptableObject
    {
    }
    
    [CreateAssetMenu(menuName = Constants.MENU_THINGS + "Second Thing", order = Constants.ORDER_THINGS + 2)]
    public class SecondThing : ScriptableObject
    {
    }
    
    [CreateAssetMenu(menuName = Constants.MENU_THINGS + "Third Thing", order = Constants.ORDER_THINGS + 3)]
    public class ThirdThing : ScriptableObject
    {
    }
    
    [CreateAssetMenu(menuName = Constants.MENU_WIDGETS + "First Widget", order = Constants.ORDER_WIDGETS + 1)]
    public class FirstWidget: ScriptableObject
    {
    }
    
    [CreateAssetMenu(menuName = Constants.MENU_WIDGETS + "Second Widget", order = Constants.ORDER_WIDGETS + 2)]
    public class SecondWidget: ScriptableObject
    {
    }