Is there any way to organize monobehaviours in the inspector?

Hi guys. As my GameObjects are growing I am finding some of them are getting quite a lot of monobehaviours on them. Mostly because I like to split out logic into smaller scripts. Because the inspector just displays all components as one big list it is getting a bit messy. I know there are plenty of solutions for creating tabs WITHIN monobehaviours, however I didn’t really see anything that just allows me to move monobehaviours themselves to a new tab on the object. Is there anything like this?

I’m not aware of anything but if you’re consistently having this problem in projects you could create a MonoBehaviour that acts as a container for other MonoBehaviours and write a custom editor for it.

public class MultiMonoBehaviour : MonoBehaviour
{
    public List<MonoBehaviour> monoBehaviours;

    public Awake() => foreach (var mb in monoBehaviours) mb.Awake();
    public Start() => foreach (var mb in monoBehaviours) mb.Start();
    public Update() => foreach (var mb in monoBehaviours) mb.Update();
}

What about dropdown fields? Odin Inspector supports those well but even with builtin unity those are trivial to make. Instead of 20 public or Serializefield fields you would just group them into one or more (private, inline) structs that you make serializable. Then that struct is a field in the MB and you can open it up with that triangle button.

In my opinion if one object has too many Monobehaviours like that you may be better off having multiple objects. Nothing says you can’t have an object be a child of something else. I think it is a failure of OOP principles to have an object do too many things, even if those are split into multiple scripts. The same principles that apply to classes also can apply to objects.

I’d certainly love to see a legitimate case where someone really needs 20 different monobehaviours on something where it wouldn’t make sense to split things up. I’m always trying to learn things.

Another consideration, if you really want them all together, you can always “minimize” each component in the inspector with the triangle on the left(similar to the above-mentioned structs). Then you can easily fit all the 20 components into a single screen height’s space and only open up the ones you need at a specific time. The Collapse All Components option in the inspector menu(the 3 dots on the upper right corner) will “minimize” all the components in one menu item click too.

1 Like

I would stuff them into child game objects. Then I’d name child objects according to their purpose.

1 Like

That sounds like something ChatGPT would suggest.

Except you construct MonoBehaviours (and any Component) directly onto a GameObject. And the magical references like .transform and mechanisms like SendMessage/GetComponent all depend on that referential relationship.

@CPTANT No, just the collapsing little arrow.

1 Like

Actually, would that even work?

Normal unity usage allows you to use AddComponent and select behaivors from a list. Or drag scripts into inspector.

All of this is likely going to break with proposed approach.

And if you’re making custom behavior classes, there’s no real reason to make them MonoBehaviors. Another thing to keep in mind is that MonoBehavior is not a proper normal class. For example methods like Awake() are not virtual, and they’re gathered from components, apparnetly through reflection or something similar.

For example, if you take a look at the basic unity example from here:
https://docs.unity3d.com/ScriptReference/MonoBehaviour.Awake.html

using UnityEngine;
public class ExampleClass : MonoBehaviour
{
    private GameObject target;
    void Awake()
    {
        target = GameObject.FindWithTag("Player");
    }
}

Then Awake() is private. Meaning you cannot call it from normal C# code. It is not an interface method, because interface methods are required to be public. It is not virtual, because there is no override modifier and virtual methods cannot be private.

1 Like

Alright, I got curious, tested it, and this isn’t gonna work, because MonoBehavior does not have Awake(), Start() and Update() methods, due to not being a normal C# class. Which is in line with things I wrote earlier. The defined methods are related to components, messages and coroutines.

8905299--1218873--upload_2023-3-27_6-39-46.png

1 Like

I wish I could claim that it led me down the wrong path but this was entirely my own idea. :stuck_out_tongue:

1 Like

Sometimes, yes, but do keep in mind that this has a performance cost. In particular, there is a cost to moving GameObjects which have a large number of child / parent GameObjects because of the various data which potent needs to be re-computed when this happens. With that in mind, my general rule of thumb is to only split something into a child GameObject if it gets some benefit from having its own Transform.

Sometimes, “this will make things easier for the human developers” is indeed a benefit. :wink:

Also remember that OOP isn’t the only valid approach. It’s a useful default, but it’s not the best tool in all circumstances, and by its nature Unity leans more towards Component Oriented Design than straight Object Oriented (though certainly there’s overlap).

1 Like

Putting them on child gameobjects is by far the most intuitive approach imo. Especially if the object in any way corresponds to an object in real life with some kind of anatomical structure.

Otherwise I’d go for custom classes.

I think you may like neon-age’s Smart Inspector. It has tab-like toggles to hide/show components.

3 Likes

Thanks, I will check it out!

Thinking more about this general question I think I will start moving a lot more stuff into custom plain C# classes instead of monoBehaviours, there isn’t really a reason for a lot of them to be mono. And even if I do need to do something in Awake or Update I can also call this from the “main” class that references the component. Refactoring everything now is probably not worth it though and the only real downside for now is some clutter.