- Home /
Find out what fields the object have and let user edit them in custom editor window (Reflections)
Hey guys,
So let's say I have a few ScriptableObject items in my database and each have different set of fields like: int damage, float coolDown, SpriteRenderer sprite, etc. For example:
public class Item1: ScriptableObject
{
public int damage;
public float speed;
}
public class Item2: ScriptableObject
{
public bool isFunny;
public SpriteRenderer sprite;
public int damage;
}
When I press a button I want to show fields of selected object in a custom inspector that user can edit. I only know how to display what fields the object have:
var fields = items[i].GetType().GetFields();
for (int j=0; j<fields.Length; j++)
{
GUILayout.Label(fields[j].ToString());
}
This is the first time I use Reflections, I have no idea how to treat them. I did research yesterday but I am still having trouble.
Any suggestions?
Take a look at the FieldInfo entry on $$anonymous$$SDN, is what I would recommend.
Hey, thanks for your comment. I looked at this before and I somewhat understand how it works. But the problem I am having is - how can I create a field in my custom window in order to edit values?
Answer by Bunny83 · Oct 02, 2016 at 10:38 AM
You shouldn't use reflection here since you have to take care of which variables actually can be serialized and which can't. Not all fields are serialized / serializable.
Just to answer your question:
To get the value of a field you have to call "GetValue" and pass the containing object as parameter.
object val = fields[j].GetValue(items[i]);
This will read the value of the field into an object variable. Of course if you want to display a GUI control to edit the value you would need to analyse the type (int, float, string, ....) and cast the value to the actual type and display an appropriate GUI control.
Finally to write it back you have to use SetValue the same way:
fields[j].SetValue(items[i], val);
Also don't forget to use Undo.RecordObject before you apply any changes, otherwise the changes won't be persistent.
What's way easier is to use the SerializedObject class. This can handle all that for you. The steps are:
You create a SerializedObject for each of the items you want to edit and store them in an array / list once.
at the beginning of each item you would call the Update method of the SerializedObject instance. This will update all the serialized values inside that SerializedObject.
Now you simply iterate through all SerializedProperties using GetIterator which returns the first SerializedProperty and in turn using Next each iteration.
Now you can simply use EditorGUILayout.PropertyField with the current SerializedProperty to show the appropriate control for this field.
Important: When you're done with an Item you have to call ApplyModifiedProperties on the SerializedObject instance to actually write the serialized data and to automatically create an Undo step.
The second way is the way how the normal Inspector works (in case no custom editor has been defined for this class).
If you really want to use relfection, have a look at this list. It's a list of all the 18 different types Unity can serialize. But that's not the end. You have to check private variables as well and see if they have a SerializeField attribute attached and if so, display them as well. Further more custom Serializable class references are not serialized seperately but simply within the containing object. So you would need to do all that recursively for nested objects.
At all of these steps you have to be very careful how you treat the values (so you don't get casting exceptions) and to not run into an infinite recursion.
The SerializedObject class takes away a lot of this trouble, though sometimes it's limitations can be a bit annoying.
Thanks a lot for your broad answer. This looks like a perfect solution for my problem, I will start working on it right now. ;)