Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
2
Question by AlucardJay · Oct 05, 2012 at 07:33 AM · componentstypecast

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();
 

Comment
Add comment · Show 10
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Demigiant · Oct 05, 2012 at 08:01 AM 0
Share

You could do that using Reflection, but it would be super slow.

avatar image AlucardJay · Oct 05, 2012 at 08:11 AM 0
Share

Thanks Fattie, I'm slowly getting this stuff via osmosis. I'm trying to make everything modular and universal. As I said, it would be quite easy with a universal health script (only one type there) and Send$$anonymous$$essage can do its thing.

avatar image Griffo · Oct 05, 2012 at 08:18 AM 0
Share

I'd like to know the answer to this question to, as I was at that point not long ago and used a globalVars script to hold ALL the enemy health variables, and ray cast to check what enemy I was facing then call the relevant health variable from the globalVars script.

avatar image Fattie · Oct 05, 2012 at 08:26 AM 0
Share

GRIFFO - there's nothing at all wrong with using a singleton (or some careful approach to essentially globals) in game engineering.

But the "send$$anonymous$$essage" concept is incredibly useful, once your program$$anonymous$$g comes along! Enjoy!

avatar image whydoidoit · Oct 05, 2012 at 08:58 AM 1
Share

BTW you could make that code a little less verbose and a bit faster by doing:

     someScript = someTarget.GetComponent(Char$$anonymous$$inerForExample);

The non-quoted version is faster and does not need to be cast with an as afterwards.

Show more comments

1 Reply

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by whydoidoit · Oct 06, 2012 at 08:51 AM

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.

Comment
Add comment · Show 10 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image whydoidoit · Oct 06, 2012 at 09:06 AM 0
Share

Ok here's an example:

TestInterfaces.js

 #pragma strict
 
 var items : GameObject[];
 
 function Start () {
 
 }
 
 function Update () {
     for(var o in items)
     {
          Debug.Log(o.GetComponent(IAmAlive).Damage(4).ToString());
     }
 }


IAmAlive.js

 #pragma strict
 
 interface IAmAlive
 {
     function GetCurrentHealth() : float;
     function Damage(amount : float) : float;
 }


ThingWithHealth.js

 #pragma strict
 
 class ThingWithHealth extends $$anonymous$$onoBehaviour implements IAmAlive
 {
 
     var health : int;
     
     function GetCurrentHealth() : float
     {
         return health;
     }
     
     function Damage(amount : float) : float
     {
         health -= amount;
         return health;
     }
 
 }

OtherThingWithHealth.js

 #pragma strict
 
 class OtherThingWithHealth extends $$anonymous$$onoBehaviour implements IAmAlive
 {
     var health : float;
     
     function GetCurrentHealth() : float
     {
         return health;
     }
     
     function Damage(amount : float) : float
     {
         health -= amount/2;
         return health;
     }
     
     function Update()
     {
         health += Time.deltaTime;
     }
 }
avatar image whydoidoit · Oct 06, 2012 at 09:07 AM 0
Share

In that example you can see how each of the two different classes that implement IAmAlive can be found in exactly the same way without knowing their script name, just the fact that they implement IAmAlive.

avatar image whydoidoit · Oct 06, 2012 at 09:17 AM 0
Share

To complete the set here is an example of using inheritance and interfaces that works with the above test example:

LivingThings.js

 #pragma strict
 
 class LivingThing extends $$anonymous$$onoBehaviour implements IAmAlive
 {
     var health : int;
     
     function GetCurrentHealth() : float
     {
         return health;
     }
     
     function Damage(amount : float) : float
     {
         health -= amount;
         return health;
     }
 
 }

ThingWithHealth.js

 #pragma strict
 
 class ThingWithHealth extends LivingThing
 {
     var iHaveSomeOtherVariables : String;
     
     function And$$anonymous$$ethods()
     {
     }
     
 }

OtherThingWithHealth.js

 class OtherThingWithHealth extends LivingThing
 {
     function Update() 
     {
           health += Time.deltaTime * 5;
     }
 }

YetAnotherThingWithHealth.js

 #pragma strict
 
 class YetAnotherThingWithHealth extends $$anonymous$$onoBehaviour implements IAmAlive
 {
     var health : float;
     
     function GetCurrentHealth() : float
     {
         return health;
     }
     
     function Damage(amount : float) : float
     {
         health -= health > 50 ? amount/2 : amount;
         return health;
     }
     
 }
avatar image whydoidoit · Oct 06, 2012 at 09:18 AM 0
Share

As you can see you can use both interfaces and inheritance to have objects provide their own implementations or just use a standard base class implementation.

avatar image Fattie · Oct 06, 2012 at 12:32 PM 0
Share

http://www.youtube.com/watch?v=IwZx6GjCIOU !!!

Show more comments

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

14 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Multiple Game Objects, different components 1 Answer

Flash raw animation data to Unity 0 Answers

Cant destroy object, dont know how to fix help pls 1 Answer

Unity editor bugging out 4 Answers

UNet bugs all over the place, fixed after re-building the Player prefab. 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges