I have a IsoTile
class and a terrain
property of class TerrainType
. The IsoTile
is designed to be added as a component to a lot of game objects on the scene and be configurable using standard Unity Inspector window.
public class IsoTile : MonoBehaviour {
public TerrainType terrain;
// ...
}
public abstract class TerrainType : ScriptableObject {
}
public class SimpleTerrain : TerrainType {
}
public class ComplexTerrain : TerrainType {
}
public class TransitionTerrain : TerrainType {
}
Here is what I see in editor, but I want to choose between all my terrain types. How could I do that?
If what you need is a drop-down showing SimpleTerrain, ComplexTerrain and TransitionTerrain you will need to write your own property drawer or custom editor.
Here’s a code I wrote some time ago to achieve that:
TypeSelectorAttribute.cs
[AttributeUsage (AttributeTargets.Field)]
public class TypeSelectorAttribute : PropertyAttribute {
public Type type { get; private set; }
public TypeSelectorAttribute (Type type) : this (type, false) {
}
public TypeSelectorAttribute (Type type, bool runtimeReadOnly) {
this.type = type;
}
}
TypeSelectorAttributeDrawer.cs
[CustomPropertyDrawer (typeof (TypeSelectorAttribute))]
public class TypeSelectorDrawer : PropertyDrawer {
static Dictionary<System.Type, List<string>> types = new Dictionary<System.Type, List<string>> ();
void CollectTypes (System.Type type) {
List<string> subtypes = System.AppDomain.CurrentDomain.GetAssemblies ().SelectMany (asm => asm.GetTypes ()).Where (t => t.IsSubclassOf (type) && !t.IsAbstract).Select (t => t.Name).ToList ();
types.Add (type, subtypes);
}
public override float GetPropertyHeight (UnityEditor.SerializedProperty property, GUIContent label) {
return 18f;
}
public override void OnGUI (Rect position, UnityEditor.SerializedProperty property, GUIContent label) {
position.yMin += 2f;
TypeSelectorAttribute attr = attribute as TypeSelectorAttribute;
System.Type type = attr.type;
if (!types.ContainsKey (type))
CollectTypes (type);
int idx = types[type].ToList ().IndexOf (property.stringValue);
if (idx == -1)
idx = 0;
if (types[type].Count > idx) {
EditorGUI.BeginProperty (position, label, property);
EditorGUI.BeginChangeCheck ();
idx = EditorGUI.Popup (position, label.text, idx, types[type].ToArray ());
if (EditorGUI.EndChangeCheck ()) {
property.stringValue = types[type][idx];
}
if (property.stringValue == string.Empty)
property.stringValue = types[type][idx];
EditorGUI.EndProperty ();
} else {
EditorGUI.LabelField (position, label.text, "No " + type.Name + "s found");
}
}
}
Usage:
[TypeSelector (typeof (TerrainType))]
public TerrainType terrain;
(Bear in mind that I copy-pasted code and stripped some useless parts of it, just to demonstrate here real code on how you would achieve that).