首页 > 解决方案 > 如何在统一自定义编辑器中从一组可编写脚本的对象中获取值?

问题描述

我正在尝试制作自定义编辑器,但无法从数组中的可编写脚本对象中获取值。这是包含 CharacterData 可脚本化对象的 FightData 脚本。

public class FightData : ScriptableObject {
    public CharacterData [] enemyDatas;
}

CharacterData 包含统计信息。

public class CharacterData : ScriptableObject {

    public CharacterStats stats;
}

这是 CharacterStats

[System.Serializable]
public class CharacterStats
{
    public float HP;
    public float damage;
    public float defense;
    public float attackInterval;

    public CharacterStats(){
        HP = 0f;
        damage = 0f;
        defense = 0f;
        attackInterval = 2f;
    }
}

我想总结所有统计数据并将它们显示在 FightData 的自定义编辑器中。但统计数据始终为空。这是我的方法:

[CustomEditor(typeof(FightData))]
public class FightDataEditor : Editor
{
    SerializedProperty _enemyDatas;


    private void OnEnable() {  
        _enemyDatas = serializedObject.FindProperty("enemyDatas");     
    }

    public override void OnInspectorGUI(){
        serializedObject.Update();
        EditorGUILayout.PropertyField(_enemyDatas);

        var result = 0f;
        int length = _enemyDatas.arraySize;
        for (int i = 0; i < length; i++)
        {
            SerializedProperty stats = _enemyDatas.GetArrayElementAtIndex(i).serializedObject.FindProperty("stats");
            if(stats == null){
                Debug.Log(stats);
                continue;
            }
            result += stats.FindPropertyRelative("HP").floatValue;
            result += stats.FindPropertyRelative("damage").floatValue;
            result += stats.FindPropertyRelative("defense").floatValue;
        }

        EditorGUILayout.Space(); 
        EditorGUILayout.LabelField("Total Power", EditorStyles.boldLabel);
        EditorGUILayout.FloatField(result);

 
        serializedObject.ApplyModifiedProperties();
    }
}

标签: c#unity3dunity-editorunity3d-editorscriptable-object

解决方案


FindPropertyRelative只有当它实际上是一个被序列化为 YAML 值的嵌套“普通”序列化类时才会起作用。

但是对于ScriptableObject(通常任何继承自的UnityEngine.Object)您存储的不是序列化,而只是UnityEngine.Object 参考

您宁愿需要获得相应的SerializedObject实例,例如

[CustomEditor(typeof(FightData))]
public class FightDataEditor : Editor
{
    SerializedProperty _enemyDatas;


    private void OnEnable() 
    {  
        _enemyDatas = serializedObject.FindProperty("enemyDatas");     
    }

    public override void OnInspectorGUI()
   {
        serializedObject.Update();
        EditorGUILayout.PropertyField(_enemyDatas);

        var result = 0f;
        int length = _enemyDatas.arraySize;
        for (int i = 0; i < length; i++)
        {
            // Get the element SerializedProperty
            var element = _enemyDatas.GetArrayElementAtIndex(i);

            // The field exists but no object is referenced
            if(!element.objectReferenceValue)
            {
                continue;
            }

            // otherwise get a serialized object for this reference
            var sObj = new SerializedObject(element.objectReferenceValue);

            // stats is now a property of that serialized object
            var stats = sObj.FindProperty("stats");

            // The other values are now further nested properties of the serialized CharacterStats class
            result += stats.FindPropertyRelative("HP").floatValue;
            result += stats.FindPropertyRelative("damage").floatValue;
            result += stats.FindPropertyRelative("defense").floatValue;
        }

        EditorGUILayout.Space(); 
        EditorGUILayout.LabelField("Total Power", EditorStyles.boldLabel);
        EditorGUILayout.FloatField(result);

 
        serializedObject.ApplyModifiedProperties();
    }
}

注意:如果您要公开这些 SerializedObjects 的字段并且还想更改它们,您还需要相应地调用

sObj.Update();

...

sObj.ApplyModifiedProperties();

在智能手机上打字,但我希望这个想法很清楚


推荐阅读