- Home /
public script variable in inspector
Hello,
like you can say 'public string' and there will be a box displayed in the script window in the inspector, is there a similar variable that let's you click and drag a script in there?
Thanks!
Answer by Bunny83 · Nov 27, 2016 at 07:36 PM
This boils down to what you understand by "script". If you ask if you can drag a script asset (the actual .cs or .js file) onto a variable, the answer is "no" for runtime scripts and "yes" for editor scripts.
Scripts inside the Unity editor are represented with the editor type "MonoScript". However that's an editor only class that can't be used in a runtime script.
edit
I quickly have written a property drawer which allows you, by simply attaching an attribute to a string variable, to have an object field in the inspector where you can drag and drop MonoScript files. It will extract the class name of the class inside the MonoScript and save that name in the string variable.
Two files are required:
MonoScriptPropertyDrawer.cs - this is the actual PropertyDrawer. This file has to be placed in a folder named "editor" inside your assets folder.
MonoScriptAttribute.cs - this is just the custom attribute definition. This file must not be inside an editor folder as it is required by your runtime scripts.
I released those under the MIT license in case someone want to change something.
Ohh it has a hidden "feature". You can click the label of the field in the inspector to toggle between object field and the usual text field where you can manually edit the string. Note however if you manually type in a string that doesn't represent the name of a MonoScript the object field can't link properly back.
To use this property drawer you have to import this namespace in the script where you want to have a MonoScriptField:
using B83.Unity.Attributes;
Then simply add the "MonoScript" attribute to your string variable like this:
[MonoScript]
public string typeName;
That's all
[ original post ]
If however you ask if you can drag and drop a script instance the answer is yes. That's actually one of the main features of Unity. You just have to use the type of script you want to use as variable type.
Short example:
public class MyScript : MonoBehaviour
{
public void Foo()
{
Debug.Log("Bar");
}
}
In another script you can define a variable of type MyScript:
public MyScript script;
void Start()
{
script.Foo();
}
When those two scripts are assigned to gameobjects in the scene you can drag the gameobject with the MyScript attached onto the variable "script" in the inspector of the other script.
Thanks a great bunch! I actually am using both those scripts :)
How would you use this now with a AddComponent("Your monoscript string here");
Hey, this is extremely useful, thank you! I just have one question:
If I wanted to restrict the scripts I can assign to only those which derive from a certain abstract class (instead of every script in my project) would that be possible? Is there somewhere in MonoScriptPropertyDrawer.cs I can edit to do this?
Uhm , that's already built into the property drawer and the MonoScriptAttribute I created. It has an optional type field that you can set to a certain base type. The field will only allow scripts which are assignable to that type. So you can use interfaces or base classes. Something like that:
[MonoScript(type = typeof(YourBaseClass))]
public string typeName;
So "YourBaseClass" can be an interface or base class type that the wanted script has to implement.
Answer by thechayed · Jul 31, 2021 at 06:13 PM
Hey, just wanted to add to @Bunny83's answer and say that it's incredibly important to use GetClass().FullName instead of .Name, because any classes within a Namespace will throw an error.
Here's the updated MonoScriptPropertyDrawer.cs :
/*****
* This is a simple PropertyDrawer for string variables to allow drag and drop
* of MonoScripts in the inspector of the Unity3d editor.
*
* NOTE: This is an editor script and need to be placed in a folder named "editor".
* It also requires another runtime file named "MonoScriptAttribute.cs"
*
* Copyright (c) 2016 Bunny83
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*****/
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using B83.Unity.Attributes;
namespace B83.Unity.Editor.PropertyDrawers
{
[CustomPropertyDrawer(typeof(MonoScriptAttribute), false)]
public class MonoScriptPropertyDrawer : PropertyDrawer
{
static Dictionary<string, MonoScript> m_ScriptCache;
static MonoScriptPropertyDrawer()
{
m_ScriptCache = new Dictionary<string, MonoScript>();
var scripts = Resources.FindObjectsOfTypeAll<MonoScript>();
for (int i = 0; i < scripts.Length; i++)
{
var type = scripts[i].GetClass();
if (type != null && !m_ScriptCache.ContainsKey(type.FullName))
{
m_ScriptCache.Add(type.FullName, scripts[i]);
}
}
}
bool m_ViewString = false;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
if (property.propertyType == SerializedPropertyType.String)
{
Rect r = EditorGUI.PrefixLabel(position, label);
Rect labelRect = position;
labelRect.xMax = r.xMin;
position = r;
m_ViewString = GUI.Toggle(labelRect, m_ViewString, "", "label");
if (m_ViewString)
{
property.stringValue = EditorGUI.TextField(position, property.stringValue);
return;
}
MonoScript script = null;
string typeName = property.stringValue;
if (!string.IsNullOrEmpty(typeName))
{
m_ScriptCache.TryGetValue(typeName, out script);
if (script == null)
GUI.color = Color.red;
}
script = (MonoScript)EditorGUI.ObjectField(position, script, typeof(MonoScript), false);
if (GUI.changed)
{
if (script != null)
{
var type = script.GetClass();
MonoScriptAttribute attr = (MonoScriptAttribute)attribute;
if (attr.type != null && !attr.type.IsAssignableFrom(type))
type = null;
if (type != null)
property.stringValue = script.GetClass().FullName;
else
Debug.LogWarning("The script file " + script.name + " doesn't contain an assignable class");
}
else
property.stringValue = "";
}
}
else
{
GUI.Label(position, "The MonoScript attribute can only be used on string variables");
}
}
}
}
Yes, you're right. I can't actually remember when Unity added proper namespace support but I guess this was already after they introduced it. Anyways I've updated my code. Btw
script.GetClass().Name
can be replaced by
type.FullName;