Find if any script on a GameObject has a specific variable?

I wish to clarify and amend this question.

If I am expecting to have a collision on a set layer,

there are many different types of object on that layer.

I know all of the objects will have a common variable on their script

that variables’ value is unique to them

but it is the same variable name across all different types of script

Can (and if so how) do I access that variable to read and write to ?

Can I also find out that type (the name of the script), store it as a string, then use it as a reference

e.g.

go = hit.collider.gameObject;
goScript : String = [name of go script].ToString();
goScript.health -= 1;

SendMessage is fine for one-way operations, and creating functions of variable names, to deal with those variables, but there is no way to use something like return[info]; in the script that is the target of the SendMessage.

Thanks =]


  • Original Question

I am playing around making an RTS game, and it is surprising how well it is going with just giving each type of object (fighter, archer, building, ect) a behaviour, and let them run off and be happy.

However I have just hit a bump where adding different types of enemy building etc i have a steadily increasing switch-case for finding what type of enemy I am around and GetComponent of that enemy script to deduct health from.

it didn’t click when I was doing some enemies, but when I added buildings I realized this is a pain, and I have to implement a universal health system.

my first idea is to have a health script that attached to everything, that simply SendMessage to its associated gameObject to deal damage, become dead, etc.

but I would like to know If i can do it without an extra script.

Can I Find if any script on a GameObject has a specific variable name?

to put it another way :

is there a way to search for a variable on a script (or all scripts as components of a GameObject) without knowing its typecast (script name)

and possibly from that can I find the type that script is, and use it later (like currentEnemyScript.health -= 1; ) ?

Just for explanation, this is what I’m starting to notice and wish to avoid :

each enemy has a different script for their behaviour of course (a building isn’t a troop … yet!) therefore a different script name, therefore a different TypeCast :

// check for opponents
// spherecast every 0.5 secs
// then ....

	for (var object : Collider in objectsInRange) 
	{
		switch( object.gameObject.name )
		{
			// Troops
			
			case "Troops_0" :
				// ... Do Stuff ... then
					troopTarget = object.gameObject.transform; 
			break;
			
			case "Miner_0" :
				// ... 
					minerTarget = object.gameObject.transform; 
			break;
			
			case "Builder" :
				// ... 
				builderTarget = object.gameObject.transform; 
			break;
			
			// Buildings
			
			case "Barracks" :
				// ... 
					barracksTarget = object.gameObject.transform; 
			break;
			
			case "Refinery" :
				// ... 
					refineryTarget = object.gameObject.transform; 
			break;
			
			case "0" :
				
			break;
		}
		
	}
		
	
	// store reference to targeted troop transform and script
	
	// then follow
	if ( troopTarget != null )
	{
		// switch case for troop name
		troop0script = troopTarget.GetComponent( "CharTroops0" ) as CharTroops0;
		
		// then follow
		targetFollowing = "Troops_0";
		enemyCurrentState = enemy0state.Following;
		
		currentTarget = troopTarget;
	}
	
	else if ( minerTarget != null )
	{
		// switch case for troop name
		miner0script = minerTarget.GetComponent( "CharMiner" ) as CharMiner;
		
		// then follow
		targetFollowing = "Miner_0";
		enemyCurrentState = enemy0state.Following;
		
		currentTarget = minerTarget;
	}
	
	else if ( builderTarget != null )
	{
		etc

Edit :

My idea of a health class that is applied to all Objects that can be damaged

the health script :

// the main script finds that var and changes it at start
// e.g. if a fighter then health = 5; if an archer then health = 3; etc
var health : float = 5.0; 

function JustBitTheDust()
    {
    // disable the troop gameObject
    // add the troop back to the pool
}

on the troop :

// when finding a target
targetHealthScript = hit.collider.gameobject.GetComponent("GenericHealthScript") as GenericHealthScript;

// every cycle that the troop does damage
targetHealthScript.health -= 1;

if (health <= 0) targetHealthScript.JustBitTheDust();

So there are three ways you could directly get variables and methods on a script without knowing its script name:

  • Reflection
  • Interfaces
  • Inheritance

So just to say it again - Reflection is slow. Reflection here would be very slow because you would need to interrogate all of the components on the target object looking for a particular method. In this case you might as well use SendMessage except for the fact you could get a return value - which obviously you want.

What you might be looking for is an Interface I think. Interfaces allow multiple objects to offer a well known behaviour but implement it in different ways. An interface definition is like a class definition except that there is no implementation. Then you actually implement the interface on each of your behaviours and you can treat them all the same. So, for example, things supporting an IAmAlive interface would all have health and be able to take damage, or heal. IRangedWeapon behaviours would all know how to aim and fire, IPickup behaviours would all be able to be displayed in an inventory and picked up etc. The benefit of interfaces is that a magic bow could for instance be alive, a ranged weapon and a pickup. This post talks about interfaces in UnityScript - it does mean you have to explicitly define your classes rather than let Unity do it all behind the scenes.

The other method is to use inheritance - in this case you are classifying objects - for example all living things inherit from LivingThing which has the variables and methods to affect health. Inheritance is more limited but you do not have to keep writing health methods. Often you will end up using both interfaces and inheritance! Make an interface to do something, then make a base class that implements that interface which most of your objects will be able to inherit from - special cases get their own version. Inheritance also requires that you explicitly define your classes and the base classes you write will need to inherit from MonoBehaviour.

Getting the interface on a component can be done with GetComponent.