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:
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.
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.
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.
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.
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);
}