简体   繁体   English

在 Unity 检查器中绘制没有明确类型信息的对象作为属性

[英]Draw objects without explicit type info as property in Unity inspector

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 .我在使用UnityEvent时遇到了困难,因为它对多参数方法和异步逻辑的支持很差,所以我正在编写我自己的版本,它被建模为ScriptableObject的派生 class。

// 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.) (你可以假设我已经过滤掉了所有那些不可绘制的方法 arguments,所以我们要绘制的每个参数都必须有一个对应的自定义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;问题来了:因为我所有的 arguments 都存储在List<object>中,通过SerializedProperty访问它们会丢失类型信息; I can manually convert them to UnityEngine.Objects and then SerializedObject though (regardless of the edgecases of prmitive values like int s or Vector3 s), 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 .我可以手动将它们转换为UnityEngine.Objects ,然后再转换为SerializedObject (不管int s 或Vector3 s 等原始值的边缘情况),但这样做会使我们忘记修改后的值,因为EditorGUI.PropertyField并没有真正返回值,而不是我们必须使用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 .我在想也许有一些神奇的功能可以告诉我任何给定的System.Type对应的PropertyDrawer是什么。 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.完成后,我会将其作为个人工具包在 GitHub 上开源。

Edit : I've managed to implement such thing successfully in Unity.编辑:我已经成功地在 Unity 中实现了这样的事情。 See my GitHub repo .请参阅我的GitHub 回购协议

How are you going to serialize List<object> ?你打算如何序列化List<object> Isn't the plan collapse at this point?难道计划到这里就崩溃了吗?

I guess the whole idea is possible with a new class SerializedArgument or alike.我想整个想法可以通过新的 class SerializedArgument或类似的东西来实现。 It should contain dedicated fields for all possible types of arguments (like SerializedProperty has fields for many types).它应该包含 arguments 的所有可能类型的专用字段(如SerializedProperty有许多类型的字段)。 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 .我认为List<SerializedArgument>的序列化和使用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 .关于为给定的System.Type或类型和SerializedProperty获取PropertyDrawer There are methods that allow you to get it.有一些方法可以让你得到它。 But they are internal for UnityEditor, if I understood it correctly.但如果我理解正确的话,它们是 UnityEditor 的内部。 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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM