- Home /
How do you instantiate a script from a monoscript?
I'm making en editor tool to create prefabs from selected scripts. Selection.objects returns a list of objects which are actually monoscripts. Monoscripts can't seem to be cast as anything, and while I can use GetClass() to find the type, I don't know how to use that type to instantiate a new, properly casted script object. Instantiate(obj) as ScriptName returns a null, and I can't figure out how to fit the returned (GetClass()) type into a New() method, since unity doesn't register that as a type.
Important note: This class doesn't derive from monobehaviour. Previous it did, and I was using AddComponent<((Monoscript)obj).GetClass()>(), but since then I've discovered I need it to be a custom class.
Here's the entire, currently mangled script so you can see what I'm doing:
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Collections;
public class CreateItemPrefabs : EditorWindow {
[MenuItem ("Tools/Create Item Prefabs")]
static void CreatePrefabs () // goes through each script selected in the editor and creates a prefab
{
foreach (Object obj in Selection.objects)
{
var go = new GameObject();
//System.Type itemType = ((MonoScript)obj).GetClass();
Item instance = Instantiate( obj) as Item;
var container = go.AddComponent<ItemContainer>();
container.m_Item = instance;
Debug.Log(instance.GetType());
Item _item = go.GetComponent<Item>();
if( !(instance is Item))
{
Debug.Log("skipped");
continue;
}
// Add interactive script and tag it
var pickupScript = go.AddComponent<InteractData>();
pickupScript.interactTag = "Item";
pickupScript.hoverMessage = "pick up " + _item.itemName;
// Change tag to interact
go.tag = "Interact";
Object prefab = AssetDatabase.LoadAssetAtPath("Assets/Prefabs/Items/"+obj.name+".prefab", typeof(Object));
// if no prefab is found, create one.
if (prefab == null)
{
prefab = PrefabUtility.CreateEmptyPrefab("Assets/Prefabs/Items/"+obj.name+".prefab");
}
// Replace prefab
PrefabUtility.ReplacePrefab(go, prefab, ReplacePrefabOptions.ReplaceNameBased);
DestroyImmediate(go);
}
}
}
You can only add Component
s to a GameObject
. If your class doesn't inherit from Component
, you have absolutely no chance at all for adding it as a component. $$anonymous$$onoBehaviour
for instance inherits from Component
and can therefore be added as a component. EditorWindow
inherits from ScriptableObject
, which inherits from Object
. EditorWindow
therefore doesn't inherit from Component
and cannot be added as such.
It seems you can only create a $$anonymous$$onoScript
from either a ScriptableObject
or $$anonymous$$onoBehaviour
. see here
I'm not trying to create a monoscript. I'm trying to instantiate a class from the value returned by GetClass()
Answer by aidesigner · Oct 10, 2014 at 11:43 AM
Here are your options depending on your base class. Since .NET is a statically typed language you must know a common base that all your instances will share. Note .Net has recently added great support for the dynamic type, but it is a long way from making it to Unity (Mono 2.6).
Base Class System.Object:
MyCommonClass myCommonClass = Activator.CreateInstance(myMonoScript.GetClass()) as MyCommonClass;
Base Class ScriptableObject:
MyCommonClass myCommonClass = ScriptableObject.CreateInstance(myMonoScript.GetClass()) as MyCommonClass;
Answer by hferrone1 · Mar 19, 2018 at 09:15 PM
I know this is years later, but I wanted to leave a solution here for anyone that's struggled with this exact problem for hours on end. @dustingunn
NOTE: This is using ScriptableObject, and hasn't been tested with @aidesigner's suggestion of creating a Base Class System.Object.
Step 1 - Abstract class FTW
Declare an abstract class that inherits from ScriptableObject and include any methods you may need.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public abstract class CommonScriptableClass : ScriptableObject
{
public abstract void DoSomething();
}
Step 2 - Subclass
Create a new script (or scripts) that you want to inherit from CommonScriptableClass and override any of its methods if applicable.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestClass : CommonScriptableClass
{
public override void DoSomething(){}
}
Step 3 - Create SO from MonoScript
Now, in your custom Editor Window of choice:
CommonScriptableObject newScript =
(CommonScriptableObject)ScriptableObject.CreateInstance(monoScript.GetClass());
newScript.DoSomething();
Editor.CreateEditor(newScript).OnInspectorGUI();
Works in an Editor Window and displays correctly. Hope this helps someone.
Your answer
Follow this Question
Related Questions
Hiding scripts from monoscript selector 1 Answer
CustomAttribute on Class or Method ( EDIT: Button to call methods) 2 Answers
Detect if unity hub 0 Answers
Using an Array of "MyClass" in EditorGUILayout.ObjectField ? 0 Answers
How to use "SerializeObject" with an object which doesn't derive from Object? 1 Answer