I have a serializable class called Event Option with a custom Property Drawer. It appears correctly in the inspector for fields on objects of type EventOption. But if I wanted to have a field which is an array of EventOptions I find that editing one in the array, edits all of them.
So I have the following serializable class.
[Serializable]
public class EventOption
{
[SerializeField]
private string text;
[SerializeField]
[Min(0)]
private int value;
[SerializeField]
private bool hasTask;
[SerializeField]
private GameTask task;
internal string Text => text;
internal int PopHappiness => value;
internal bool HasTask => hasTask;
internal GameTask Task => task;
}
With the following Custom Property Drawer.
[CustomPropertyDrawer(typeof(EventOption))]
public class EventOptionDrawer : PropertyDrawer
{
private Rect _lastRect;
private float _totalHeight;
private float _labelHeight;
private SerializedProperty _text;
private float _textHeight;
private SerializedProperty _value;
private float _valueHeight;
private SerializedProperty _hasTask;
private float _hasTaskHeight;
private SerializedProperty _task;
private float _taskHeight;
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
_totalHeight = 0;
_labelHeight = EditorGUIUtility.singleLineHeight;
_totalHeight += _labelHeight;
_text = property.FindPropertyRelative("text");
_textHeight = EditorGUI.GetPropertyHeight(_text);
_totalHeight += _textHeight;
_value = property.FindPropertyRelative("value");
_valueHeight = EditorGUI.GetPropertyHeight(_value);
_totalHeight += _valueHeight;
_hasTask = property.FindPropertyRelative("hasTask");
_hasTaskHeight = EditorGUI.GetPropertyHeight(_hasTask);
_totalHeight += _hasTaskHeight;
_task = property.FindPropertyRelative("task");
if (_hasTask.boolValue)
{
_taskHeight = EditorGUI.GetPropertyHeight(_task, true);
_totalHeight += _taskHeight;
}
return _totalHeight;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
Rect labelRect = FirstRect(position, _labelHeight);
EditorGUI.PrefixLabel(labelRect, label);
EditorGUI.indentLevel++;
GenerateProperty(_text, _textHeight);
GenerateProperty(_value, _valueHeight);
GenerateProperty(_hasTask, _hasTaskHeight);
if (_hasTask.boolValue)
{
EditorGUI.indentLevel++;
GenerateProperty(_task, _taskHeight);
EditorGUI.indentLevel--;
}
EditorGUI.indentLevel--;
EditorGUI.EndProperty();
}
private void GenerateProperty(SerializedProperty property, float propertyHeight)
{
Rect rect = NextRect(propertyHeight);
EditorGUI.PropertyField(rect, property, true);
}
private Rect FirstRect(Rect position, float propertHeight)
{
_lastRect = new(position.x, position.y, position.width, propertHeight); ;
return _lastRect;
}
private Rect NextRect(float propertyHeight)
{
_lastRect = new(_lastRect.x, _lastRect.y+_lastRect.height, _lastRect.width, propertyHeight);
return _lastRect;
}
}
Which is used in the following scriptable object.
public class GameEvent : ScriptableObject
{
[SerializeField]
private string id;
[SerializeField]
private string title;
[SerializeField]
private Sprite image;
[SerializeField]
[TextArea(3, 8)]
private string description;
[SerializeField]
private EventOption testOption;
[SerializeField]
private EventOption[] eventOptions;
Now testOption appears correctly. But editing any of the eventOptions in the array will edit all of them.
