如何解决Unity3D 编辑器:在侧边栏中渲染嵌套元素 我有什么我想要什么
在 Unity 中,我的一个 MonoBehavIoUrs 有一个指向另一个对象(ScriptableObject)的字段。如果我双击该字段,我可以看到该对象的字段。如何将这些字段渲染到顶层 MonoBehavIoUr 的属性抽屉中?
图片形式
我有什么
(双击元素)
我想要什么
我有自己的 [CustomEditor]
组件,但我无法让它正常工作;像这样的东西:
SerializedProperty activityStack = serializedobject.FindProperty("activityStack");
EditorGUILayout.PropertyField(activityStack.GetArrayElementAtIndex(0));
只呈现“元素 0(空闲活动)”位,而不是引用的实际内容。
解决方法
因为 PropertyField
的默认 ScriptableObject
正是您获得的:UnityEngine.Object
引用字段,例如游戏对象和组件以及其他资产;)
当然,您可以实现您想要实现的目标,但这有点复杂,并且对于维护来说不是很好,我不推荐它。
我不知道您的 ScriptableObject
所以这里举个例子
public class ExampleSO : ScriptableObject
{
public int SomeInt;
[SerializeField] private string _someString;
}
和你的MonoBehaviour
例如
public class Example : MonoBehaviour
{
public List<ExampleSO> _SOList;
}
然后编辑器可能看起来像例如
using UnityEditor;
using UnityEngine;
// This is the namespace for the ReorderableList
using UnityEditorInternal;
[CustomEditor(typeof(Example))]
public class ExampleEditor : Editor
{
SerializedProperty _SOList;
Example _example;
MonoScript _script;
ReorderableList _list;
private void OnEnable()
{
// Link up the serializedProperty
_SOList = serializedObject.FindProperty("_SOList");
// get the casted target instance (only needed for drawing the script field)
_example = (Example) target;
// get the according script instance (only needed for drawing the script field)
_script = MonoScript.FromMonoBehaviour(_example);
// Set up the ReorderableList
_list = new ReorderableList(serializedObject,_SOList,true,true)
{
// What shall be displayed as header for the list?
drawHeaderCallback = (Rect rect) => EditorGUI.LabelField(rect,_SOList.displayName),// How is each element displayed?
drawElementCallback = (Rect rect,int index,bool isActive,bool isFocused) =>
{
// Get the element in the list (SerializedProperty)
var element = _SOList.GetArrayElementAtIndex(index);
// and draw the default object reference field
EditorGUI.PropertyField(new Rect(rect.x,rect.y,rect.width,EditorGUIUtility.singleLineHeight),element,new GUIContent("Reference"));
// Check if an asset is referenced - if not we are done here
if (!element.objectReferenceValue) return;
// Otherwise get the SerializedObject for this asset
var elementSerializedObject = new SerializedObject(element.objectReferenceValue);
// and all the properties (SerializedProperty) of it you want to display
var someInt = elementSerializedObject.FindProperty("SomeInt");
var someString = elementSerializedObject.FindProperty("_someString");
// Similar to the OnInspectorGUI first load the current values into this serializedobject
elementSerializedObject.Update();
{
// Adding some indentation just to show that the following fields are actually belonging to the referenced asset
EditorGUI.indentLevel++;
{
rect = EditorGUI.IndentedRect(rect);
// shift down the rect by one line
rect.y += EditorGUIUtility.singleLineHeight;
// Draw the field for the Int
EditorGUI.PropertyField(new Rect(rect.x,someInt);
// Shift down the rect another line
rect.y += EditorGUIUtility.singleLineHeight;
// Draw the string field
EditorGUI.PropertyField(new Rect(rect.x,someString);
}
EditorGUI.indentLevel--;
}
// Write back the changed values and trigger the checks for logging dirty states and Undo/Redo
elementSerializedObject.ApplyModifiedProperties();
},// How much vertical space should be reserved for each element?
elementHeightCallback = (int index) =>
{
// Get the elements serialized property
var element = _SOList.GetArrayElementAtIndex(index);
// by default we have only the asset reference -> single line
var lines = 1;
// if the asset is referenced adds space for the additional fields
if (element.objectReferenceValue) lines += 2; // or how many lines you'll need
return lines * EditorGUIUtility.singleLineHeight;
}
};
}
public override void OnInspectorGUI()
{
// draw th script field
DrawScriptField();
// Load the current values into the serializedObject
serializedObject.Update();
{
// let the ReorderableList do its magic
_list.DoLayoutList();
}
// Write back the changed values into the actual instance
serializedObject.ApplyModifiedProperties();
}
// Just draws the usual script field at the top of the Inspector
private void DrawScriptField()
{
EditorGUI.BeginDisabledGroup(true);
{
EditorGUILayout.ObjectField("Script",_script,typeof(Example),false);
}
EditorGUI.EndDisabledGroup();
EditorGUILayout.Space();
}
}
这导致以下检查员。如您所见,我打开了 MonoBehaviour
的 Isnpectors 和 ExampleSO
的两个实例,以显示如何将值转移到实际实例中
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。