Reputation: 2771
I have found an interesting "issue" in UnityEditor regarding Scriptable objects. Below is simple example:
I have scriptable class ScriptableExpressionBulder that holds some list and a float field. Then I have another class ScriptableExpressionCreator that holds a LIST of scriptable objects mentioned previously. The code looks like this:
public class ScriptableExpressionBuilder : ScriptableObject
{
public List<MultipleExpressionBuilder> multipleExpressionBuilder;
public float delay;
}
public class ScriptableExpressionCreator : ScriptableObject {
public List<ScriptableExpressionBuilder> List;
}
When creating ScriptableExpressionBuilder the fields from (MultipleExpressionBuilder) comes up nicely but it also adds a second field "delay" at the end (which is perfect to this point).
Now for the interesting part:
The second class ScriptableExpressionCreator holds a list of previous scriptables but it doesn't serialize the "delay" field in this current scriptable. The only field that is serialized is a Scriptable class.
Is there a way to serialize the field from ScriptableExpressionBuilder in another Scriptable that holds a list of these scriptables so I can basically set the delay from where this expressions are called. I could however populate the field in the inspector of original scriptable, but the wouldnt be reusable since each delay is different.
Upvotes: 0
Views: 708
Reputation: 90580
You had the question deleted but I voted to reopen it since I already had started to write the solution and finished just when you deleted it and I think this now does what you want and gives you a good start point for further extending it where needed ;)
That's not really an issue, however, not possible built-in.
For ScriptableObject
(and anything else that inherits from UnityEngine.Object
) the Inspector by default draws an object field. If you want to draw something else you would need a custom editor script. There is not really away around customizing the Inspector in order to expose fiels of other UnityEngine.Object
references in the Inspector of another one.
It could look somewhat like e.g. (for now assuming you only want the delay
field to be exposed additionally)
#if UNITY_EDITOR
using System;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
[CustomEditor(typeof(ScriptableExpressionCreator))]
public class ScriptableExpressionCreatorEditor : Editor
{
private SerializedProperty _list;
// I know ... but that's your fault for naming th field List :P
private ReorderableList _listList;
// For Edito this is called when the object gains focus and the Inspector is loaded for this scriptableobject instance
private void OnEnable()
{
// Find and link the serialized field called "List"
_list = serializedObject.FindProperty(nameof(ScriptableExpressionCreator.List));
// Initialize and configure the ReorderableList to draw the referenced elements in the way we want
_listList = new ReorderableList(serializedObject, _list, true, true, true, true)
{
// How is te list header drawn?
drawHeaderCallback = rect => EditorGUI.LabelField(rect, _list.displayName),
// how should each element be drawn?
drawElementCallback = (rect, index, active, focused) =>
{
// get the current element
var element = _list.GetArrayElementAtIndex(index);
// draw the default object reference field with the height of a single line without the label
EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), element, GUIContent.none);
// if no object is referenced do nothing more
if (!element.objectReferenceValue) return;
// move one line lower
rect.y += EditorGUIUtility.singleLineHeight;
// get a serializedObject of the reference
var elementsSerializedObject = new SerializedObject(element.objectReferenceValue);
// same as in our own OnInspectorGUI method below loads the current values
elementsSerializedObject.Update();
// for now assuming you only want the delay field
var delay = elementsSerializedObject.FindProperty(nameof(ScriptableExpressionBuilder.delay));
// draw the delay field
EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), delay);
// same as in our own OnInspectorGUI method below writes back changed values and handles undo/redo marking dirty etc
elementsSerializedObject.ApplyModifiedProperties();
},
// how do we get the height of one element?
elementHeightCallback = index =>
{
// get the current element
var element = _list.GetArrayElementAtIndex(index);
// if nothing is referenced we only need a single line
if (!element.objectReferenceValue)
{
return EditorGUIUtility.singleLineHeight;
}
// otherwise we need two lines, one for the object field and one for the delay field
return EditorGUIUtility.singleLineHeight * 2;
}
};
}
public override void OnInspectorGUI()
{
// draw the script field
DrawScriptField();
// loads current values into the serialized version
serializedObject.Update();
// draw the list according to the settings above
_listList.DoLayoutList();
// writes bac any changed values into the actual instance and handles undo/redo marking dirty etc
serializedObject.ApplyModifiedProperties();
}
// Draws the default script field on the top the Inspector
private void DrawScriptField()
{
// The script field is disabled since nobody is supposed to evr change it
EditorGUI.BeginDisabledGroup(true);
EditorGUILayout.ObjectField("Script", MonoScript.FromScriptableObject((ScriptableExpressionCreator)target), typeof(ScriptableExpressionCreator), false);
EditorGUI.EndDisabledGroup();
// leave a little space between the script field and the actual inspector conten
EditorGUILayout.Space();
}
}
#endif
For now this would look like this
Upvotes: 1