Passing Script as a Public Variable,Passing Script as Public Variable

I am trying to implement a generic shooting method for a game I am making and part of what I would like to do is pass a script containing a method for the firing pattern to a generic shooting script. To accomplish this, I have set a public variable with the pattern script’s method in the generic script, but when I attempt to drag my pattern script into the appropriate slot in the editor, it rejects it.

Here is my code for the generic firing method:

public class Shooting : MonoBehaviour
{
    public GameObject bullet;
    List<ArrayList> bs;
    bool shouldFire;
    public FireMethod firePattern;
    // Start is called before the first frame update
    void Start()
    {
        bs = new List<ArrayList>();
        shouldFire = true;
    }

    void FixedUpdate(){
        if (shouldFire){
            List<ArrayList> to_add = firePattern.Fire(bullet, this.transform.position);
            foreach (ArrayList a in to_add){
                bs.Add(a);
            }
        }
        if (bs.Count != 0){
            for (var i = 0; i < bs.Count; i++){
                GameObject b = (GameObject) bs*[0];*

Vector3 spd = (Vector3) bs*[1];*
}
}
}
}
And here is some code for my “pattern script”:
public class FireMethod : MonoBehaviour
{
public List Fire(GameObject b, Vector3 loc){
List r = new List();

r.Add(new ArrayList{Instantiate(b, loc, Quaternion.identity), new Vector3(0, 1, 0)});

return r;
}
}

remove this line at the top

public FireMethod firePattern;

Add class name to Fire in FixedUpdate

List to_add = FireMethod.Fire(bullet, this.transform.position);

Then in “pattern script” add static to your method

public static List Fire(GameObject b, Vector3 loc)

This should work

public class Shooting : MonoBehaviour
{
    public GameObject bullet;
    List<ArrayList> bs;
    bool shouldFire;
    // Start is called before the first frame update
    void Start()
    {
        bs = new List<ArrayList>();
        shouldFire = true;
    }

    void FixedUpdate()
    {
        if (shouldFire)
        {
            List<ArrayList> to_add = FireMethod.Fire(bullet, this.transform.position);
            foreach (ArrayList a in to_add)
            {
                bs.Add(a);
            }
        }
        if (bs.Count != 0)
        {
            for (var i = 0; i < bs.Count; i++)
            {
                GameObject b = (GameObject)bs*[0];*

Vector3 spd = (Vector3)bs*[1];*
}
}
}
}

public class FireMethod : MonoBehaviour
{
public static List Fire(GameObject b, Vector3 loc)
{
List r = new List();

r.Add(new ArrayList { Instantiate(b, loc, Quaternion.identity), new Vector3(0, 1, 0) });

return r;
}
}

A MonoBehaviour is just a class of objects, it’s not an object itself so it can’t be assigned directly to a public variable. You have to create an instance of the MonoBehaviour and that instance has to be attached to a GameObject. A slightly better solution in your case would be to make FireMethod derive from ScriptableObject instead of MonoBehaviour. Scriptable objects behave more like Assets than like components so they don’t have to be attached to a GameObject but you still have to create them separately and can’t just assign the script directly. I think that’s about as close as you can get with Unity’s builtin functionality. Thankfully Unity is very extensible and we can make it do exactly what you want with a new baseclass and a custom property drawer. Drop this file in your project and make FireMethod a subclass of AssignableScript and it should work:

AssignableScript.cs

using UnityEngine;

#if UNITY_EDITOR

using UnityEditor;

[CustomPropertyDrawer(typeof(AssignableScript), true)]
public class AssignableScriptPropertyDrawer : PropertyDrawer {
	public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
		EditorGUI.BeginChangeCheck();

		var script = MonoScript.FromScriptableObject((ScriptableObject)property.objectReferenceValue);
		script = (MonoScript)EditorGUI.ObjectField(position, label, script, typeof(MonoScript), false);

		if (EditorGUI.EndChangeCheck()) {
			if (script) {
				var type = script.GetClass();

				if (typeof(AssignableScript).IsAssignableFrom(type)) {
					property.objectReferenceValue = ScriptableObject.CreateInstance(type);
				} else {
					Debug.LogError("Script " + type.Name + " must extend " + nameof(AssignableScript) + " to be assigned to this property");
				}
			} else {
				property.objectReferenceValue = null;
			}
		}
	}
}

#endif

public class AssignableScript : ScriptableObject { }

FireMethod.cs

public class FireMethod : AssignableScript {
	...
}