- Home /
Manually Tracking a Custom Editor
I've been messing around with Unity's custom editor system, and decided to try keeping Editors around after an object is unselected, so empty objects with no geometry have handles to select them, as well as other functionalities. I know this isn't the intended use of the Editor's functions, and would be better suited as a manager that stores all related objects, but this is more of an exercise than anything.
However, there's been a problem. As far as I can tell, there are two ways to spawn an editor script with a Component as its target: first, the regular way is to select an object. I've tried doing this on load, cycling through and selecting each object and giving each a frame to register the new Editor. This is clunky with a few GameObjects and messy with many. The other way to add an Editor is to just use Editor.CreateEditor()
. While this creates an object with the Component as its target and allows me to draw Handles using onSceneGUIDelegate
, it doesn't send the OnInspectorGUI()
message.
As far as I can tell looking at the exposed C# source of Unity, inspector drawing is done by looking through a list of tracked editors through ActiveEditorTracker.sharedTracker.activeEditors
. I've logged it, and it's apparent that none of my custom editors are tracked, even the one that's associated with the selected GameObject. This is a read-only array, and there's no exposed functions I can see to add editors to this tracker manually. Is there some functionality to manually track and untrack active editors, or is this functionality entirely unexposed for the moment?
I'm not sure exactly what you're after, but maybe EditorWindow could be a first step?
Also have a look at Gizmos, which may or may not be better than Handles in your case.
Gizmos have no functionality to handle input events, they're purely for display, so they won't do. Editor Windows need to be opened separately rather than being a part of the main scene editor, so that falls short too.
If anyone's dealing with similar problems, I still haven't found a solution but I'm using a workaround: have an unselected and selected script for the editor. Spawn the unselected script for every GameObject, and disable it when the object is selected. The selected script should be marked as a CustomEditor and will be spawned and tracked when that object is selected. When the selected editor is destroyed, simply reenable the unselected editor. This is clunky and it would be better to have a way to track and untrack the same editor manually, but this is the best workaround I can think of for the moment.
Answer by Jamora · Jul 29, 2018 at 12:21 PM
Your question intriques me because I'm all for these little tweaks to Unity as well.
From what I gather, you want to have an inspector-like view visible at all times, with no manual creation required and have certain gameobjects drawn with handles or other stuff in OnSceneGUI, even when they're not selected. This can be done with EditorWindows. Below is the code which satisfies the above conditions.
The editor window targets CustomScript
, which is a normal MonoBehaviour. The Editor window is only shown if there is at least one CustomScript
in the Scene and disappears when the last one is deleted (because why have an editor if there's nothing to edit). The editorWindow also acts as a second inspector for CustomScript
, if a GO containing one is selected and shows something else when something else is selected. Although I added a menu item, no manual creation or removal is needed apart from adding a script to the scene.
Hope it gives you ideas, it was an interesting exercise regardless.
using UnityEngine;
using UnityEditor;
[InitializeOnLoad]
public class CustomEditorWindow : EditorWindow
{
static CustomEditorWindow window;
bool myBool = true;
static CustomEditorWindow()
{
//this won't ever be removed
EditorApplication.hierarchyChanged += CheckChanges;
}
// Add menu named "My Window" to the Window menu. Just for shows.
[MenuItem("Window/My Window")]
static void Init()
{
window = (CustomEditorWindow)EditorWindow.GetWindow(typeof(CustomEditorWindow));
window.Show();
}
static void CheckChanges() {
CustomScript[] r = GameObject.FindObjectsOfType<CustomScript>();
if (r.Length == 0 && window != null)
{
window.Close();
window = null;
}
else {
Init();
}
}
private void OnEnable()
{
SceneView.onSceneGUIDelegate += SceneGUI;
}
/*
* This is updated 10 times per second or so.
* If every frame is needed, add a function to the EditorApplication.update delegate in OnEnable.
*/
void OnInspectorUpdate()
{
Repaint();
}
void OnGUI()
{
GameObject target = Selection.activeGameObject;
if (target != null && target.GetComponent<CustomScript>() != null){
Editor e = Editor.CreateEditor(target.GetComponent<CustomScript>());
e.OnInspectorGUI();
}
else {
myBool = EditorGUILayout.Toggle("Toggle", myBool);
}
}
void SceneGUI(SceneView view)
{
CustomScript[] go = GameObject.FindObjectsOfType<CustomScript>();
foreach (CustomScript p in go)
{
Handles.Label(p.transform.position, "Visible label");
Handles.DrawLine(p.transform.position, Vector3.zero);
Handles.ArrowHandleCap(GUIUtility.GetControlID(FocusType.Keyboard), p.transform.position, Quaternion.LookRotation((Vector3.zero - p.transform.position).normalized, Vector3.back), 2, EventType.Repaint);
}
}
void OnDestroy()
{
SceneView.onSceneGUIDelegate -= SceneGUI;
}
}
Oh, I should've looked closer into EditorWindows... This is probably more efficient than having an Editor for every object anyway! Ideally I wanted to have the inspector information drawn in the default Inspector tab, but I suppose that's just not an option right now. Thank you for this workaround, it will work nicely.
Your answer
Follow this Question
Related Questions
Adding dropdown to a list add buttom 2 Answers
Unity Editor interface implementation selector? 1 Answer
Custom Editor has stopped working 1 Answer
Object references in a custom editor 2 Answers
Custom Inspector Raycasting 1 Answer