Why is there no upfront support for this? It seems like it would be EXTREMELY empowering.
What I want is to select from the inspector which subclass to use on a field which has its baseclass as type, then work with the fields contained within that subclass. This would NOT require an instance of the class to already exist but would perhaps require a process of creating and storing an instance behind the scenes so to speak?
Currently, I can only work with a Class type field by using a Monbehaviour which exists in the scene, which in no way achieves what I want here, or a ScriptableObject instance for which I would need to create a new instance for each assignment for the contained fields to be what I need and that would mean clutterâŚ
So far my research has resulted in people stating that unity simply does not support this kind of behavior, but why not? We have MonoBehaviour, we have ScriptableObject, so why canât we have something like âSelectableTypeâ to derive from which would allow us to utilize State Pattern from the inspector? Seems way too powerful a tool to shrug offâŚ
At any rate, any suggestions on how to achieve this kind of thing? I need to be able to, when assigning to a field of a class type which derives from a âSelectableTypeâ class, have the option to assign any of its subclasses as the type and then assign the fields of the chosen subclass.
What you are looking for is SerializeReference. Unfortunately you will need to at least write a custom inspector for choosing the class or copy any of the ones floating around the forum.
If youâve never written one your best bet is to look through the asset store/online for free options. Otherwise paid options like Odin Inspector exist that support SerializeReference out of the box.
If youâve never written a custom inspector you have a looot of learning to do (perhaps years) for something like a subclass selector which is straight in advanced territory.
Iâd use an existing solution, or, take a look at how they do things code wise.
Start with Unityâs manual for how to make a custom Inspector in general.
Once youâve got one, look up C# how-tos for getting a list of sub-classes of a target in the current domain, and then for creating an instance.
Youâll also need to make sure itâs serializable by Unity, also covered in the manual.
Itâs a bit complex, but take it one step at a time and youâll get there. Of course, if anything Iâve daid doesnât make sense yet then there are some extra steps.
wow yâall are awesome! thanks to the direction given so far, i have almost what i need. followed the medium guide, made a few adjustments, applied TypeCache code to make it cleaner, and it works pretty well. this is what i have so far:
public class TestBehaviour : MonoBehaviour
{
[SerializeReference] public SelectableType selectableType;
}
public class SelectableType
{
[SerializeField] private bool testing;
public int TestInt
{
get; set;
}
}
[CustomEditor(typeof(TestBehaviour))]
public class SelectableTypeEditor : Editor
{
private Type[] selectableTypes;
private int selectableTypeIndex;
private bool lockSelectableType = true;
public override void OnInspectorGUI()
{
TestBehaviour testBehaviour = target as TestBehaviour;
if (testBehaviour == null)
{
return;
}
if (selectableTypes == null)
{
selectableTypes = TypeCache.GetTypesDerivedFrom<SelectableType>().Where(p => typeof(SelectableType).IsAssignableFrom(p) && !p.IsAbstract).ToArray().Where(impl => !impl.IsSubclassOf(typeof(UnityEngine.Object))).ToArray();
}
selectableTypeIndex = EditorGUILayout.Popup(new GUIContent("SelectableType"), selectableTypeIndex, selectableTypes.Select(impl => impl.FullName).ToArray());
if ((lockSelectableType = GUILayout.Toggle(lockSelectableType, "LockSelectableType")) == false
&& GUILayout.Button("Create instance"))
{
testBehaviour.selectableType = (SelectableType)Activator.CreateInstance(selectableTypes[selectableTypeIndex]);
lockSelectableType = true;
}
base.OnInspectorGUI();
}
}
//---
public class TestA : SelectableType
{
[SerializeField] private int testInt;
[SerializeField] private bool tester;
}
public class TestB : TestA
{
[SerializeField] private int testInt2;
}
Now where i need to go from here:
I need, hopefully there is a way, to get around the requirement of writing this custom editor typeOf attribute to refer to each class i want to implement its functionality. Iâm hoping thereâs a way to apply the functionality directly to the SelectableType class i created, so that whenever i have a field of type SelectableType or any of its subclasses, the editor automatically apply the [SerializedReference] attribute to that field and will apply the result of our code so far. i think i am suppoosed to useâŚPropertyDrawer? research and chatGPT suggest thatâs the route to take next, but iâm not sure i understand how.
I hope that makes sense, and any further help would be most appreciated, as its difficult to find a correct answer by searching when i dont know exactly what to search for as far as terminology xD
The Editor canât know to serlialize a field from its type alone, which is why [SerializeField] exists. Itâs perfectly normal to mark a field as â[SerializeField] private float whatever = 2.0f;â when working in Unity, so youâre going to be doing that a lot anyway (or using âpublicâ if youâre that way inclined).
But yes, once the Editor knows it has to serialize something, if thereâs a matching PropertyDrawer it will be used to present it in the Inspector, so you shouldnât have to repeat the presentation code.
In short:
Unity knows what to serialize based on compatible fields being marked with [SerializeField] and/or being public.
The Inspector draws fields based on Component-specific code, PropertyDrawers, or using Inspector defaults.
Hi Iâm trying to do the exact same thing.
Did you by any chance make progess on the topic? I know its been a year but maybe youâll be able to save me a lot of time
Anyway thanks to all of you! Now I know that what I want to do is not impossible and I might find a solution eventually.