Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

[Solved] Finding Script by name and run function from it.

Discussion in 'Scripting' started by Altwo, Jun 26, 2019.

  1. Altwo

    Altwo

    Joined:
    Aug 7, 2018
    Posts:
    9
    Hello. I try to find script that attached to same object by name and run function from it using
    Code (CSharp):
    1.  gameObject.GetComponent(ScriptName).MyFunction(something);
    but I get
    Error 'Component' does not contain a definition for 'MyFunction' and no extension method 'MyFunction' accepting a first argument of type 'Component' could be found (are you missing a using directive or an assembly reference?)
    Any suggestions how to make it work?
     
  2. Deleted User

    Deleted User

    Guest

    Did you add MyFunction to the public or private variable list?
     
  3. Altwo

    Altwo

    Joined:
    Aug 7, 2018
    Posts:
    9
    Function declared as public, if i understand you right
     
  4. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,193
    The reason it's not working is that the version of GetComponent you're using returns an object cast to Component. Instead, you should use the generic version of GetComponent, like this:

    Code (CSharp):
    1. gameObject.GetComponent<ScriptName>().MyFunction(something);
    Note that ScriptName in this case isn't a string: it's the type of your script.

    I highly recommend using the generic version like this. But if, for some reason, you really want to use the other version, you'd need to cast the result of the GetComponent call before you can call methods on it. The docs for GetComponent shows that approach towards the bottom: https://docs.unity3d.com/ScriptReference/GameObject.GetComponent.html

    Still, if you can avoid using strings, that's usually best, since it's more robust.
     
    Last edited: Jun 26, 2019
    WallaceT_MFM likes this.
  5. Altwo

    Altwo

    Joined:
    Aug 7, 2018
    Posts:
    9
    Thanks but I can't avoid using strings, so how can I convert a string to a type then?
     
  6. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,186
    Why can't you avoid using strings?
     
  7. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,193
    I think you're most likely wrong in that statement, at least not based on the example you gave. So let's dig into that a bit.

    Let's imagine I made this component, called MyComponent:

    Code (CSharp):
    1.     public class MyComponent : MonoBehaviour
    2.     {
    3.         public void DoSomething()
    4.         {
    5.  
    6.         }
    7.     }
    Now let's say I put that component on some object, and I want to do what you're doing: Get the component, and call DoSomething() on it. I can do that either of the following two ways, either using strings, or using the generic approach:

    Code (CSharp):
    1. // Generic Approach:
    2. theGameObject.GetComponent<MyComponent>().DoSomething();
    3.  
    4. // String approach:
    5. ((MyComponent)theGameObject.GetComponent("MyComponent")).DoSomething();
    You can see that if I use the string "MyComponent", I need to cast the result before calling DoSomething on it.

    Both of these calls are equivalent, but the string-based approach is more fragile, and more likely to break in the future due to class renaming. So, the generic approach is preferred.

    In what way can you not avoid using strings? I would think that would only be the case if everything about your code was dynamic, in which case you'd be using reflection anyway.
     
    MoonJellyGames likes this.
  8. Altwo

    Altwo

    Joined:
    Aug 7, 2018
    Posts:
    9
    Ok. Maybe about that I was wrong. So i have dropdown list. Depending on the option chosen, I need to add (or enable) a specific script. With aother action (for example button click) i need to run specific function exectly from that script.
     
  9. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,193
    There are probably a lot of different approaches you could take for that. The two that come to mind are:
    • Just hardcoding things if you don't have too many different options in the dropdown
    • Use reflection
    If you only have a few items in the dropdown, then I might just hardcode things. So, let's say you had two options: "A" and "B":
    Code (CSharp):
    1. if (choice == "A") {
    2.     theGameObject.GetComponent<ComponentA>().DoSomething();
    3. } else if (choice == "B") {
    4.     theGameObject.GetComponent<ComponentB>().DoSomethingElse();
    5. }
    That's simple, but messy if you have a lot of choices.

    Reflection is another option, more similar to what you were originally doing, where everything is dynamic. Something like this:

    Code (CSharp):
    1.         public void CallSomeMethod(GameObject go, string componentName, string methodName)
    2.         {
    3.             var component = go.GetComponent(componentName);
    4.             var componentType = component.GetType();
    5.             var methodInfo = componentType.GetMethod(methodName);
    6.             var parameters = new object[0]; // Set up parameters here, if needed.
    7.             methodInfo.Invoke(component, parameters);
    8.         }
    I'm sure others will have other suggestions as well, but either of those could work.
     
    Altwo likes this.
  10. Altwo

    Altwo

    Joined:
    Aug 7, 2018
    Posts:
    9
    Thank you for help. It's really works.