Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/unity3d/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在CustomPropertyDrawer中设置SerializedProperty.propertyType_C#_Unity3d_Unity3d 2dtools_Unity Editor - Fatal编程技术网

C# 如何在CustomPropertyDrawer中设置SerializedProperty.propertyType

C# 如何在CustomPropertyDrawer中设置SerializedProperty.propertyType,c#,unity3d,unity3d-2dtools,unity-editor,C#,Unity3d,Unity3d 2dtools,Unity Editor,我正在使用这两个库: Unity SerializableDictionary: 统一场景参考: 基本上,serializable dictionary查看propertyType以确定是否可以扩展该属性,并进行以下检查: static bool CanPropertyBeExpanded(SerializedProperty property) { switch(property.propertyType) { case SerializedPropertyTy

我正在使用这两个库:

  • Unity SerializableDictionary:

  • 统一场景参考:

基本上,serializable dictionary查看propertyType以确定是否可以扩展该属性,并进行以下检查:

static bool CanPropertyBeExpanded(SerializedProperty property)
{
    switch(property.propertyType)
    {
    case SerializedPropertyType.Generic:
    case SerializedPropertyType.Vector4:
    case SerializedPropertyType.Quaternion:
        return true;
    default:
        return false;
    }
}
但是,场景引用似乎已注册为可扩展属性,即使它不是。这是因为——显然——Unity将其注册为类型
Generic

我可以通过将
SerializedProperty.propertyType
设置为更有意义的类型来解决这个问题,但它是只读的


那么,如何设置自定义属性抽屉的
序列化属性.propertyType

public class Test
{
   public string stringProperty;
}
现在,尝试设置propertyType基本上就像试图告诉编译器更改类的属性类型,这是不可能的,因为它已经被写为“string”

你能做的就是

static bool CanPropertyBeExpanded(SerializedProperty property)
{
   float height = EditorGUI.GetPropertyHeight(property);
   // Property expandable if its height is twice the single line height.
   return height >= EditorGUIUtility.singleLineHeight * 2;
}

它没有文档记录,但是类型
Generic
会自动分配给任何自定义类(例如
场景引用
)。您不能更改
属性类型,因为它是只读的。。。您不能告诉编译器将您的自定义类作为其他对象处理

即使如果你可以。。。什么是“更有意义的类型”?的可用类型是有限的,对于自定义类来说,没有一种类型更有意义


这里的主要“问题”是:

SerializableDictionary
抽屉简单地假设,如果您有一个自定义(
Generic
)类,而没有自定义的
PropertyDrawer
,那么使用默认抽屉,它的行为与
四元数
Vector4
的默认抽屉完全相同:

  • 它的第一行有标签和折页
  • 字段/内容绘制在下方,且仅当属性折叠时绘制
由于
SceneReference
的抽屉未实现此行为,因此它被绘制在字典的键字段顶部


因此,作为最简单的修复方法,您当然可以简单地删除

case SerializedPropertyType.Generic:
因此,
sceneaset
(以及所有其他自定义类)被视为一个正常的未展开字段-这是一个品味问题


或者,您可以更改
SceneReference
PropertyDrawer
,以反映四元数的行为,例如
Quaternion

  • 添加一个带有标签的
    EditorGUI.Foldout
    ,该标签将更改
    属性.isExpaned
  • 将任何内容移到下面一行(可选)
  • 如果(!property.isExpanded)
可能看起来像:

// Made these two const btw
private const float PAD_SIZE = 2f;
private const float FOOTER_HEIGHT = 10f;

public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
    // Move this up
    EditorGUI.BeginProperty(position, GUIContent.none, property);
    {
        // Here we add the foldout using a single line height, the label and change
        // the value of property.isExpanded
        property.isExpanded = EditorGUI.Foldout(new Rect(position.x, position.y, position.width, lineHeight), property.isExpanded, label);

        // Now you want to draw the content only if you unfold this property
        if (property.isExpanded)
        {
            // Optional: Indent the content
            //EditorGUI.indentLevel++;
            //{

            // reduce the height by one line and move the content one line below
            position.height -= lineHeight;
            position.y += lineHeight;

            var sceneAssetProperty = GetSceneAssetProperty(property);

            // Draw the Box Background
            position.height -= FOOTER_HEIGHT;
            GUI.Box(EditorGUI.IndentedRect(position), GUIContent.none, EditorStyles.helpBox);
            position = boxPadding.Remove(position);
            position.height = lineHeight;

            // Draw the main Object field
            label.tooltip = "The actual Scene Asset reference.\nOn serialize this is also stored as the asset's path.";


            var sceneControlID = GUIUtility.GetControlID(FocusType.Passive);
            EditorGUI.BeginChangeCheck();
            {
                // removed the label here since we already have it in the foldout before
                sceneAssetProperty.objectReferenceValue = EditorGUI.ObjectField(position, sceneAssetProperty.objectReferenceValue, typeof(SceneAsset), false);
            }
            var buildScene = BuildUtils.GetBuildScene(sceneAssetProperty.objectReferenceValue);
            if (EditorGUI.EndChangeCheck())
            {
                // If no valid scene asset was selected, reset the stored path accordingly
                if (buildScene.scene == null) GetScenePathProperty(property).stringValue = string.Empty;
            }

            position.y += paddedLine;

            if (!buildScene.assetGUID.Empty())
            {
                // Draw the Build Settings Info of the selected Scene
                DrawSceneInfoGUI(position, buildScene, sceneControlID + 1);
            }

            // Optional: If enabled before reset the indentlevel
            //}
            //EditorGUI.indentLevel--;
        }
    }
    EditorGUI.EndProperty();
}

public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
    var sceneAssetProperty = GetSceneAssetProperty(property);
    // Add an additional line and check if property.isExpanded
    var lines = property.isExpanded ? sceneAssetProperty.objectReferenceValue != null ? 3 : 2 : 1;
    // If this oneliner is confusing you - it does the same as
    //var line = 3; // Fully expanded and with info
    //if(sceneAssetProperty.objectReferenceValue == null) line = 2;
    //if(!property.isExpanded) line = 1;

    return boxPadding.vertical + lineHeight * lines + PAD_SIZE * (lines - 1) + FOOTER_HEIGHT;
}

现在看起来像是

[Serializable]
public class TestDict : SerializableDictionary<string, SceneReference> { }

public class Example : MonoBehaviour
{
    public SceneReference NormalReference;

    public TestDict DictExample = new TestDict();
}
[可序列化]
公共类TestDict:SerializableDictionary{}
公共课示例:单一行为
{
公共场景引用规范引用;
public TestDict DictExample=new TestDict();
}



由于此
场景引用
属性基本上有两行,因此不会对检查器中的行为造成太大的更改。嘿,感谢您的努力。您想在GitHub上以PR的形式发送此邮件吗?我希望你的名字能作为贡献者出现在那里。@S.Tarıkıetin不客气!将其添加到git。顺便说一句,我在SerializedDictionary中也遇到了一个错误:当我的键名发生冲突(由于两个都是空字符串)并在上下文菜单中点击
Reset
时,我遇到了很多异常,它是不可更改的(除了注释断开的字典并重新编译),谢谢!!