Reputation: 45
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();
}
}
Upvotes: 3
Views: 2587
Reputation: 31
To dive into other fields of a class with FindPropertyRelative does not work. Especially Scriptible Objects requires different method. For inner and nested Scriptible Objects want to be converted Serialized Object type. After this process you can access inner Scriptible Objects.
Upvotes: 0
Reputation: 90813
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
Upvotes: 1