GetComponent.<T> () and System Type.GetType()

trying to get component with a public string that gets converted to Type. but failing.
is there a way to get a component with a public var without knowing the Type upfront?
i want to be able to use this on many different objects, getting different custom scripts as components…

using UnityEngine;
using System;
using System.Collections;

public class PlayerActive : MonoBehaviour {
	
	public int raduis;
	public string Script;
	private Vector3 position;
	private Vector3 playerPosition;

	void Start () 
	{
		position = transform.position;
	}
	
	void Update () 
	{
		Type type = Type.GetType(Script);
		
		playerPosition=GameObject.FindGameObjectWithTag("Player").transform.position;
		if(type!=null)
		{
			print(type);
			if((position - playerPosition).sqrMagnitude < raduis)
				gameObject.GetComponent<type>().enabled = true;
			else
				gameObject.GetComponent<type>().enabled = false;
		}
		
	}
}

if you have a variable t, just use t.GetType() to get its type.

Providing a string is not a proper way to do it.
If you have no specific base class its still granted to be at least a UnityEngine.Component as thats what you can look for at maximum. All your own scripts actually extend MonoBehaviour (which extends Behaviour which extends Component) so if you only want to find custom scripts, you could make the variable Script of type MonoBehaviour instead of making it of type Component.

So replace:

public string Script;

with

public Component Script

and use Script.GetType(); to get its type

with

public Component Script;

if i do

void Start () 
	{
		Script=Script.GetType();

it says: can’t convert system.type to unityengine.component

if i just do

void Start () 
	{
		Script.GetType();

it keeps saying that Script is a field not a type

so I’m a bit confused on where and how to put it to make it work.

Still stuck with this also tried

Type type=script.GetType();
script=gameObject.GetComponent<type>();

script still beeing a public Component.
but then it says type or namespace type not found.

Can you maybe explain a bit better what you’re trying to accomplish exactly?

I’m trying to make a script that turns a component on/off, but i want to component to be set in the inspector. so it can be any kind of type. trying to do it by giving the name of the desired component.

there is Type.GetType() that i thought could get my type (it has a string overload) and using GetComponent either by type or by string.
looks like a combination of the two should do the trick but i can’t find how. :frowning:

trying this:
script is a public string set to CollectItem which is the script I’m trying to get in this case…

Component Script=gameObject.GetComponent(script)as Component;
			Script.GetType();
			print(Script);

debugs:

element_neon (CollectItem)
UnityEngine.MonoBehaviour:print(Object)

which seems what i want only if i try to acces public fields of the component it says it doesn’t have them

Why don’t you just declare a public MonoBehaviour (or Component) and assign it via the inspector then? Or use the string overload of GetComponent and cast it yourself? (Although the second method opens you up to typos)

because with this:

public MonoBehaviour Script;
Script=gameObject.GetComponent<Script>();

i get :

`PlayerDistanceActive.Script' is a `field' but a `type' was expected

Could you explain why you can’t use the conventional way:

public MonoBehaviour Script;
Script=gameObject.GetComponent<MonoBehaviour>();

Or if it’s public why you can’t just assign it via the Inspector? Or don’t use the generic overload of GetComponent?

Script = gameObject.GetComponent(typeof(Script));
2 Likes

for example i have a script on my items: “CollectItem” and i have this script: “PlayerDistanceActive”. and so if the distance between the player and the item is less than the radius i set in PlayerScriptActive. a bool gets changed in CollectItem.
this works great for collecting items, now I’d like to change the PlayerDistanceActive so i can use it with other scripts/components without hardcoding the type of component.

Then make all your classes that need to interact in this way derive from the same base class. The more “correct” way would be to implement a common interface but that’s a pain to get working well with GetComponent and often includes additional overhead.

for now i don’t have other then CollectItem but I’ll keep that in mind.
I really want it to be as generic as possible so i can access Custom Scripts as well as monoBehaviour derived classes

ended up using this:

using UnityEngine;
using System;
using System.Collections;

public class PlayerDistanceActive : MonoBehaviour {
	
	public int raduis=2;
	public string script;
	private MonoBehaviour Script;
	private Vector3 position;
	private Vector3 playerPosition;

	void Start () 
	{ 
		Script= gameObject.GetComponent(script) as MonoBehaviour;	
	}
	
	void Update () 
	{	
		position = transform.position;
		playerPosition=GameObject.FindGameObjectWithTag("Player").transform.position;
		if((position - playerPosition).sqrMagnitude < raduis)
		{
			Script.enabled=true;
		}
		else if(Script != null)
		{
			Script.enabled=false;
		}
	}
}

I wonder if this is cheaper then letting the player activate things with a raycast or trigger.
in the end if every item or interactive part in my game will have this script on it… won’t constant check of every item for the player position be more exspensive?

this is the worst performing and least secure solution as it does not check if ‘script’ has a typo in.

I might not get it but why exactly didn’t you just use

public MonoBehaviour Script;
MonoBehaviour myComponent = GetComponent<Script.GetType()>();

as recommended earlier which will work and which at compile time would already error out if ‘Script’ is not declared as Component or a descendent type

As long as script is a string you are basically hoping that it will not fail and I would be willing (not meant rude, just experience) to bet that you will be hunting down one or more strange crash - null ref exceptions later on due to your “solution”. If this ever goes to mobile, thats a major thing as null ref exceptions on mobile mean that your application gets instantly killed by the OS.

hey Dreamora, thanks a lot this is just the feedback I’m looking for! (no pun intended)

but i tried that and monodevelop doesn’t except:

 MonoBehaviour myComponent = GetComponent<Script.GetType()>();

looks like i can’t do the () behind GetType like this.

line 15, idk worked for me so many thanks :slight_smile:

I am trying to develop something similar for very different reasons. I’m just trying to have a generic component that you assign in the inspector (eg Camera, MonoBehaviour, Light, Audio Listener etc.), and I’m trying to make a script that can toggle these on and off from Game, just as a debugging/ quality of life thing. I’m trying to make it Generic as possible to be reusable, but i’m running into a lot of these same problems.

Wow, ok, 2 min after I posted this I solved it and it was really 'heckin easy. Boy do I feel dumb.
Here is the script I got working:

using UnityEngine;

public class Disabler : MonoBehaviour
{
    public Behaviour componentToDisable;
    public KeyCode pauseKey;

    void Update()
    {
        if (componentToDisable != null)
        {
            if (Input.GetKeyDown(pauseKey))
            {
                componentToDisable.enabled = false;
            }
            if (Input.GetKeyUp(pauseKey))
            {
                componentToDisable.enabled = true;
            }
        }
    }
}

Quick Script Update - Just in case you want to disable multiple components at once

using UnityEngine;
public class DisablerArray : MonoBehaviour
{
    public Behaviour[] componentsToDisable;
    public KeyCode pauseKey;
    void Update()
    {
        if (componentsToDisable != null)
        {
            if (Input.GetKeyDown(pauseKey))
                foreach (Behaviour i in componentsToDisable)
                    i.enabled = false;
            if (Input.GetKeyUp(pauseKey))
                foreach (Behaviour i in componentsToDisable)
                    i.enabled = true;
        }
    }
}