Reputation: 115
While trying to make a script for building assets, I ran into an issue with unity's serialization. I have a class in which I store some arbitrary information, which is then stored in an array in a MonoBehaviour on a prefab. I cannot for the life of me get the array to save however, as when I make the object into a prefab it loses the list's values. I have tried using [System.Serializable] and ScriptableObject, but both seem to pose their own new issues.
For instance, using ScriptableObject would mean having to save the data objects as assets, which would become way too much since these objects can get to hundreds in number.
Am I making a mistake in my understanding of unity's serialization? Is there a way to get this working without the ScriptableObject approach of saving every ArbitraryInfo object in an asset?
Data object:
[System.Serializable]
public class ArbitraryInfo{
public int intValue;
public Vector3 vectorValue;
}
OR
public class ArbitraryInfo : ScriptableObject {
public int intValue;
public Vector3 vectorValue;
void OnEnable() {
hideflags = HideFlags.HideAndDontSave;
}
}
Behaviour:
public class MyBuilder : MonoBehaviour {
public ArbitraryInfo[] infoArray;
}
Editor:
[CustomEditor(typeof(MyBuilder))]
public class MyBuilderEditor : Editor {
private SerializedProperty infoArrayProperty;
void OnLoad() {
infoArrayProperty = serializedObject.FindProperty("infoArray");
}
void OnInspectorGUI() {
serializedObject.Update();
for (var i = 0; i < infoArrayProperty.arraySize; i++) {
if (i > 0) EditorGUILayout.Space();
var info = infoArrayProperty.GetArrayElementAtIndex(i).objectReferenceValue as ArbitraryInfo;
EditorGUILayout.LabelField("Info " + i, EditorStyles.boldLabel);
info.intValue = EditorGUILayout.IntField(info.intValue);
info.vectorValue = EditorGUILayout.Vector3Field(info.vectorValue);
}
serializedObject.ApplyModifiedProperties();
}
}
I changed my code to incorporate the changes. Now there are errors for ArbitraryInfo not being a supported pptr value.
Secondly, ArbitraryInfo no longer being a ScriptableObject poses the question of how to initialize it. An empty object can be added to infoArrayProperty
through infoArrayProperty.arraySize++
, but this new empty object seems to be null in my case. This might be due to the pptr issue mentioned above.
The issue I was having was caused by another piece of code where I tried to check if infoArrayProperty.objectReferenceValue == null
. I changed this to another check that did the same thing and everything worked!
Upvotes: 1
Views: 8941
Reputation: 90862
No, no ScriptableObject needed.
But note that GetArrayElementAtIndex(i)
returns a SerializedProperty
. You can not simply parse it to your target class.
so instead of
var info = infoArrayProperty.GetArrayElementAtIndex(i).objectReferenceValue as ArbitraryInfo;
and
info.intValue = EditorGUILayout.IntField(info.intValue);
info.vectorValue = EditorGUILayout.Vector3Field(info.vectorValue);
you have to get the info
's SerializedProperty
s by using FindPropertyRelative
:
var info = infoArrayProperty.GetArrayElementAtIndex(i);
var intValue = info.FindPropertyRelative("intValue");
var vectorValue = info.FindPropertyRelative("vectorValue");
than you can/should use PropertyField
s
EditorGUILayout.PropertyField(intValue);
EditorGUILayout.PropertyField(vectorValue);
allways try to avoid using direct setters and use those SerializedProperties instead! This provides you with Undo/Redo functionality and marking the changed Behaviour/Scene as unsaved automatically. Otherwise you would have to tak care of that manually (... don't ^^).
Upvotes: 2