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