I would like to draw a property right after instantiation, without reference to any Object. I saw that in Odin it is possible to do this using a PropertyTree, but I would like to get the same result without depending on this Asset.
I’ve tried every way, but I can only do this using SerializedObject or SerializedProperty, both depend on Object for this, and I would like the object itself to be fully independent of inheritances or context.
Here is the example of the object I’m trying to draw.
[Serializable]
public class Test
{
[SerializeField] public GameObject go;
[SerializeField] public int integer;
}
public class TestDrawer : EditorWindow
{
private Test test;
private void OnEnable()
{
test = new Test();
}
private void CreateGUI()
{
// TODO: Draw test by VisualElement
}
private void OnGUI()
{
// TODO: Draw test by GUI
}
}
This is drawable, because content.Target inherits from ScriptableObjects, so it also inherits from UnityEngine.Object, and that lets me use Editor.CreateEditor(); However this is not possible with objects that do not inherit anything.
Using Odin’s PropertyTree this is possible, you can pass any type of object, regardless of its inheritance and the Editor is able to draw it perfectly.
I would like to be able to create the right panel from any type of object, but without Odin, using only Unity’s base classes. How can I do this?
If it is possible to do this using PropertyDrawers please show me
So if the object is not a Unity Object you’ll need to handle it differently. There’s no one size fits all solution here, as you’ll probably have other edge cases to deal with.
Needless to say Odin spoils us a bit with it’s far better systems.
Well Unity can only know what to draw if it has access to the data structure of the object. You will still need access to the root UnityEngine.Object (as all serialisation starts at the root Unity object), after which you can find the appropriate SerializedProperty like so: https://docs.unity3d.com/ScriptReference/SerializedObject.FindProperty.html
Again, no one size fits all solution here. It’s going to take a bit of work.
1 - Instantiating a ScriptableObject with my object inside, in this case “instance” was not able to find the property’s path. Declaring it finds the path, but that way doesn’t solve my problem, because I need to work with object.
public class DevelopmentToolsWindow : EditorWindow
{
// Show Window code here...
public void CreateGUI()
{
DrawProperty<LevelDesignTools>(rootVisualElement);
}
private void DrawProperty<T>(VisualElement root)
{
MyTestObject myObj = ScriptableObject.CreateInstance<MyTestObject>();
instance.Set<T>();
SerializedObject serializedObject = new SerializedObject(myObj);
PropertyField property = new PropertyField();
property.bindingPath = nameof(myObj.instance);
property.Bind(serializedObject);
root.Add(property);
}
}
public class MyTestObject : ScriptableObject
{
[SerializeField] public object instance;
[SerializeField] public LevelDesignTools test;
public void Set<T>()
{
instance1 = Activator.CreateInstance(typeof(T));
}
}
2 - It also doesn’t work with a generic type, because it is not possible to instantiate MyTestGeneric and you end up falling in the first case if you inherit from the “object” type
public class MyTestGeneric<T> : ScriptableObject
{
[SerializeField] public T instance1;
[SerializeField] public LevelDesignTools instance2;
}
public class MyObject : MyTestGeneric<object> { }
Well it’s not going to work because Unity’s default SerializeField cannot serialise System.Object. You might want to try SeralizeReference in that case.
Remember the whole system works around Unity’s ability to read the object’s serialised data structure. If it’s not being serialised it won’t work.
I will say, you could probably do this without the need to make wrapper objects.
So long as you have access to the unity object this data is stored in, you can walk along it’s entire serialised property structure and just draw them. How you select these properties is another matter, but definitely not impossible.