Change Component Order via Script

Hi all,

Is there any way to change component order via script?

We can do this by right-clicking the component in the inspector, then select move up/down.
But I need to do this by code. Is it possible that way?

To make it more specific, I have 2 components that use OnRenderImage(). They need to be called in a specific order, or else the resulting image is wrong. I have tried to set the script execution order but it has no effect.

Any help is appreciated. Thanks!

Use the undocumented UnityEditorInternal.ComponentUtility.MoveComponentUp/Down to move components around at edit time. (Thanks to Statement for the tip.)

static void MoveUp()
{
    var sel = Selection.activeGameObject;
    var target_component = sel.GetComponent<MoveThisKindOfComponent>();
    UnityEditorInternal.ComponentUtility.MoveComponentUp(target_component);
}

You could make an Editor with a button to fix the component order on the selected object (or search for objects that need to be fixed).

One way to do this is by attaching a component, that references all the other components attached to the same gameObject, and then via some magical custom editor stuff, you could get something like this (an example of what I’m working on):

[19798-inspector.png*_|19798]

You could see those “U” and “D” buttons, which stand for Up/Down. You could use this object to sort the other components, and then when you want to render - you take the order of your components, from that component.

If this solutions works for you, let me know and I’ll post the code I used to get this custom editor.


So, here’s what I worked out for you:

[19800-sorter.png*_|19800]

Here’s the sorter component, for which I will make a custom editor for - it just has a list of components:

using UnityEngine;
using System.Collections.Generic;

public class ComponentSorter : MonoBehaviour
{
	[HideInInspector]
	public List<Component> components;

	void OnGUI()
	{
		for (int i = 0; i < components.Count; i++) {
			GUI.Label(new Rect(Screen.width / 2, i * 25, 500, 50), components*.ToString());*
  •   	}*
    
  •   }*
    
  • }*
    And, here’s where the magic happens:
    ComponentSorterEditor.cs (put this in your Editor folder, if you don’t have one, create it - “Assets/Editor”)
    using UnityEngine;
    using UnityEditor;
    using System.Collections.Generic;

[CustomEditor(typeof(ComponentSorter))]
public class ComponentSorterEditor : Editor
{

  • private SerializedProperty components;*
  • private void OnEnable()*
  • {*
  •   components = serializedObject.FindProperty("components");*
    
  • }*
  • public override void OnInspectorGUI()*
  • {*
  •   DrawDefaultInspector();*
    
  •   serializedObject.Update();*
    
  •   PopulateComponents();*
    
  •   GUILayout.Label(components.name, EditorStyles.boldLabel);*
    
  •   for (int i = 0; i < components.arraySize; i++) {*
    
  •   	EditorGUILayout.BeginHorizontal();*
    
  •   	{*
    
  •   		EditorGUILayout.PropertyField(components.GetAt(i));*
    
  •   		if (GUILayout.Button("D", GUILayout.Width(20f))) {*
    
  •   			components.MoveDown(i);*
    
  •   		}*
    
  •   		if (GUILayout.Button("U", GUILayout.Width(20f))) {*
    
  •   			components.MoveUp(i);*
    
  •   		}*
    
  •   	}*
    
  •   	EditorGUILayout.EndHorizontal();*
    
  •   }*
    
  •   serializedObject.ApplyModifiedProperties();*
    
  • }*
  • private void PopulateComponents()*
  • {*
  •   components.RemoveNullObjects();*
    
  •   var targetGo = (serializedObject.targetObject as ComponentSorter).gameObject;*
    
  •   var comps = targetGo.GetComponents<Component>();*
    
  •   foreach (var comp in comps) {*
    
  •   	if (!components.Contains(comp)) {*
    
  •   		components.Add(comp);*
    
  •   	}*
    
  •   }*
    
  • }*
    I think the code is pretty straight forward. One thing to note here, RemoveNullObjects is useful so that, if you remove a component, the components list will get populated accordingly in a way that you won’t see nulls as the objects values.
    See [this video][3], to see what I’m talking about. (I solved it on the fly in a redundant way in the video, there was no need to clear out the whole array)
    [Here’s the SerializedProperty extension methods][4]. Don’t be scared, they’re just there to make your life easier. Feel free to modify.
    One thing you’d probably wanna do is remove the ComponentSorter reference from the components themselves. That could be easily achieved by adding one more condition to the if that’s adding the comps:
  • if (!components.Contains(comp) && !(comp is ComponentSorter)) {*
  •   components.Add(comp);*
    
  • }*
    When you want to render your stuff, you just do:
    var orderedComps = myStuffGo.GetComponent().components;
    Hope you like it :slight_smile:
    ----------
    Answering your comment:
    You’ll get serializedObject for free when you inherit from Editor which is where its declared. As its name suggests, it’s of type SerializedObject
    If you don’t want to use the custom editor, then you won’t get a visual representation of what’s going on.
    If you insist, you could use the extension methods I have MoveUp and MoveDown methods ‘inside’ ComponentSorter:
    They just need some modifications:
  • public static List Swap(this List list, int i, int j)*
  • {*
    _ T temp = list*;_
    _ list = list[j];
    list[j] = temp;
    return list;
    }
    ** Codes are not tested from this point on **
    public class ComponentSorter : MonoBehaviour
    {
    public List components;
    public void MoveUp(int fromIndex)
    {
    int previous = fromIndex - 1;
    if (previous < 0) previous = prop.arraySize - 1;
    components.Swap(fromIndex, previous);
    }
    public void MoveDown(int fromIndex)
    {
    int next = (fromIndex + 1) % prop.arraySize;
    components.Swap(fromIndex, next);
    }
    }
    (You could actually make the MoveUp and MoveDown list extensions as well, I’d go for that…)
    If you don’t like moving them by index, you could do:
    public void Move(Component c, bool up)
    {
    int index = components.IndexOf(c);
    if (index == -1) return; // component not found;
    if (up) MoveUp(index);
    else MoveDown(index);
    }
    So… wanna move the Transform component? you could do:
    Move(components.Find(c => c is Transform) as Transform, true); // don’t forget System.Linq;
    One more thing you could do, write a generic move method:
    public void Move(bool up) where T : Component
    {
    int index = components.FindIndex(c => c.GetType() == typeof(T)); // if you want to get any children of ‘T’ do "c => c.GetType().IsSubclassOf(typeof(T))
    if (index == -1) return; // component not found;
    if (up) MoveUp(index);
    else MoveDown(index);
    }
    Use it like:
    // for pure convenience*
    private const bool UP = true;
    private const bool DOWN = false;_

Move(UP);
I suggest you keep the custom editor - it’s very useful. If you do remove it, then you have to move the population of the components array, to the sorter as well…
*
*
*[3]: - YouTube
*[4]: http://pastebin.com/5VWqNLmq*_

For anyone still reading this looking to simply move a component up or down in editor code (for doing something like ensuring background images show up behind text, etc):

UnityEditorInternal.ComponentUtility.MoveComponentUp(yourComponentReference); 
UnityEditorInternal.ComponentUtility.MoveComponentDown(yourComponentReference);

I wrote a ComponentSorter component that sorts components by name. I used bubble sort because we can only move components up and down. After each component switch, I call GetComponents again so we have the same list order as in editor UI.

    public class ComponentSorter : MonoBehaviour
    {
        public void Sort()
        {
            var components = GetComponents<Component>().ToList();
            components.RemoveAll(x => x.GetType().ToString() == "UnityEngine.Transform");

            for (int p = 0; p <= components.Count - 2; p++)
            {
                for (int i = 0; i <= components.Count - 2; i++)
                {
                    Component c1 = components*;*

Component c2 = components[i + 1];

string name1 = c1.GetType().ToString().Split(‘.’).Last();
string name2 = c2.GetType().ToString().Split(‘.’).Last();

if (string.Compare(name1, name2) == 1)
{
ComponentUtility.MoveComponentUp(c2);
components = GetComponents().ToList();
components.RemoveAll(x => x.GetType().ToString() == “UnityEngine.Transform”);
}
}
}

for (int i = 0; i < components.Count; i++)
{
ComponentUtility.MoveComponentUp(this);
}
}
}
And the custom editor class with the button:
[CustomEditor(typeof(ComponentSorter))]
public class ComponentSorterEditor: Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();

ComponentSorter myScript = (ComponentSorter)target;
if (GUILayout.Button(“Sort Components”))
{
myScript.Sort();
}
}
}