- Home /
How should I declare a nested class to find it latter with SerializedObject.FindProperty?
Hello. I'm trying to imitate what was explained on the Unite 11 Intro to Editor Scripting on a ScriptableObject class. The class contain an array of another "class of the class".
Example :
public class A : ScriptableObject
{
[System.Serializable]
public class B
{
public B()
{
}
Rect rectangle;
Vector2 position;
}
public A()
{
myArray = new B[1];
myArray[0] = new B();
}
private B[] myArray;
}
With this class, the serialization works like a charm.
Now, I have an EditorWindow wich I use to populate my A's with some B's. For that, following the Unite 11 video, I use a SerializedObject and access its properties with SerializedObject.FindProperty(), like that :
public class AEditor : EditorWindow
{
private SerializedObject myObject;
public void SetA(A a)
{
myObject = new SerializedObject(a);
}
public void OnGUI()
{
if(myObject == null)
return;
myObject.Update();
A.B[] bs = GetBs();
// Do stuff
myObject.ApplyModifiedProperties();
}
private A.B[] GetBs()
{
int arraySize = myObject.FindProperty("myArray.Array.size").intValue;
A.B[] bs = new A.B[arraySize];
for(int i = 0; i < arraySize; i++)
{
Object o = myObject.FindProperty(string.Format ("myArray.Array.data[{0}]", i)).objectReferenceValue;
if(o == null)
{
Debug.LogError ("Object not found in array.");
continue;
}
A.B b = o as A.B;
if(b == null)
{
Debug.LogError("B object not loaded");
continue;
}
bs[i] = b;
}
return bs;
}
}
With this, The script won't compile because of line 23 "A.B b = o as A.B;", I have this :
error CS0039: Cannot convert type 'UnityEngine.Object' to 'A.B' via a built-in conversion
So, I made B inherit from System.Object :
public class A : SerializedObject
{
public class B : UnityEngine.Object
{
...
}
...
}
Here, FindProperty find my Bs as UnityEngine.Object, but when I try to cast them, I got a null.
B object not loaded
Here is my question : how should I declare my class B so it can be found by FindProperty() AND be castable afterward?
what variable is "frames". Why is it not "myArray". I don't see a variable named frames here.
Fixed. The example code is based on my project's code, $$anonymous$$imalized to have only what matter for the question. I forgot to change the name of the array in this string.
I couldn't answer that, because I was faced with another problem.
When I inheritate B from Object, I try to instanciate B like this :
public class B : Object
{
public B()
{
myArray = new B[1];
myArray[0] = new B();
}
}
But it seems B is not saved within A, all I have in myArray is null... Thus I now have :
Object not found in array.
So it seems inheriting B from Object is not a solution anymore.
Now, why I had my B's in the array when I asked the question, I don't know...
One solution would be to access each property of B individialy, ins$$anonymous$$d of the B itself. Like this :
Rect rect = myObject.FindProperty(string.Format ("myArray.Array.data[{0}].rectangle", i)).rectValue;
Vector2 vect = myObject.FindProperty(string.Format("myArray.Array.data[{0}].position", i)).vector2Value;
But I'm willing to have an answer to the main question anyway, in the case my B would contains faaaaaaar more properties.
Answer by Jamora · Jul 20, 2013 at 12:10 PM
This is what works for me:
using UnityEngine;
using UnityEditor;
using System.Collections;
public class AEditor : EditorWindow {
[SerializeField]
private A myObject;
#region methods for testing
[MenuItem("Temp/Temp")]
public static void Init() {
GetWindow<AEditor>();
}
void OnGUI() {
A.B[] temp = GetBs();
foreach (A.B b in temp){
if(b != null)
b.i = EditorGUILayout.IntField(b.i);
}
}
#endregion
void OnEnable(){
if (myObject == null){
Debug.Log("instantiating serializedobject");
myObject = ScriptableObject.CreateInstance<A>();
}
}
private A.B[] GetBs() {
int arraySize = myObject.myArray.Length;
A.B[] bs = new A.B[arraySize];
for (int i = 0; i < arraySize; i++) {
A.B b = myObject.myArray[0];
if(b == null) {
Debug.LogError("B object not loaded");
continue;
}
bs[i] = b;
}
return bs;
}
}
using UnityEngine;
using System.Collections;
[System.Serializable]
public class A : ScriptableObject {
[SerializeField]
public B[] myArray;
void OnEnable() {
hideFlags = HideFlags.HideAndDontSave;
if(myArray == null) {
Debug.Log("a constructor");
myArray = new B[1];
myArray[0] = new B();
}
}
#region Nested Class : B
[System.Serializable]
public class B {
public B()
{
Debug.Log("inside B constructor");
}
[SerializeField]
public int i;
Rect rectangle;
Vector2 position;
}
#endregion
}
I made your private variables public because I couldn't bother with the getters. Of course you won't be that lazy...
Of course, this code works fine, but in my case, I'm trying to use the SerializableObject (different from ScriptableObject alone) to indirectly edit my A object. All the question here is about accessing the nested B through SerializedObject.FindProperty.
But thanks to you, I remembered that a "class of a class" is better called "nested class". :p
Seemed to me like you wanted serialization to work, well when working with SerializedObjects, you have to use their Update and Apply$$anonymous$$odifiedProperties when you want to work directly with properties. GetBs() would be a good place to at least update the SerializedObject.
Seems to me that working with serializedProperties is making a simple thing hard... Good for practice I guess.
I didn't made the OnGUI appear in my example, but of course I use the Update and Apply$$anonymous$$odifiedProperties on the SerializedObject.
Well, sure it makes things a bit harder, but the features of SerializedObject are quite interresting for a sturdy tool.
(I added OnGUI in the example just to be sure.)
Your answer
Follow this Question
Related Questions
Getting any type in Unity Inspector 1 Answer
Renaming Serialized Classes 1 Answer
Serialization of Singleton vs Static class in Editor 1 Answer
How to get a List of all Variables in a Class 1 Answer
Null Reference When Setting a Class? 1 Answer