[System.Serializable]
public class Animal
{
public int animalValue;
}
// Display class with a list of animals
public class Animals : MonoBehaviour
{
public List<Animal> animals;
}
// CustomPropertyDrawer for Animal class
[CustomPropertyDrawer(typeof(Animal))]
public class AnimalEditor : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
EditorGUI.PropertyField(position, property, false);
position.y += 20;
position.height = 16;
EditorGUI.PropertyField(position, property.FindPropertyRelative("animalValue"));
EditorGUI.EndProperty();
}
}
If the class Animal is not a Monobehaviour (like in this example above), and I just set List of animals to say length of 3 in inspector, I can get āanimalValueā field with FindPropertyRelativeā¦
However, if I were to change Animal to MonoBehaviour, add Animal as component to a empty GameObject, then drag this into Animals class list, FindPropertyRelative doesnāt work like described.
Iām pretty inexperienced with editor scripting, and itās been 1+ year since Iāve last touched editor scripting⦠I did some testing, but couldnāt get any meaningful property path printout with Debug.Log from SerializedProperty property, in PropertyDrawer classā¦
So Iām not quite sure how and where I can get my hands to Animal items in List⦠maybe Iām just looking into wrong direction, maybe I should use fieldInfo or such - which I havenāt used at all.
If you make āAnimalā a MonoBehaviour, then the list is referencing other āAnimalā scripts attached elsewhere.
See⦠the serialization (and therefore editor) of classes in unity do NOT respect reference. UNLESS the reference is to a unity object of some sort (MonoBehaviour, Component, GameObject, etc).
FindProperty and FindPropertyRelative are returning SerializedProperty. BUT because your property is now a unity object (a MonoBehaviour), itās a SerializedProperty that references another object, as opposed to actually being a serialized object. So there is no relative property.
I vaguely suspected something like that, but definitely couldnāt put it to words⦠Now Iād have to just solve how to go about this⦠so:
If I now donāt have SerializedProperty in my use for Animal instances in List of Animals⦠then I gather that I have just instances of Animal class in my use?
So instead of using property.FindPropertyRelative, I now have to get values from these like from any typical class?
This seems to be working. This would place the animalValue fields valueā¦
So this is actually bit less fluent way to get and output values to CustomPropertyDrawer, if I canāt use EditorGUI.PropertyField⦠unless Iām on wrong track.
Generally, you donāt want to draw a different MonoBehaviour as a property - you want to change the values on that other MonoBehaviour on that other MonoBehaviour!
You can, however, draw a different MonoBehaviourās editor in your own editor. So if you have a CustomInspector, you can do:
[CustomEditor(typeof(AnimalList))]
public class AnimalListEditor : Editor {
private AnimalList script;
private Dictionary<Animal, Editor> editors;
private void OnEnable() {
script = (AnimalList) target;
editors = new Dictionary<Animal, Editor>();
}
public override void OnInspectorGUI() {
var before = script.animals.Count;
base.OnInspectorGUI();
var after = script.animals.Count;
if(before != after) {
return; //prevent an exception due to Unity doing this in two passes
}
for (int i = 0; i < script.animals.Count; i++) {
if(script.animals[i] == null) {
EditorGUILayout.LabelField("Null animal");
}
else {
var animal = script.animals[i];
EditorGUILayout.LabelField(animal.name);
EditorGUI.indentLevel++;
FindEditorFor(animal).OnInspectorGUI();
EditorGUI.indentLevel--;
}
}
}
private Editor FindEditorFor(Animal animal) {
Editor animalEditor;
if(!editors.TryGetValue(animal, out animalEditor)) {
animalEditor = CreateEditor(animal);
editors[animal] = animalEditor;
}
return animalEditor;
}
}
This will look like this:
If you write a CustomInspector for Animal, thatāll show up instead, so you can get rid of the Script-field. You could also, of course, just write custom layout code for the animal, but this will allow you to use the same code both for Animalās drawer and for AnimalListās, preventing duplication.
The before != after thing up there is due to custom editors being a bit finnicky. I believe drawing is done in two passes, one to figure out the layout and one that actually creates the interactable elements. If the number of things you draw changes during the second pass, Unity throws exceptions at you. Itās generally annoying but harmless. If you return early, that doesnāt happen.
Thank you @Baste for your code example⦠was away from forums for a day.
What I actually wanted to do is avoid something like that = custom editor.
While learning editor scripting, I was sort of liking the idea of PropertyDrawers, meaning no need for specific editors which are quite a lot of work for beginner level coder - IMHO.
Where there are instances of property, itās rendered like it should, no matter if itās in some custom editor, or ānormalā Array / List. However, this concept doesnāt seem to work like I āwantedā.
So when non MonoBehaviour classes are rendered using CustomPropertyDrawer, it looks like image below, when the third parameter is set to true - it automatically renders fields of class Animal like this:
So I could do some formatting, then print out the fields as they are, if needed.
However with MonoBehaviour classes, the case is different, most likely because of reasons @lordofduct mentioned. The result is this with same lines of code:
And like the image shows, I only get the field for MonoBehaviour that is attached to some empty GameObject that I then dragged to slot/field in list⦠no fields of Animal class like with standard C# classes.
So I actually just thought this would be nice and easy way to combine drag and dropable GameObjects and CustomPropertyDrawersā¦
If anyone else finds this thread and for future self⦠I post this here too.
I found another thread about this question:
In addition to what @lordofduct and @Baste said, this post shows how to create editor for Monobehaviour class instead of creating CustomPropertyDrawer, how to use it was already covered in reply by @Baste .