如何从统一自定义编辑器中的可编写脚本的对象数组中获取值?

How to get a value from an array of scriptable objects in unity custom editor?

我正在尝试创建一个自定义编辑器,但我无法从数组中的可编写脚本的对象中获取值。 这是包含 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();
    }
}

FindPropertyRelative 仅当它实际上是一个嵌套的“正常”序列化 class 时才有效,它被序列化为 YAML 值。

但是 for ScriptableObject(一般来说任何继承自UnityEngine.Object)你存储的东西没有被序列化values 而只是 UnityEngine.Object reference!

您更需要获取相应的 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();

在智能手机上打字,但我希望思路清晰