- Home /
Using a script as a member variable in another script.
Hey,
I will preface this by saying I am using C# for my scripts.
I have a script called ButtonAction. It is derived from MonoBehaviour. It has a function named Respond().
I have a script called LoadScene. It is derived from ButtonAction. It also has a funciton named Respond().
I have a script called PlaySound. It is derived from ButtonAction. It also has a function named Respond().
I have a game object. It has a script named StaticObject attached to it.
In the script StaticObject, I want to have a public variable. This variable must, essentially, be a script. More specifically, a ButtonAction script. More specifically still, the variable must hold a script derived from ButtonAction.
In the script StaticObject, I wish to call the Respond() function of the aforementioned member variable, and have the appropriate function be called.
This is to achieve a system where I can have a Prefab that has the StaticObject script attached to it and I can make many instances of said Prefab but have each one execute a different script when clicked without braking the instance link to the prefab.
Any guidance in achieving this would be appreciated.
Answer by Statement · Dec 13, 2011 at 04:34 PM
Do you mean that you want an easy way to change the implementation of respond? Unity offer limited existing help for this, since what I guess you want to do is make an option to choose an implementation detail for your component (Strategy Pattern).
If you have a known and fixed set of options, you could do with an enum, and add corresponding component to your object during awake. This is a bit quicker to code than the other solutions since you only need to create an enum, a public variable for it and a switch that add the right component to the object.
If it's not known during code design time and enums aren't an options, you could make an editor inspector script that use reflection to find all derived classes and present them as options. You'd then store the name of that class and use AddComponent with the string or type argument overload.
If I misunderstood you and you just need to be able to link to an existing game object that has a ButtonAction script on it, just add a public variable of that type.
public ButtonAction action;
Update to comment discussion:
public class Test : MonoBehaviour
{
public enum ClickOptions { ClickMethod1, ClickMethod2, ClickMethod3 }
public ClickOptions click;
void OnGUI()
{
if (GUI.Button(new Rect(0, 0, 64, 64), "Click me"))
SendMessage(click.ToString());
}
void ClickMethod1() { Debug.Log("Clicked"); }
void ClickMethod2() { Debug.Log("Clicketyclick"); }
void ClickMethod3() { Debug.Log("Click click click"); }
}
This doesn't add much flexibility in regard to scripts. But you could easily do the same with AddComponent(click.ToString()) if the ClickOptions enum contain name of classes you want to support, and send a message later.
Thanks for the reply,
No you didn't misunderstand me and have outlined the options I thought I had available.
I was thinking of using an enum - it's just that switch statements get messy and huge. Thanks agin!
You could use the enums mapped to function calls by string. See updated answer.
Answer by UnityBrains · Dec 13, 2011 at 09:31 PM
Edit: Read the comments. This doesn't work.
I thought I'd update the situation. I now have the exact behaviour I wanted.
I create an empty game object in my scene. I attach this script to it:
using UnityEngine;
using System.Collections;
public class TheScript : MonoBehaviour
{
// Use this for initialization
void Start () {}
// Update is called once per frame
void Update () {}
void OnGUI()
{
if(GUI.Button(new Rect(x, y, 64, 64), Tex))
{
gameObject.AddComponent(a.GetClass());
gameObject.GetComponent(a.GetClass()).SendMessage("Respond");
Object.Destroy(gameObject.GetComponent(a.GetClass()));
}
}
public Texture2D Tex;
public UnityEditor.MonoScript a;
public int x;
public int y;
}
I have written this base class script:
using UnityEngine;
using System.Collections;
public abstract class BaseClass : MonoBehaviour
{
// Use this for initialization
void Start () {}
// Update is called once per frame
void Update () {}
abstract public void Respond();
}
...from which these are derived: using UnityEngine; using System.Collections;
public class DerivedA : BaseClass
{
// Use this for initialization
void Start () {}
// Update is called once per frame
void Update () {}
override public void Respond()
{
print("DerivedA");
}
}
...and: using UnityEngine; using System.Collections;
public class DerivedA : BaseClass
{
// Use this for initialization
void Start () {}
// Update is called once per frame
void Update () {}
override public void Respond()
{
print("DerivedA");
}
}
So now, when I drag either DerivedA or DerivedB onto the "A" member variable of TheScript in the inspector, the appropriate "Respond" funciton is called. I am posting this to clarify my original question and posting a solution so that if someone else needs to do this later, they can google it and hopefully find this solution. It may also be common knowledge, but if it is, it's not easy to find. Hopefully this post makes it a little easier.
I would, however, like to get some feedback on the code if possible. It may be somewhat naieve in its execution and could be done more safely, efficiently or easily.
You won't be able to release a build with this since you're referencing UnityEditor inside game code which isn't included in the final build (try it yourself). If you could, it would be a nice feature of Unity indeed!
EDIT: Another update.
I changed TheScript to use a string ins$$anonymous$$d of the $$anonymous$$onoScript value. It behaves the same, but you have to type in the name of hte script you want to have activate (and this builds and runs :P). It's a bit clunkier than I'd like it to be.
Edit again: Thanks for the help Statement. How do you +Reccommend people here? Your enum suggestion is a nice solution.
upvoted for you as it was a good point that I hadn't thought of and let to problems in my own code.
Your answer
Follow this Question
Related Questions
An OS design issue: File types associated with their appropriate programs 1 Answer
Javascript not being updated, variables being overridden, but C# is fine 1 Answer
Parent Class variables in Child Class's Inspector (C#) 0 Answers
Editing a variable from another script on collision 3 Answers
Multiple Cars not working 1 Answer