Unity Script: Find all Assets and Prefabs with a given Component by Type

Hi Xander here…

The current game in development is Endless Elevator. During the development cycle we have used a bunch of placeholder audio files and Audio.Play() functions. This is to get some quick auditory feedback from the game during testing phases. It’s much more fun to hear a gun go off and have the bullet zing past to impact on the wall and make a satisfying “Crack-Bang! Zoom! Whhhumppp!” noise than hearing nothing at all.

But now we are ramping up development of the noises and soundtracks in the game and while it’s not my favourite part (and not my skill set) I have enjoyed watching The Baron get all Foley artist. I recently witnessed the birth of a gun noise by repeatedly slamming a dryer door with a bunch of copper wire and a microphone taped to the inside. Game development is really fun and you get to do a shocking amount of creative weirdness. I digress.

Since we now have to start replacing all the temporary raw audio calls with some proper artistry, and serious sound work I had to find all those existing audio components out there in the project and add them to Unity Mixer channels. At the moment Endless Elevator is not huge but it’s not small either. There are are maybe a hundred prefabs sorted into four sub-folders in the Project explorer and I didn’t really want to go searching through them all and open up each one looking for Audio Sources. (Does anyone else find the new Prefab workflow of having to open up a prefab for editing a few clicks too many?)

So this script is my solution for finding all the Audio Sources in the project.

(I do like to make a Zulu heading in the Editor Window to run scripts from)

Finding Audio Sources in the Current Scene

Firstly I wanted to know how many Assets in the current scene had Audio Components. This wasn’t too hard as the game is mostly procedural (and endless…) so there isn’t too many objects to a scene in the Edior.

I’ll put the full script at the end but this is the code snippet to do that:

Debug.Log("Finding all Assets in the Current Scene that have an Audio Component...");
AudioSource[] myAudioSources = FindObjectsOfType(typeof(AudioSource)) as AudioSource[];
Debug.Log("Found " + myAudioSources.Length + " objects with an AudioSource attached");
        foreach (AudioSource item in myAudioSources)
        {
            Debug.Log(item.gameObject.name);
        }

The main function here is the FindObjectsOfType() which I rarely have cause to use but is perfect for this sort of thing. The output in the Console is shown below…

I also found a really useful tool on the Asset Store that looked interesting for those who need a bit more power for doing this: Asset Usage Detector. It looks pretty full featured and is free! Shout out and respect to the dev Süleyman Yasir Kula who has a whole heap of good looking tools up there.

Finding Audio Sources in Prefabs

The next bit took a longer to write. I had never really delved into the Asset Database API and I found it really interesting and a bit of an eye-opener. Which is why I decided to write it up in this post.

This is how I found all the Prefabs in my project with an Audio Component:

Debug.Log("Finding all Prefabs that have an Audio Component...");

string[] guids = AssetDatabase.FindAssets("t:Object", new[] { "Assets/Prefabs" });

        foreach (string guid in guids)
        {
            //Debug.Log(AssetDatabase.GUIDToAssetPath(guid));
            string myObjectPath = AssetDatabase.GUIDToAssetPath(guid);
            Object[] myObjs = AssetDatabase.LoadAllAssetsAtPath(myObjectPath);

            //Debug.Log("printing myObs now...");
            foreach (Object thisObject in myObjs)
            {
                //Debug.Log(thisObject.name);
                //Debug.Log(thisObject.GetType().Name); 
                string myType = thisObject.GetType().Name;
                if (myType == "AudioSource")
                {
                    Debug.Log("Audio Source Found in...  " + thisObject.name + " at " + myObjectPath);
                }
            }
        }

The first step was this line:

string[] guids = AssetDatabase.FindAssets(“t:Object”, new[] { “Assets/Prefabs” });

This makes an array of all the Objects under my Prefabs folder in the Project Hierarchy. You can replace t:Objects with any other Type but I was playing around with what I could find using this method so left it in there in case I wanted to look at other things. It’s also important to note that as the Audio Component is attached to a Game Object as a Component, and is not an Object in it’s own right, we have to reference the Object first so we can start to access the added components.

Next we get a reference to the path of the Object and use LoadAllAssetsAtPath to make an array of the “Assets” that we can start to interrogate. These are the active lines:

string myObjectPath = AssetDatabase.GUIDToAssetPath(guid);
Object[] myObjs = AssetDatabase.LoadAllAssetsAtPath(myObjectPath);

Next we run a foreach loop through those Objects and test for the AudioSource name in the component. The output in the console looks like this:

The Whole Script…

I’ll put the whole script below:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class FindAssets : MonoBehaviour
{
    // Find all object that have an Audio component

    [MenuItem("Zulu/FindAssets Audio")]
    static void FindAudio()
    {
        
        Debug.Log("Find Assets Script started...");
        // Find all Prefabs that have an Audio component under my Prefabs folder
        Debug.Log("Finding all Prefabs that have an Audio Component...");

        string[] guids = AssetDatabase.FindAssets("t:Object", new[] { "Assets/Prefabs" });

        foreach (string guid in guids)
        {
            //Debug.Log(AssetDatabase.GUIDToAssetPath(guid));
            string myObjectPath = AssetDatabase.GUIDToAssetPath(guid);
            Object[] myObjs = AssetDatabase.LoadAllAssetsAtPath(myObjectPath);

            //Debug.Log("printing myObs now...");
            foreach (Object thisObject in myObjs)
            {
                //Debug.Log(thisObject.name);
                //Debug.Log(thisObject.GetType().Name); 
                string myType = thisObject.GetType().Name;
                if (myType == "AudioSource")
                {
                    Debug.Log("Audio Source Found in...  " + thisObject.name + " at " + myObjectPath);
                }
            }
        }

        // Find all object that have an Audio component in the current Scene
        Debug.Log("Finding all Assets in the Current Scene that have an Audio Component...");
        AudioSource[] myAudioSources = FindObjectsOfType(typeof(AudioSource)) as AudioSource[];
        Debug.Log("Found " + myAudioSources.Length + " objects with an AudioSource attached");
        foreach (AudioSource item in myAudioSources)
        {
            Debug.Log(item.gameObject.name);
        }
    }
}

I should finish off that this is an Editor only tool and will not impact the performance of your game or blow out your memory by loading in all those assets (if you got heaps). Also make sure you put this script in a folder called Editor otherwise you build will fail 🙂

Enjoy and happy coding… Xander.

2 thoughts on “Unity Script: Find all Assets and Prefabs with a given Component by Type

  1. Thank you!

    I used this to make a more generic (and slow) any component finder in prefabs and scenes
    I don’t know how to pos code correctly, so I’m posting it as is here, sorry for that

    [MenuItem(“CONTEXT/Component/What uses this component?”, false, 10)]
    public static void WhatUsesThisComponent(MenuCommand command) {
    Component c = (Component) command.context;
    var typeToSearch = c.GetType();
    var typeString = c.GetType().Name;

    Debug.Log(“Finding all Prefabs and scenes that have the component ” + c.GetType() + “…”);

    string[] guids = AssetDatabase.FindAssets(“t:scene t:prefab”);

    int count = 0;

    for (int i = 0; i g.GetComponentsInChildren(typeToSearch, true)).ToArray();
    }
    else {
    myObjs = AssetDatabase.LoadAllAssetsAtPath(myObjectPath);
    }

    if (EditorUtility.DisplayCancelableProgressBar(“Searching in scenes/prefabs…”, count + ” matches. Progress: ” + i + ” / ” + guids.Length + “. Current: ” + asset.name, i / (guids.Length – 1f))) {
    goto End;
    }

    foreach (Object thisObject in myObjs) {
    if (typeToSearch.IsAssignableFrom(thisObject.GetType())) {
    Debug.Log(“” + typeString + ” Found in ” + thisObject.name + ” at ” + myObjectPath, asset);
    count++;
    break;
    }
    }

    if (asset is SceneAsset) {
    EditorSceneManager.ClosePreviewScene(s);
    }

    }

    End:
    EditorUtility.ClearProgressBar();
    }

Feel free to Comment