How to change children layers, then change back?

I have objects that have children, some of those children are on different layers

I need to know:
How to temporarily store the layer of each child object, regardless of how many nested children there may be
Then change their layer
Then be able to change each child’s layer back to their original layer

The layer is an integer. Put it in something that can store integers, perhaps an integer array.

Again, it’s an integer. Assign it.

Using the original collection of stored layer integers, write them back to the GameObjects they belong on.

Here’s a very unoptimized method:

var children = GetComponentsInChildren<Transform>(true).Select(t => t.gameObject).ToList();
var originalLayers = children.Select(c => c.layer).ToList();

// change layer
children.ForEach(c => c.layer = tempLayer);

// restore layer
_ = children.Select((c, i) => c.layer = originalLayers[i]);
1 Like

When I try “GetComponentsInChildren(true).Select” I get an error that Transform[ ] does not contain definition for Select. I’m not sure what’s missing, as I haven’t yet had to work much with arrays, so I haven’t encountered an issue similar to this and have no idea how to correct it.
But am interested to try your solution since I have been looking for a solution for a couple days and every solution I try seems to only change the layers of the first one or two children. I even tried solutions that don’t bother keeping track of the original layer, yet still only the first two objects’ layers want to change for some reason

I usually find methods similar to

    public static void SetLayerRecursively(this GameObject obj, int layer) {
        obj.layer = layer;
        foreach (Transform child in obj.transform) {
            child.gameObject.SetLayerRecursively(layer);
        }
    }

or

public static void SetLayerRecursively(this Transform parent, int layer)
    {
        parent.gameObject.layer = layer;
        for (int i = 0, count = parent.childCount; i < count; i++)
        {
            parent.GetChild(i).SetLayerRecursively(layer);
        }
    }

Yet still only the first two game object (I believe the parent, one child, then maybe one of it’s children) change layers. What am I missing?

Note: I don’t even have any other script that changes any layers whatsoever in my project, so there shouldn’t be any chance of another script interfering with the layer change

You need to iterate what GetComponentsInChildren() returns and use each one individually.

Don’t use the var keyword because it is confusing you about the type(s) of your variables.

Be explicit and follow the documentation to find out what types methods return.

Also, break your longer code lines up.

If you have more than one or two dots (.) in a single statement, you’re just being mean to yourself.

How to break down hairy lines of code:

http://plbm.com/?p=248

Break it up, practice social distancing in your code, one thing per line please.

“Programming is hard enough without making it harder for ourselves.” - angrypenguin on Unity3D forums

“Combining a bunch of stuff into one line always feels satisfying, but it’s always a PITA to debug.” - StarManta on the Unity3D forums

Take advantage of your IDE; in many cases it is smart enough to not only tell you what the issue is, but to also fix the issue for you automatically.

8457548--1122452--Quick Actions.png

8457548--1122455--using System.Linq.png

8457548--1122449--Result.png

In this case the issue was that Select is an extension method in the System.Linq namespace, so you need to add using System.Linq; to the top of your file to import the extension method so that you can reference it in your class :slight_smile:

Both of the SetLayerRecursively extension methods you posted should work perfectly. You can do a simple test scene that contains nothing else than test component using SetLayerRecursively to verify that this is the case (reducing the number of moving pieces like this can help a lot when debugging issues). The issues you’re having must be related to something else rather than the code in SetLayerRecursively.

And the Linq code I posted is basically just a more succinct way of expressing this:

using System.Collections.Generic;
using UnityEngine;

public static class GameObjectExtensions
{
    public static void SetLayerRecursively(this GameObject @this, int layer)
    {
        var children = @this.GetComponentsInChildren<Transform>(true);
        var originalLayers = new List<int>(children.Length);
        foreach(var child in children)
        {
            var gameObject = child.gameObject;
            originalLayers.Add(gameObject.layer);
        }

        // change layer
        foreach(var child in children)
        {
            var gameObject = child.gameObject;
            gameObject.layer = layer;
        }

        // restore layer
        for(int i = 0, count = children.Length; i < count; i++)
        {
            Transform child = children[i];
            var gameObject = child.gameObject;
            gameObject.layer = originalLayers[i];
        }
    }
}