- Home /
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[i][0];
Vector3 spd = (Vector3) bs[i][1];
}
}
}
}
And here is some code for my "pattern script":
public class FireMethod : MonoBehaviour
{
public List<ArrayList> Fire(GameObject b, Vector3 loc){
List<ArrayList> r = new List<ArrayList>();
r.Add(new ArrayList{Instantiate(b, loc, Quaternion.identity), new Vector3(0, 1, 0)});
return r;
}
}
Answer by Megaboy238 · Feb 10, 2021 at 09:16 PM
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[i][0];
Vector3 spd = (Vector3)bs[i][1];
}
}
}
}
public class FireMethod : MonoBehaviour
{
public static List<ArrayList> Fire(GameObject b, Vector3 loc)
{
List<ArrayList> r = new List<ArrayList>();
r.Add(new ArrayList { Instantiate(b, loc, Quaternion.identity), new Vector3(0, 1, 0) });
return r;
}
}
Thanks, this was a simple solution and worked effectively.
Answer by BastianUrbach · Feb 11, 2021 at 11:57 AM
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 {
...
}