Array of Components using Behaviour or Monobehaviour array/list

Hi all,

I’m trying to return a list of components attached to a Gameobject and have the ability to enable/disable them.
Because I don’t know what kind of components are attached to each Gameobject I’m returning an array of them all using:
componentObject.GetComponents();
The problem I’m having with this is that I can’t do Component.enabled = false.
Because of this I’m trying to list the Components as Behaviour or Monobehaviour objects but am having trouble filling my array.

public class ActivateDeactivateComponent : EventScript
{
    public GameObject componentObject;

    public Component[] components;
    public MonoBehaviour[] monoComponents;

    void Start()
    {
        if(componentObject!=null)
        {
            components = componentObject.GetComponents<Component>();
            monoComponents = componentObject.GetComponents<MonoBehaviour>();
        }
    }

my components array fills as expected but my monoComponents array has 0 elements. I have also tried:

monoComponents = componentObject.GetComponents(typeof(MonoBehaviour));

and

monoComponents = componentObject.GetComponents<Component>() as MonoBehaviour;

but nothing seems to fill the list.
Any help with this would be fantastic.

Thanks,

Matt

First to your code directly.

  • GetComponents() might not return deactivated objects so this might be a problem. You would have to use GetComponentsInChildren which has a boolean option to also include deactivated ones.

  • GetComponents<>() returns an array of elements so to cast it to an array of something else you would use “as MonoBehaviour[ ]”. This method won’t work in this case as casting only changes the “type” and doesn’t repackage it into Monobehaviours.

  • You can manually loop through your array, cast each one to a monobehaviour check if it really is monobehaviour (!= null) and put it into a new array of type monobehaviour.

  • You could do the above using linq

monoComponents = components.OfType<MonoBehaviour>().ToArray();
  • The drawback of your method of using MonoBehaviours is that a BoxCollider for instance isn’t a monobehaviour and so it won’t be returned this way.

My Solution
There is a little known class in between component and monobehaviour called behaviour. This class provides the enabled field for all subclasses (including MonoBehaviours) as can be seen in the documentation.
using

components = GetComponents<Behaviour>()

You have the enabled field available directly without any further casting.
Unfortunately colliders have their own enabled field inherited from the collider class so you would have to add a GetComponents() and loop through them separately if this is desired.

1 Like

Hi,

Thanks for your reply.
I dabbled with Behaviour but had the same result. I couldn’t get it to fill an array and it just appears empty in the inspector window.

public Behaviour[] behaviourComponents

behaviourComponents = componentObject.GetComponents<Behaviour>();

returns no errors in the console but the array is still empty.

Did you try using

behaviourComponents = componentObjects.GetComponentsInChildren<Behaviour>(true);

This will include all inactive objects (and child objects).

yeah, still has an array size of 0 :frowning:

Is this because only scripts, lights, cameras etc extend Behaviour, whereas Colliders, Mesh Renderers, Particle systems etc don’t ?

As @billykater mentioned, not all components are derived from Behavior. Some, like Rigidbody and Animator, have their own, independent enabled properties. The method below handles them. If I missed any components, just add them in using the same principle. :slight_smile:

public void SetComponentEnabled(Component component, bool value) {
   if (component == null) return;
   if (component is Renderer) {
     (component as Renderer).enabled = value;
   } else if (component is Collider) {
     (component as Collider).enabled = value;
   } else if (component is Animation) {
     (component as Animation).enabled = value;
   } else if (component is Animator) {
     (component as Animator).enabled = value;
   } else if (component is AudioSource) {
     (component as AudioSource).enabled = value;
   } else if (component is MonoBehaviour) {
     (component as MonoBehaviour).enabled = value;
   } else {
     Debug.Log("Don't know how to enable " + component.GetType().Name);
   }
}

// Disable all components:
foreach (var component in componentObject.GetComponents<Component>()) {
    SetComponentEnabled(component, false);
}
2 Likes

Can it be a different issue? You know, sometimes simple things make us go crazy…

You have exposed a variable in the inspector: public GameObject componentObject;

Now if you drag&dropped an object in there… did this object have any MonoBehaviours on it?