for my unity project I'm trying to make a custom property drawer in order to make inspector accept objects that are only implementing the interface I pass via attribute parameter. I am glad that I achived the task satiably for MonoBehaviour objects. However I'm having trouble in applying a similar approach for scriptable objects. There I need help.
Here is my property drawer code. The Problem is C# doesnt let me do a type-check with "is" keyword. Here are few codes I tried
if(temp_SO is requiredAttribute.requiredType) {}
if(temp_SO is T) {}
if(temp_SO.GetType().Equals(requiredAttribute.requiredType) {}
but all fails... However as seen in the code below, if I hardcode it like if(temp_SO is interface_C)
then it works. I couldn't find a way to pass the type value dynamically. Because IDE keeps throwing "a constant value is expected" error. Any help will be appreciated. Thanks..
[CustomPropertyDrawer(typeof(SOInterfaceExposeAttribute))]
public class SOInterfaceExposeAttributeDrawer : PropertyDrawer
{
Type T;
public override void OnGUI ( Rect position , SerializedProperty property , GUIContent label )
{
if ( property . propertyType == SerializedPropertyType . ObjectReference )
{
var requiredAttribute = this . attribute as SOInterfaceExposeAttribute;
T = requiredAttribute . requiredType;
var lastValidRef = property . objectReferenceValue;
EditorGUI . BeginProperty(position , label , property);
ScriptableObject temp_SO = EditorGUI . ObjectField(position , label , property . objectReferenceValue , typeof(ScriptableObject) , true) as ScriptableObject;
// Finish drawing property field.
if ( temp_SO != null )
{
if ( temp_SO is Interface_C)
{
Debug . Log("interface component found");
property . objectReferenceValue = temp_SO as ScriptableObject;
}
else
{
Debug . Log("interface component NOT found");
property . objectReferenceValue = lastValidRef;
}
}
EditorGUI . EndProperty();
}
else
{
// If field is not reference, show error message.
// Save previous color and change GUI to red.
var previousColor = GUI . color;
GUI . color = Color . red;
// Display label with error message.
EditorGUI . LabelField(position , label , new GUIContent("Property is not a reference type"));
// Revert color change.
GUI . color = previousColor;
}
}
}
is
indeed requires a constant type parameter.
The other way you tried
if(temp_SO.GetType().Equals(requiredAttribute.requiredType)
would not work since these two types are definitely not equal since the one implements the other;)
You could probably use IsInstanceOfType
var temp_SO = EditorGUI.ObjectField(position, label, property.objectReferenceValue, typeof(ScriptableObject), true);
// Finish drawing property field.
if (temp_SO != null)
{
if (requiredAttribute.requiredType.IsInstanceOfType(temp_SO))
{
Debug.Log("interface component found");
property.objectReferenceValue = temp_SO;
}
else
{
Debug.Log("interface component NOT found");
property.objectReferenceValue = lastValidRef;
}
}
or IsAssignableFrom
like
var temp_SO = EditorGUI.ObjectField(position, label, property.objectReferenceValue, typeof(ScriptableObject), true);
// Finish drawing property field.
if (temp_SO != null)
{
if (requiredAttribute.requiredType.IsAssignableFrom(temp_SO.GetType()))
{
Debug.Log("interface component found");
property.objectReferenceValue = temp_SO;
}
else
{
Debug.Log("interface component NOT found");
property.objectReferenceValue = lastValidRef;
}
}
Another way could be using FindInterfaces
in order to compare if any inherited type implements the interface type
var temp_SO = EditorGUI.ObjectField(position, label, property.objectReferenceValue, typeof(ScriptableObject), true);
// Finish drawing property field.
if (temp_SO != null)
{
// Filter taken from the linked examples
if (temp_SO.GetType().FindInterfaces(new TypeFilter((type, criteria) => type.ToString() == criteria.ToString()), requiredAttribute.requiredType.Name()).Length > 0)
{
Debug.Log("interface component found");
property.objectReferenceValue = temp_SO;
}
else
{
Debug.Log("interface component NOT found");
property.objectReferenceValue = lastValidRef;
}
}
Btw you could make this more efficient by not constantly checking this but rather only when the reference was changed wrapping it within
EditorGUI.BeginChangeCheck();
var temp_SO = EditorGUI.ObjectField(position, label, property.objectReferenceValue, typeof(ScriptableObject), true);
if(EditorGUI.EndChangeCheck())
{
...
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.