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

Time:11-15

I'm trying make a custom editor and I can't get a value from a scriptable object in an array. Here is the FightData script that contains CharacterData scriptable objects.

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

CharacterData contains stats.

public class CharacterData : ScriptableObject {

    public CharacterStats stats;
}

Here is the 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;
    }
}

I want to sum up all the stats and display them in the custom editor for FightData. But stats is always null. Here is my approach:

[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();
    }
}

CodePudding user response:

FindPropertyRelative would work only if it is actuallly a nested "normal" serialized class which is serialized into YAML values.

But for ScriptableObject (in general anything inheriting from UnityEngine.Object) what you store is not serialized values but rather only the UnityEngine.Object reference!

You rather need to get the according SerializedObject instances like e.g.

[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();
    }
}

Note: If you are going to expose fields of these SerializedObjects and also want to change them you would additionally also call accordingly

sObj.Update();

...

sObj.ApplyModifiedProperties();

Typed on smartphone but I hope the idea gets clear

  • Related