Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Can I assign a script in the Inspector?

Discussion in 'Scripting' started by GarthSmith, Oct 17, 2014.

  1. GarthSmith

    GarthSmith

    Joined:
    Apr 26, 2012
    Posts:
    1,240
    I want a script to AddComponent<SomeMonoBehaviour>() to it's gameObject, but I want to be able to assign different MonoBehaviours to add to the gameObject.

    Example: I have a HealEverySecond MonoBehaviour and a DamageEverySecond MonoBehaviour. I want a third script to add one or the other, depending on what's assigned in the inspector. I can do this currently if I use a string, but then anything can be entered in the string field by anyone.
    Code (csharp):
    1. // Is there anyway to assign the script directly?
    2. public string scriptNameToAdd;
    3.  
    4. void Start() {
    5.   gameObject.AddComponent(scriptNameToAdd);
    6. }
    The problem with this is that any string can be entered and I won't know if the script name doesn't exist until runtime.
     
  2. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,523
    This is a great question, and I've wondered about the best solution myself. It's not ideal, but what about a custom inspector (or [ExecuteInPlayMode]) that tries to add the component at design time when you assign the property? If it throws an exception, you can report an error. If it works, you can remove the component.
     
  3. RockoDyne

    RockoDyne

    Joined:
    Apr 10, 2014
    Posts:
    2,234
  4. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,523
    The way I read Garth Smith's question is that the parent script doesn't know ahead of time what type of child script will be assigned, so it can't specify RequireComponent or AddComponent with a specific type.
     
  5. Cpt Chuckles

    Cpt Chuckles

    Joined:
    Dec 31, 2012
    Posts:
    86
    what if you made a List<MonoBehaviour>?

    or if you only need one you could just say
    Code (csharp):
    1. public MonoBehaviour scriptToAdd;
    2.  
    3. void Start()
    4. {
    5.     if(scriptToAdd) AddComponent(scriptToAdd);
    6.     else Debug.LogError("No script assigned to be added to object "+gameObject.name);
    7. }
    or if you need a bunch you might be able to just make an array
    Code (csharp):
    1. public MonoBehaviour[] scriptsToAdd;
    2.  
    3. void Start()
    4. {
    5.     if(scriptsToAdd.Length > 0)
    6.         foreach(MonoBehaviour s in scriptsToAdd) AddComponent(s);
    7. }
     
    Last edited: Oct 17, 2014
  6. RockoDyne

    RockoDyne

    Joined:
    Apr 10, 2014
    Posts:
    2,234
    Scratch that. My bigger question is why do you need multiple scripts to separately handle a positive and a negative value? Hell, why is this not just some function of the main health/stats class?

    Ignoring my main issue, I'll also turn against common wisdom and say this is probably a case where you should actually hard code values. I would assume there are actual conditions in place already to determine what to assign, so why would they not know exactly what they are there to assign in the first place?
     
  7. GarthSmith

    GarthSmith

    Joined:
    Apr 26, 2012
    Posts:
    1,240
    @RockoDyne I'm attempting to do something like the Command pattern where I can assign commands to an Item just by dragging and dropping a script that contains the command in it. I already have it working, but it would be nice if I can create new item types by dragging and dropping a couple of scripts on it.

    Again, this way works, but I wish there was a better way to validate the data.

    Other work arounds are to create an editor script that validates the string and makes sure it's a valid class name, or to create an enum of known item commands and use the enum to provide a drop down list in the inspector.
    Code (csharp):
    1. public class Item : MonoBehaviour
    2. {
    3.   public string[] commandScripts;
    4.  
    5.   public void Use()
    6.   {
    7.     foreach (string scriptName in commandScripts)
    8.     {
    9.       gameObject.AddComponent(scriptName);
    10.     }
    11.   }
    12. }
     
    Last edited: Oct 17, 2014
  8. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,523
    Just brainstorming other ideas. What about pushing off the validation into a ScriptableObject? Then you can assign ScriptableObjects to your Item's commandScripts instead of strings. It doesn't completely solve the problem, but it allows you to assign assets to your component without worrying about typos.
     
  9. RockoDyne

    RockoDyne

    Joined:
    Apr 10, 2014
    Posts:
    2,234
    Of options you presented, I would lean toward the enum route. Not knowing much about what this is actually trying to solve though, this all feels like an over engineered solution to a problem that's not even the root problem.


    Does seem like there should be some kind of way to do
    Code (CSharp):
    1. public Object obj;
    2.  
    3. AddComponent<TypeOf(obj)>();