To clarify, at runtime I’m looking to create and add a script to an object based on what type the reference has. This functionality already exists in the form of MonoScript (ScriptReference/MonoScript.html). However MonoScript only works in the editor.
I’ve considered the following 2 approaches but they seem either inefficient or error prone:
- Use string properties and call gameObject.AddComponent(myString)
- Store script asset references as a TextAsset and then call gameObject.AddComponent(myTextAsset.name);
Option 2 might be ok but I don’t want Unity to load up the whole script file just to get its name.
Is there a better way?
Scripts are compiled into an assembly and so are all available at runtime. I do not know if the representative assets have to be loaded however.
I would just input the name of the script using a regular string variable.
If you are using Unity 4 then you can implement a custom property drawer and attribute to achieve drag & drop in the inspector:
Usage:
public class SomeBehaviour : MonoBehaviour {
[ScriptPicker]
public string myScriptName;
public void Foo() {
gameObject.AddComponent(myScriptName);
}
}
Attribute Implementation:
using UnityEngine;
public class ScriptPickerAttribute : PropertyAttribute {
}
Drawer Implementation:
using UnityEngine;
using UnityEditor;
[CustomPropertyDrawer(typeof(ScriptPickerAttribute))]
public class ScriptPickerPropertyDrawer : PropertyDrawer {
public override void OnGUI(Rect position, SerializedProperty prop, GUIContent) {
Rect rect;
int controlID = GUIUtility.GetControlID(FocusType.Passive);
int objectFieldWidth = 45;
// Detect drag & drop
CheckDragAndDrop(position, prop, controlID);
// Allow manual text entry
rect = new Rect(
position.x,
position.y,
position.width - objectFieldWidth - 2,
position.height
);
prop.stringValue = EditorGUI.TextField(
rect, label, prop.stringValue
);
// Allow drag & drop or selection from dialog
rect = new Rect(
position.xMax - objectFieldWidth,
position.y,
objectFieldWidth,
position.height
);
MonoScript script = (MonoScript)EditorGUI.ObjectField(
rect, null, typeof(MonoScript), false
);
if (script != null) {
prop.stringValue = script.name;
}
}
private void CheckDragAndDrop(Rect position, SerializedProperty prop, int controlID) {
Event e = Event.current;
EventType eventType = e.GetTypeForControl(controlID);
switch (eventType) {
case EventType.DragUpdated:
case EventType.DragPerform:
if (position.Contains(e.mousePosition)
&& DragAndDrop.objectReferences.Length == 1
&& DragAndDrop.objectReferences[0] is MonoScript)
{
if (eventType == EventType.DragUpdated) {
DragAndDrop.visualMode = DragAndDropVisualMode.Generic;
DragAndDrop.activeControlID = controlID;
}
else {
prop.stringValue = DragAndDrop.objectReferences[0].name;
DragAndDrop.AcceptDrag();
DragAndDrop.visualMode = DragAndDropVisualMode.None;
}
e.Use();
}
break;
}
}
}