How to find all objects in specific layer?

I know how to do that with tags, but in my case I would need to use layers since I’m already using tags for other purposes on those objects.

Is there a way to return the amount of objects in a specific layer?

Thanks for your time!
Stephane

There’s no built-in function, so you have to make your own. You can get all gameobjects, and iterate through them to find the ones with the specified layer, like this:

Note: Code below is not C# but not obsolete JS-like Unity Script.
function FindGameObjectsWithLayer (layer : int) : GameObject[]
{
    var goArray = FindObjectsOfType(GameObject);
    var goList = new System.Collections.Generic.List.<GameObject>();
    for (var i = 0; i < goArray.Length; i++)
    {
        if (goArray[i].layer == layer) { goList.Add(goArray[i]); }
    }
    if (goList.Count == 0) { return null; }
    return goList.ToArray();
}

I needed a solution that would let me find all objects that were inactive, and I was doing it from an EditorWindow, so I had to take a different route, using GetComponentsInChildren() and supplying a root game object to check within:

private static List GetObjectsInLayer(GameObject root, int layer)
{
	var ret = new List();
	foreach (Transform t in root.transform.GetComponentsInChildren(typeof(GameObject), true))
	{
		if (t.gameObject.layer == layer)
		{
			ret.Add (t.gameObject);
		}
	}
	return ret;
}

For using inside the Update call, I suggest making a class and inheriting all your scripts from it instead of MonoBehaviour. In this class you can create caches specific to each layer:

public class LayeredMonoBehaviour : MonoBehaviour
{
    private static IDictionary<int, IList<GameObject>> layersCache = new Dictionary<int, IList<GameObject>>();
  
    /**
     * Returns a list of all (active/inactive) GameObjects of the specified layer. Returns null if no GameObject was found.
     */
    public static IList<GameObject> FindGameObjectsWithLayer(int layer)
    {           
        return layersCache[layer];
    }
  
    /**
     * Returns one GameObject with the specified layer. Returns null if no GameObject was found.
     */
    public static GameObject FindWithLayer(int layer)
    {
        var cache = layersCache[layer];
        if (cache != null && cache.Count > 0)
            return cache[0];
        else
            return null;
    }
  
    protected void Awake()
    {
        // careful: this code assumes that your GameObjects won't change layer during gameplay.
        IList<GameObject> cache;
        if (!layersCache.TryGetValue(gameObject.layer, out cache))
        {
            cache = new List<GameObject>();
            layersCache.Add(gameObject.layer, cache);
        }
  
        cache.Add(gameObject);
    }
  
    protected void OnDestroy()
    {
        layersCache[gameObject.layer].Remove(gameObject);
    }
}

The disadvantage is that you’ll have to override Awake and OnDestroy and call base’s implementation if you intend to use these methods in your scripts; but in general this is a good strategy and during the development of your game you may find other stuff that you want to add to this parent class that you wouldn’t be able to do with extension methods for the regular MonoBehaviour.

It’s also important to note that it won’t work for GameObjects that doesn’t have any scripts attached to it!

I wanted an editor solution that didn’t make me specify root.

Layer 31 is hardcoded.

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
  
public class GetAllObjectsInLayer : MonoBehaviour 
{
	
	public static int layer = 31;
	
	[MenuItem("Tools/Select Objects in Layer 31", false, 50)]
	public static void SelectObjectsInLayer()
	{
		var objects = GetSceneObjects();
		GetObjectsInLayer(objects, layer);
	}
  
     private static void GetObjectsInLayer(GameObject[] root, int layer)
     {
         List<GameObject> Selected = new List<GameObject>();
         foreach (GameObject t in root)
         {
             if (t.layer == layer)
             {
                 Selected.Add(t);
             }
         }
         Selection.objects = Selected.ToArray();
  
     }
  
	private static GameObject[] GetSceneObjects()
	{
		return Resources.FindObjectsOfTypeAll<GameObject>()
				.Where(go => go.hideFlags == HideFlags.None).ToArray();
	}
}

Just to correct

static List<GameObject> GetObjectsInLayer(GameObject root, int layer)
{
    var ret = new List<GameObject>();
    foreach (Transform t in root.transform.GetComponentsInChildren(typeof(GameObject), true))
    {
        if (t.gameObject.layer == layer)
        {
            ret.Add(t.gameObject);
        }
    }
    return ret;
}

Easiest way to do it is with Linq To GameObject package. It’s free. This is how I do it.

void Start()
{           
  _walkableGameObjects = GetGameObjectsInLayer("Ground");
}

public List<GameObject> GetGameObjectsInLayer(string layerName)
{
  List<GameObject> allObjectsInLayer = new List<GameObject>();
  
  //works
  allObjectsInLayer = GameObject.Find("SCENE ROOT").Descendants().Where(t=>t.layer == LayerMask.NameToLayer(layerName)).ToList();

  Debug.Log($"<color=blue>there are {allObjectsInLayer.Count} items on the ground layer</color>");

  return allObjectsInLayer;
}

I needed a C# version, displayed in the Editor menu (Tools), to simply create an inventory of game objects by layer. Here’s the code (it should be part of a class that extends Editor class and is inside the "Editor" folder):

[MenuItem("Tools/Show Objects in each Physics Layer")]
public static void FindGameObjectsWithLayer() {
    Dictionary<int, List<string>> gameObjects = new();

    Debug.Log($"Scanning objects...");

    foreach (var gameObject in GameObject.FindObjectsOfType<GameObject>(true))
    {
        int layer = gameObject.layer;
        if (!gameObjects.TryGetValue(layer, out List<string> objects))
        {
            objects = new();
            gameObjects.Add(layer, objects);
        }
        objects.Add(gameObject.name);
    }

    Debug.Log($"Done.");

    foreach (var layer in gameObjects.Keys)
    {
        Debug.Log(
            $"Layer ({layer}): {LayerMask.LayerToName(layer)}: {gameObjects[layer].Count} objects\n" +
            $"{string.Join("\n- ", gameObjects[layer])}");
    }
}