pass child class to ScriptableObject.CreateInstance<> ?

I’m building a custom editor to assemble a list of custom scripts and put them in a List<> on a script deriving from MonoBehaviour.

So far, my editor is working well. The point I’m stuck at is passing a variable from a list of types to ScriptableObject.CreateInstance<>

code snippets:

    public class MyEditorClass: Editor
    {
    
        private List<Type> behaviorTypes = new List<Type>();
        private int selectedType;
        void OnEnable()
        {
             behaviorTypes = ReflectionVoodooThatGetsDesiredTypes(); // this works as expected
        }
    
        void OnInspectorGUI()
        {
              if (GUILayout.Button("Add", GUILayout.ExpandWidth(true)))
		{
                    AddStuff();
                }
        }

        void AddStuff()
        {
            Type childClass = behaviorTypes[selectedType];
         AddBehavior(ScriptableObject.CreateInstance<childClass >()); // this doesn't work.  what is the proper way to do what I'm conceptually trying to achieve here? 
        }
    }

I have a base behavior class that inherits from ScritpableObject, and then several child classes that branch off of that to create a behavior tree. I have a List<> that stores all types that are derived from my base behavior class. I want to be able to select a type from that list and pass it to the ScriptableObject.CreateInstance() function.

I had this previously working using this line of code:

AddBehavior(behaviors[typeSelection].GetConstructors()[0].Invoke(new object[0]) as BaseBehavior);

this worked, but due to serialization child class types were being lost. So, now that I’ve switched over to ScriptableObject, my serialization problems are solved, but instantiation problems arise.

Thanks in advance

just to clarify, i do not know what type will be passed to ScriptableObject.CreateInstance, and I want that to remain flexible without having to build a large switch case, so that the behavior tree can be extended in the future with no updates to this chunk of code

I don't think you can instantiate a scriptable object. Only Monobehaviors.

ScriptableObject.CreateInstance() is the preferred method for creating a ScriptableObject. if you try to create one via: new BehaviorObject(); // where BehaviorObject inherits from ScriptableObject you'll get a warning.

btw: [UnityEngine.Object.Instantiate][1] works for all objects derived from UnityEngine.Object (that includes even Mesh, Material, ... and should also work with ScriptableObject) :) [1]: http://docs.unity3d.com/Documentation/ScriptReference/Object.Instantiate.html

Hmm, well, it is only a warning, but this warning pops up every time I try to use the class constructor via System.Reflection. I wanted to make sure that I do things properly to avoid any weird serialization problems later. The warning I'm seeing: AlternateExplode must be instantiated using the ScriptableObject.CreateInstance method instead of new AlternateExplode. UnityEngine.ScriptableObject:.ctor()

1 Answer

1

Simply don’t use the generic version of CreateInstance but the Type version

how do i get this to work with a List list? it does not work to call the method like this: List<Type> types; // this is how i am currently storing my BehaviorTypes, and it works for everything else that i need it for ScriptableObject.CreateInstance(types[0]); // this doesn't work similarly, I can't just say: ScriptableObject.CreateInstance("string_name_of_my_type"), because this doesn't actually become my inherited type, but only a scriptable object named "string_name_of_my_type". er, what am I missing here?

I can't make an explicit reference, as it will defeat the purpose of the entire editor script. I cannot code: ScriptableObject.CreateInstance<BehaviorType>(); because in my code, BehaviorType will in reality be any one of several subclasses of my base class BehaviorType

This ScriptableObject.CreateInstance(types[0]); Should work just finefine. Are you sure you have a valid ScriptableObject? So the filename matches the classname? I can't test myself at the moment since I'm not at home and only have my tablet here :-)

arrg! haha yeah, ok, I switched some code in a different area that bypassed my typechecking, so I was no longer checking to make sure that only one BehaviorType was added. So, I was mislead to believe that ScriptableObject wasn't checking it's type, and was therefore not doing what I wanted. Thanks for the help! ScriptableObject.CreateInstance(types[0]); that works as it should. the fault is, of course, mine :D