GetComponent(variable) as variable?

Hello, this is my first post in the forum, so sorry if i’ll make some mistakes. Forgive my poor english too, I’m Italian. :slight_smile:
I’m using UnityScript, and I have some scripts that use a variable for getting info or setting var from/to another script.

Here is an example:

var script : GameObject;
var scriptName : String;
 
function OnCollisionEnter (collision : Collision) {
 
    script.GetComponent(scriptName).OnCollisionEnter(collision); // Error is here.
   //the rest of the code...
}

I’ve switched to Android and got 999+ error, because Android can’t use Dynamic Typing (i guess), but even if all this errors was fixed in many ways, this error is over my capabilities. The construct “GetComponent(String)” give a type Component, and I have to cast it to type scriptName.

I use this approach for other scripts too, for example for setting Damage to many scripts of enemies.

I tried many ways, here are some of them:

//EnemyInfo is a general script that all enemies have.

//This return MonoScript...
var type : System.Type = enemy.GetComponent(EnemyInfo).enemyScriptType.GetType(); //enemyScriptType is of type MonoScript.

//This return ScriptName, the right value
var type : System.Type = enemy.GetComponent(EnemyInfo).enemyScriptType.GetClass(); //enemyScriptType is of type MonoScript.

enemy.GetComponent(type).Life -= damage; //Life is not a member of Component
enemy.GetComponent(type as type).Life -= damage; //The name 'type' does not denote a valid type ('not found')
enemy.GetComponent.<type>().Life -= damage; //The name 'type' does not denote a valid type ('not found')

var type : String = enemy.GetComponent(EnemyInfo).enemyScriptName; //trying with strings

enemy.GetComponent(type).Life -= damage; //Life is not a member of Component
enemy.GetComponent(Type.GetType(type)).Life -= damage; // Unknown identifier: 'Type'
enemy.GetComponent(System.Type.GetType(type)).Life -= damage; // Life is not a member of Component

I have to store a type into a variable and then use it for declaring the type of the new variable, something like this:

var type : Systm.Type = ScriptName;

var enemyScript : type = enemy.GetComponent(type);

But I can’t get them to work… How can i solve this problem? :frowning:

Thanks in advance ;).

var script : GameObject;

var scriptName : String;

 

function OnCollisionEnter (collision : Collision) {

 

    script.GetComponent(scriptName).OnCollisionEnter(collision); // Error is here.

   //the rest of the code...

}

should be…

var objectWithThisScript : GameObject;

var  scriptDataAccessor : scriptName;

 

function OnCollisionEnter (collision : Collision) {

 

   scriptDataAccessor =  objectWithThisScript.GetComponent(scriptName); // Error is gone.

   //the rest of the code...

}

What you were doing was incorrect. Just get the component and thats it.

I don’t know before the ScriptName. I have to get it from an other script, because it will not always be script01, but it has to work with script02 and script03 too.

So I can’t create a var with type script01, because it won’t work with script02.

var objectWithScript : GameObject;
var actualScript : script01;

function OnCollisionEnter (collision : Collision) {
    
    actualScript = objectWithScript.GetComponent(infoScript).scriptToGet; //this will be script01/02/03...
    //error because script02/03/04... aren't script01.
    
}

My problem is how to get a component without knowing the name of it while I am scripting, but that I will know in runtime? Of what type should be the var scriptToGet for letting me GetComponent(scriptToGet) of type scriptToGet?

Of course, but how can i create a var that whose type is the class of scriptToGet if scriptToGet can have different classes?

I can’t use

var scriptType : System.Type = objectWithScript.GetComponent(infoScript).scriptToGet.GetClass();
var script : scriptType = objectWithScript.GetComponent(scriptType);

Oh I see. I ran into this issue. For my cause I did this…

When I have an object that will need to access an array of objects scripts but it does not know what object, and thus script it needs to access off hand, instead of the messy, messy (in this case) GetComponent, or for more advanced scripters, who could probably build a super class, with sub classes, which i am not, I use SendMessage().

It is quick, simple and easy. Just, consider each member needs a common function, like runMember() then the mng, will gather object*.SendMessage(“runMember”); now that object dos what it does.*

It works perfectly!! Really thanks for your help, now I can continue my game! :smile:

Warning: All code is untested and in C# !!!

I’d like to give you the standard solution for your problem, which uses inheritance. Let me describe it with an example. Let’s assume you have different kinds of enemies that behave completely different for some actions like running. You can specify a common base class for all enemies like that:

public abstract EnemyBase : MonoBehaviour {
	public abstract void Run ();
}

All it declares is that an actual enemy will be able to run, without an actual implementation. You can now specify some actual enemy classes, which derive from the base class and need to implement the running.

public class BossEnemy : EnemyBase {
	public override void Run () {
		// Boss run code goes here.
	}
}
public class WeakEnemy : EnemyBase {
	public override void Run () {
		// You weak enemy run code goes here.
	}
}

The advantage of this is, you can now actually call Run, instead of using SendMessage, which can lead to huge issues as the project gets bigger. When you know that a game object contains either a BossEnemy or a WeakEnemy and you want it to run, you can rely on EnemyBase.

EnemyBase someEnemy = theGameObjectWithTheEnemy.GetComponent <EnemyBase> ();
someEnemy.Run ();

If theGameObjectWithTheEnemy contains a BossEnemy, the Run function from that script will be called. If it contains a WeakEnemy, the run method of that one will be called.

I am aware that this probably sounds a little complex at first, but that is the standard solution for your scenario.

Thanks @Dantus.
This explanation of creating a superclass is much simpler, than previous explanations I read. One question tho if I can, is there a similar method, to pass a value?

@renman3000, of course. If you have to pass a value, instead of using Run (), declare it as Run (float speed) or maybe Run (Vector3 direction).

Right, so just pass it as an argument.

Cheers, this helps a lot. I will have to rebuild a little bit, but probably worth it.

Just to add to what Dantus said, this is a perfect time to make use of polymorphism where each separate class may have different functionality, but at their core have certain features the same. For example, say you wanted each of your enemies to “heal” after a certain amount of time, but you also wanted them to make different sounds/animations.

One way to do this is to add the code to “heal” in each of your child classes, weakEnemy, bossEnemy etc. But depending on the amount of Enemies you could have, this will get quite cumbersome, especially if you ever want to change the healing functionality.

The better way to do this, is to Create a base class which contains the base functionality that all objects inheriting from that class will apply(if they want to).

For instance:

public class Enemy : EnemyBase
{
protected float m_health;
protected float m_healthIncrement;

    protected virtual void Start () 
    {
            m_health = 100;
            m_healthIncrement = 25;
     }

   protected virtual  void Heal() 
   {
        m_health+=m_healthIncrement;

   }

   protected virtual void Update()
    {
         if(lastTimeHealed - CurrentTime >= delayForHeal)
          Heal();
    }
}

What this class has done is create Virtual functions. Best way to explain them is that they are similar to abstract functions but they can contain a body and they can also be called from a child class. So, If you then have a subclass( lets call it bossEnemy ) which inherits from Enemy.

public class bossEnemy : Enemy
{ 

  protected override Start()
  { 
     base.Start(); //base.Start() will make sure the Start method of the parent class is called. This allows you to initialise any variables
                      //which are shared among all child classes

    m_healthIncrement = 15; //Also, we can "override" the default values of variables in our parent class by reinitialising them after the       //call to base!
  }
 protected override Heal()
  { 
     base.Heal(); //Apply the health increment, no need to duplicate the code from the parent so it is in multiple places

     //Apply any unique functionality you want this enemy to excert when he is healing
     //e.g. Play a specific sound
     
  }
 protected override Update()
  { 
     base.Update();
  }
}

Basically, Because bossEnemy is a Enemy ( due to inheritance ), whenever you call a function using the parents class signature but you are actually referencing a child, the correct function will automatically be called!

So, If you used the same method and wanted for example, all enemies to jump when they hit something. You would create the virtual function inside the parent Enemy class, add the functionality, and override it in each child class, applying any extra functionality you would like.

void OnCollisionEnter (collision : Collision) {

 

    collision.gameObject.GetComponent<Enemy>().Jump(); //This will call the Jump function of whichver type of Enemy just collided  //with something!


}

May the force of polymorphism be with you.

Great, a really good solution! And lot of opportunities too! I think that it will be hard to translate in UnityScript, but maybe it’s time for me to get into C#. Another advantage for this solution is that you can send different values on the same function, with SendMessage you can’t. :slight_smile:

I didn’t understand the last part. If GameObject has Enemy and Child has bossEnemy (just for example) can I call Child.GetComponent(Enemy).Jump() even if there isn’t any Enemy script in it, but only BossEnemy that inherits from it?

By child I do not mean child of a gameobject in the hierarchy( if that is what you meant). I mean child of the class, i.e. a subclass which inherits frm Enemy

You wouldn’t add the Enemy component directly onto the gameobject, it is a base class. You would only add sub classes onto the game object, such as bossEnemy, soldierEnemy etc.

As long as the gameObject has a component of type “Enemy” (which means ANYTHING which inherits from Enemy) you can just call

gameObject.GetComponent(Enemy).Jump() //Or whatever the proper syntax is for your language. You don’t need to use “Child.” ( I assume that is JS or something?)

The syntax is correct for JS, so bossEnemy will be a child class (subclass) of Enemy and so it’s type should be Enemy. When i Call a script bossEnemy on any gameObject that has a bossEnemy Component, because bossEnemy inherits from Enemy I can call GetComponent(Enemy) on that gameObject, and should get the bossEnemy component of type Enemy. Is that right?

Yep!

:smile: Thanks for your patience, i’ve finally understood.
I’ll use this method, it seems that will be very useful for create some really dynamic results! I can make totally different things with the same base, and eventually change the main characteristics for all in the same time!!
Again thanks for showed me these so amazing things!!

I finally decided today to implement this method in my project. Because I’m programming in Js, i had to find a translation of the C# code into this language, and found this answer:

Just for to extend the answers of this topic, if I’ll find other things, I’ll let you know :wink:

Edit: If I create a Static Funcion I can’t refer to “gameObject”, because it needs an instance of it…
I have to create a variable of type GameObject as funcion value containing the gameObject whose the instance script calling this static function is attached to… :roll:

 static function Update (gameobj : GameObject)

I got a strange behaviour: If I call a function like this:

//this is BaseClass script;

static function Update (gameObj : GameObject) {
	
	if (Life <= 0) {
		
		Destroy(gameObj);
		
	}

}

all other Enemy : BaseClass call the same function (there are ten enemies with names like 0, 1, 2, …), with same values.

Has the BaseClass the same values for every subclass? If I damage an enemy, do the others’ life value (wich is stored in BaseClass) decrease too?

I know it because the array that holds all enemies becomes empty (10 “null” GameObjects) and then there are 10 new enemy with different positions from the others (so they were respawned with the random coordinates) and all of them have name ‘0’ (i’ve discovered with print() that the order of calls is the same of the array, so of the birth of the enemies). If I disable the auto-creation of new enemies (the number of enemies is fixed) all enemies disappear.

There is a logic problem :-?, do I have to create the same function on every Enemy : BaseClass, without include it in BaseClass?