Hello! I have a Node based system that I am trying to create, to help me with creating AI easier. So I decided to also add a custom inspector for it. But I am having trouble with assigning values to PropertyFields.
- When I first tried it, I basiclly used the following, since I saw it on some tutorials:
public class InspectorView : VisualElement
{
public new class UxmlFactory : UxmlFactory<InspectorView, VisualElement.UxmlTraits> { }
private Editor editor;
public InspectorView() { }
/// <summary>
/// This function creates an unity editor and places it inside our InspectorView
/// </summary>
/// <param name="nodeView"></param>
internal void UpdateSelection(NodeView nodeView)
{
// Clears any previous selection
Clear();
// Destroy the previous editor instance if it exists
if (editor != null)
{
UnityEngine.Object.DestroyImmediate(editor);
}
// Create a new custom editor for the selected node
editor = Editor.CreateEditor(nodeView.node, typeof(InspectorEditor));
// Create an IMGUI container
IMGUIContainer container = new IMGUIContainer(() =>
{
if (editor.target)
{
// Begin the inspector GUI
editor.OnInspectorGUI();
}
});
}
At first it looked like it was working well! (Never speak too soon). I managed to basicly control and modify fields like int, float, string etc. Just like the default inspector.
But some of my nodes of course had parts like Transform, NavMeshAgent, List<>.
And when I tried to modify those parts- it basically refused. I couldnt drag anything to those fields from hierarchy or modify them in any way.
So, back to the drawing board. I tried other stuff like DragAndDrop etc. but couldnt make it work.
So in the end I decided to use ObjectField. Because for some reason, ObjectField seem to work, I could drag items to it from the hierarchy, assign items to it etc. etc.
Now only problem was OnInspectorGUI was also creating fields for those objects, so it was getting duplicated.
So- I basically decided to create a new class that inherits from Editor and use it instead so I can override the OnInspectorGUI since those fields created inside OnInspectorGUI didnt work.
- Following is the new InspectorEditor file I created:
using UnityEditor;
[CustomEditor(typeof(Node), true)]
public class InspectorEditor : Editor
{
public override void OnInspectorGUI()
{
EditorGUI.BeginChangeCheck();
serializedObject.UpdateIfRequiredOrScript();
SerializedProperty iterator = serializedObject.GetIterator();
bool enterChildren = true;
while (iterator.NextVisible(enterChildren))
{
if (iterator.propertyType == SerializedPropertyType.ObjectReference) continue;
using (new EditorGUI.DisabledScope("m_Script" == iterator.propertyPath))
{
EditorGUILayout.PropertyField(iterator, true);
}
enterChildren = false;
}
serializedObject.ApplyModifiedProperties();
EditorGUI.EndChangeCheck();
}
}
I kinda copied the DrawDefaultInspectorFunction, (which I think was called by default?) and added this part:
if (iterator.propertyType == SerializedPropertyType.ObjectReference) continue; so it bypasses any Objects or not Generic types (I think?). Which worked, it no longer created SerializedProperties for stuff like Transform, NavMeshAgent, MeshCollider etc. etc.
- And after that, I modified my original file so they fit together:
public class InspectorView : VisualElement
{
public new class UxmlFactory : UxmlFactory<InspectorView, VisualElement.UxmlTraits> { }
private Editor editor;
public InspectorView() { }
/// <summary>
/// This function creates an unity editor and places it inside our InspectorView
/// </summary>
/// <param name="nodeView"></param>
internal void UpdateSelection(NodeView nodeView)
{
// Clears any previous selection
Clear();
// Destroy the previous editor instance if it exists
if (editor != null)
{
UnityEngine.Object.DestroyImmediate(editor);
}
// Create a new custom editor for the selected node
editor = Editor.CreateEditor(nodeView.node, typeof(InspectorEditor));
// Create an IMGUI container
IMGUIContainer container = new IMGUIContainer(() =>
{
if (editor.target)
{
// Begin the inspector GUI
editor.OnInspectorGUI();
}
});
// Add the container to the InspectorView
Add(container);
FieldInfo[] fields = editor.target.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.GetField);
foreach (FieldInfo field in fields)
{
if (!typeof(UnityEngine.Object).IsAssignableFrom(field.FieldType)) {
continue;
}
ObjectField objectField = new ObjectField(field.Name[0].ToString().ToUpper() + field.Name.Substring(1))
{
objectType = field.FieldType,
value = field.GetValue(editor.target) as UnityEngine.Object
};
objectField.RegisterValueChangedCallback(evt =>
{
field.SetValue(editor.target, evt.newValue);
});
Add(objectField);
}
}
}
So in following code, I get all the FieldInfo’s from the editor.target and use that information to create ObjectFields.
And it worked (kinda). I can finally assign gameObjects properly in my node inspector. But Lists still have problems. Some of my nodes use fields like List and those parts are still handled inside the OnInspectorGUI.
I tried to use ObjectFields for it, but I guess ObjectFields dont like lists xd. Or I am doing something wrong.
Anyways! After that long explanation I have some questions.
- First of all, I dont like the way I handle this, since its still broken and I am kinda new to Unity so, I would be grateful if there are any better ways.
- I guess my second question is tied to my first question but still: How can I make this work for lists as well.
