Home > Software engineering >  Draw objects without explicit type info as property in Unity inspector
Draw objects without explicit type info as property in Unity inspector

Time:11-27

I was having hard time with UnityEvent, due to its bad support for many-argument methods and asynchronous logic, so I'm writing my own version of it, which is modeled as a derived class of ScriptableObject.

// Technically there would be more kinds of Callback,
// including a wrapper class for the legacy UnityEvent.
// But for the example's sake I'll just keep thing simple.
public class SimpleCallback : ScriptableObject {
    public Object target;
    public MethodInfo method;
    public List<object> arguments;

    public override IEnumerator Invoke() {
            if(target == null || method == null)
            return null;
                // TODO: Should be asynchronous when method is meant to be a coroutine.
        method.Invoke(target, arguments);
        return null;
    }
}

Now I'm writing a custom property drawer for it. This drawer should draw each argument of the selected method in the inspector as field slots. (You can assume that I've already filtered out all those methods with non-drawable arguments, so that every argument that we're going to draw must have a corresponding custom PropertyDrawer class.)

Here comes the problem: since all my arguments are stored in a List<object>, accessing them via SerializedProperty would lose the type information; I can manually convert them to UnityEngine.Objects and then SerializedObject though (regardless of the edgecases of prmitive values like ints or Vector3s), but doing so would make us lost track of the modified value, since EditorGUI.PropertyField doesn't really return the value, rather we'd have to retrieve it with SerializedObject.ApplyModifiedProperties.

I'm thinking perhaps there are some magical functions that can tell me what is the corresponding PropertyDrawer for any given System.Type. I can then cached a bunch of children drawers in my callback drawer. Or maybe there's some other better ways? Please let me know, thanks! I'll make it open-sourced on GitHub as a personal toolkit when it's done.

Edit: I've managed to implement such thing successfully in Unity. See my GitHub repo.

CodePudding user response:

How are you going to serialize List<object>? Isn't the plan collapse at this point?

I guess the whole idea is possible with a new class SerializedArgument or alike. It should contain dedicated fields for all possible types of arguments (like SerializedProperty has fields for many types). And field of type (just name or index to determine which field is useful for certain argument instance) with it. I think there will be no problem with serialization of List<SerializedArgument> and using SerializedObject.ApplyModifiedProperties. Just this objects could be pretty huge. And I'm not saying that this is a good approach.

About getting PropertyDrawer for given System.Type or type and SerializedProperty. There are methods that allow you to get it. But they are internal for UnityEditor, if I understood it correctly. Look here.

[Serializable]
public class SerializedArgument
{
    public string ArgType;

    //It's not so hard to access SerializedProperties you need from this class
    //And in case of custom property drawers you can draw only one prop at time according to type
    [SerializeField] int m_IntArg;
    [SerializeField] float m_FloatArg;
    [SerializeField] Vector3 m_Vector3Arg;
    //Paste more fields here
    
    public int IntArg
    {
        get => m_IntArg;
        set
        {
            ArgType = typeof(int).FullName;
            m_IntArg = value;
        }
    }
    //Paste more Props here
}
  • Related