我在UnityEditor中发现了一个关于可脚本化对象的有趣“问题”。下面是一个简单的例子:
我有一个可脚本化的类ScriptableExpressionBulder,它包含一些列表和一个浮点型字段。然后我有另一个类ScriptableExpressionCreator,它保存了前面提到的可脚本化对象的列表。代码如下所示:
public class ScriptableExpressionBuilder : ScriptableObject
{
public List<MultipleExpressionBuilder> multipleExpressionBuilder;
public float delay;
}
public class ScriptableExpressionCreator : ScriptableObject {
public List<ScriptableExpressionBuilder> List;
}在创建延迟时,(MultipleExpressionBuilder)中的字段出现得很好,但它还在末尾添加了第二个字段“ScriptableExpressionBuilder”(这在这一点上是完美的)。
现在是有趣的部分:
第二个类ScriptableExpressionCreator保存以前的脚本列表,但它不序列化当前脚本中的"delay“字段。唯一序列化的字段是一个可编写脚本的类。
有没有办法将ScriptableExpressionBuilder中的字段序列化到另一个包含这些脚本的列表的脚本表中,这样我基本上就可以设置调用这些表达式的延迟。然而,我可以在原始脚本的检查器中填充字段,但由于每个延迟是不同的,因此不能重复使用。
发布于 2021-10-19 07:21:03
您删除了问题,但我投票重新打开它,因为我已经开始编写解决方案,并在您删除它时完成,我认为这现在做了您想要的事情,并为您在需要的地方进一步扩展它提供了一个很好的起点;)
然而,这不是一个真正的问题,不可能是内置的。
对于ScriptableObject (以及从UnityEngine.Object继承的任何其他内容),检查器默认绘制一个对象字段。如果你想画其他东西,你需要一个custom editor script。为了在另一个检查器的检查器中公开其他UnityEngine.Object引用的字段,实际上并不需要自定义检查器。
它可能看起来有点像(例如,现在假设您只想另外公开delay字段)
#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现在,它看起来像这样

https://stackoverflow.com/questions/69616963
复制相似问题