我正在为一个定制属性创建一个定制抽屉,这个定制属性可以帮助我初始化一个标记为SerializeReference
属性的字段的值。
基本上,定制抽屉将显示一个下拉菜单,允许我选择要创建的Type
并将其分配给字段。
到目前为止,我已经编写了以下代码来测试不同的场景:
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var targetObject = property.serializedObject.targetObject;
var field = targetObject.GetType().GetField(property.name, FieldBindingFlags)!;
if (field.GetValue(targetObject) == null)
field.SetValue(targetObject, new OperaSinger());
else
{
EditorGUI.BeginProperty(position, label, property);
EditorGUI.PropertyField(position, property, label, true);
EditorGUI.EndProperty();
}
}
这些是测试类:
interface ISinger
{
void Sing();
}
[System.Serializable]
class OperaSinger : ISinger
{
[SerializeField] private string name;
void Sing(){}
}
class StreetPerformer : MonoBehaviour, ISinger
{
[SerializeField] private string streetName;
void Sing(){}
}
上面的代码看起来工作正常,它将属性初始化为OperaSinger
的一个新示例,并显示编辑器。
但是,当我尝试对MonoBehaviour
实现执行相同的操作时,我得到了一个错误:
尝试#1:
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var targetObject = property.serializedObject.targetObject;
var field = targetObject.GetType().GetField(property.name, FieldBindingFlags)!;
if (field.GetValue(targetObject) == null)
{
var x = ((Component)targetObject).gameObject.AddComponent<StreetPerformer>();
field.SetValue(targetObject, x);
}
else
{
EditorGUI.BeginProperty(position, label, property);
EditorGUI.PropertyField(position, property, label, true);
EditorGUI.EndProperty();
}
}
错误:[SerializeReference] cannot serialize objects that derive from Unity.Object
。
尝试#2:
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var targetObject = property.serializedObject.targetObject;
var field = targetObject.GetType().GetField(property.name, FieldBindingFlags)!;
if (field.GetValue(targetObject) == null)
{
var x = ((Component)targetObject).gameObject.AddComponent<StreetPerformer>();
property.objectReferenceValue = x;
}
else
{
EditorGUI.BeginProperty(position, label, property);
EditorGUI.PropertyField(position, property, label, true);
EditorGUI.EndProperty();
}
}
错误:type is not a supported pptr value
尝试#3:
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var targetObject = property.serializedObject.targetObject;
var field = targetObject.GetType().GetField(property.name, FieldBindingFlags)!;
if (field.GetValue(targetObject) == null)
{
var x = ((Component)targetObject).gameObject.AddComponent<StreetPerformer>();
property.objectReferenceInstanceIDValue = x.GetInstanceID();
}
else
{
EditorGUI.BeginProperty(position, label, property);
EditorGUI.PropertyField(position, property, label, true);
EditorGUI.EndProperty();
}
}
错误:type is not a supported pptr value
我做错了什么,我该怎么补救?
据我所知,第2次和第3次尝试的错误是因为该字段被定义为接口类型ISinger
。
1条答案
按热度按时间wgx48brx1#
好吧,在尝试了以下方法之后:
得到了与尝试1相同的错误,我意识到这是不可能的。
因此,我提出的解决方案是为
StreetPerformer
类创建一个wrapper-class,它将把所有方法委托给StreetPerformer
类,如下所示:显然,对我需要的每个类都这样做是很乏味的,所以我只是编写了一个代码生成器来为我创建(和更新)这个类。
因此,现在我可以在脚本中创建一个接口字段,它引用一个常规类、ScriptableObject或MonoBehaviour,而这一切都是最简单的😁