The title may be a little confusing but what I’d like to do is have an editor script that can access all game objects containing a script and control the properties of those scripts.
For example, I want an “audio manager” editor script that searches my scene for objects with an “audio property” script. This manager could then list them all out in the inspector and i could control the properties of each “audio property” script.
I’m terrible with editor scripts so any help would be great.
Well fix that first, starting with some tutorials. This stuff is fiddly to get right and you will iterate a LOT to get what you want.
If you just want a launching point for “do something to all X things in a scene,” here’s my starting point:
Read the warnings carefully and ALWAYS USE SOURCE CONTROL!
Great jumping point, thanks.
It’s very possible and in this particular instance, I would say easier to do with UI Toolkit than it is IMGUI.
Really it would be a case of a custom inspector that when it initialises, grabs all these components with FindObjectsOfType<T>
, and instances a UnityEditor.UIElements.InspectorElement
visual element for each instance, displaying them one after another (probably in a scroll view). This will display the inspector of each of them for editing.
But if you aren’t familiar with custom inspectors or UI Toolkit, I would definitely learn the basics of both, first.
Hey, I’ve written a basic script that demonstrates the behavior you’re looking for.
For sake of example lets say you have a MonoBehaviour called AudioProperty
.
Then you would make an EditorWindow
like so:
AudioManager.cs
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEngine.UIElements;
using UnityEngine.SceneManagement;
using UnityEditor.SceneManagement;
public class AudioManager : EditorWindow
{
private List<(GameObject, Editor)> audioProperties;
[MenuItem("Tools/AudioManager")]
static void Init()
{
AudioManager window = (AudioManager)EditorWindow.GetWindow(typeof(AudioManager));
// populate the scene objects list
window.audioProperties = new();
Scene activeScene = EditorSceneManager.GetActiveScene();
GameObject[] rootGameObjects = activeScene.GetRootGameObjects();
foreach (GameObject go in rootGameObjects)
{
// if the game object contains an audio property component, add it to our list and create a new editor for it
AudioProperty[] audioProps = go.GetComponentsInChildren<AudioProperty>();
if (audioProps.Length == 0)
continue;
foreach (AudioProperty audioProp in audioProps)
{
window.audioProperties.Add((go, Editor.CreateEditor(audioProp)));
}
}
}
void OnGUI()
{
// draw the audio properties
foreach ((GameObject go, Editor editor) in audioProperties)
{
EditorGUILayout.BeginVertical();
EditorGUILayout.LabelField($"{go.name}");
editor.DrawDefaultInspector();
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
}
}
// clean up when window is closed
void OnDestroy()
{
foreach ((GameObject go, Editor editor) in audioProperties)
DestroyImmediate(editor);
audioProperties.Clear();
}
}
To break it down:
- We use the
EditorSceneManager
class to get the currently open scene in the editor. - We find all the game objects in the scene with the
AudioProperty
component and create a new Editor instance for each one. This is what will allow us to make edits that get saved. - We draw the inspector for each audio property editor we created
Now when you open the AudioManager
window by going to Tools > Audio Manager, you will be able to edit the fields for each of the AudioProperty
objects.
Some improvements you could make are refreshing the window when the editor scene changes, cleaning up the gui of the objects, etc.
Hope this helps!
This looks great. Thanks for the script! I’ll give it a shot when I get back to my desk.