Search Unity

Connecting different scripts variables together?

Discussion in 'Scripting' started by Quist, Jul 29, 2014.

  1. Quist

    Quist

    Joined:
    Feb 25, 2014
    Posts:
    284
    So i have 2 scripts.

    Health script with the vars:
    public var MaxHealth : float = 100;
    public var Health : float;

    And a script called "Food".
    var food : int = 10;

    So what i need is:
    To be able to change the MaxHealth & Health variables from a code in the "Food" script.

    Etc.

    Code (JavaScript):
    1. function eatBurger ()
    2. {
    3.     Health = Health + food;
    4. }
    so when the function is called the health will go from 100 to 110..
    But right now it says Unknown identifier: 'Health'.



     
  2. Deequation

    Deequation

    Joined:
    Jan 2, 2014
    Posts:
    16


    This is a question of scope and reference. What the error message is telling you is, that in the scope that you are currently operating in, there is no variable called Health. This makes pretty good sense, if you consider the case where both scripts had a variable with the same name. How would your code know what one to pick, if they were both available directly to you. So what you need to do is establish a reference to the other script, so you can point to it and say 'the variable health I want to change is on that gameobject, in that script'. When you don't use a reference, the code assumes that the variable you are looking for is in the script you are currently in, and that is obviously not the case here.



    [01] Getting a reference to the gameobject:


    The easiest and fastest way to do this is to create a public transform or gameobject variable, and then manually drag the gameobject that holds the other script onto the field in the inspector. You can also do this with the following code. But a very important thing to note is, this is only required if your two scripts are on different gameobjects, since before we can point to the script, we need to point to the gameobject it is on. In the case where both scripts are on the same gameobject, you can skip this step somewhat. The second code example here, is when you want to do this from within the script, if you don't want to drag the gameobject, or for various reasons can't do it before you start the game.

    Code (JavaScript):
    1. [Food.js]
    2.  
    3. // Assign the reference manually before running!
    4. public var reference : Transform;
    Code (JavaScript):
    1. [Food.js]
    2.  
    3. // Find the reference automatically at runtime!
    4. private var reference : Transform;
    5.  
    6. function Awake ()
    7. {
    8.     reference = GameObject.Find("NameOfGameObject").transform;
    9. }


    [02] Getting a reference to the script:


    Now that we know what gameobject (transform) to point to, we can then find the script on it, and establish a reference directly to it, so we can change it in any way we like, as it were our own. This is done by looking up the script, remember that a script is a component. So by using the 'GetComponent' we can find a reference to the script. Note that before you call GetComponent you should tell it on what gameobject or transform it should look for it. So we will use the 'reference' variable we established above, or simply 'transform' if they are on same script. Finally, there's something very notable that I am skipping, since that is not the question, but in the future you should look into storing the reference to the script, so you don't have to get the component each time you need it. In this example I will just call it when you want to change the variable, but for performance, look into caching it!

    Code (JavaScript):
    1. [Food.js]
    2.  
    3. ..
    4. function PickUpFruit ()
    5. {
    6.     reference.GetComponent("HealthScript").MaxHealth += 10.0;
    7.     reference.GetComponent("HealthScript").Health    += 10.0;
    8. }


     
    Last edited: Jul 22, 2015
    Thoaril likes this.
  3. Ian094

    Ian094

    Joined:
    Jun 20, 2013
    Posts:
    1,548
    You'll need to use GetComponent.

    Something like this should work :
    Code (JavaScript):
    1. gameObject.GetComponent(Health).Health += food;
     
  4. Quist

    Quist

    Joined:
    Feb 25, 2014
    Posts:
    284
    I added the
    i added the var: public var reference : Transform;
    and took the "Burger" object with the food script and dragged it to the "players" Transform, but i stil lget "unknown Health yada yada stuff"...
     
  5. Quist

    Quist

    Joined:
    Feb 25, 2014
    Posts:
    284
    when i do it, it tells me an error:
    NullReferenceException: Object reference not set to an instance of an object
    Food.Update () (at Assets/Food.js:10)

    My code looks like this:

    Code (JavaScript):
    1. #pragma strict
    2.  
    3. private var drawGUI = false;
    4. var Burger : int = 10;
    5.  
    6. function Update ()
    7. {
    8.     if (drawGUI == true && Input.GetKeyDown(KeyCode.E))
    9.     {
    10.     gameObject.GetComponent(PlayerHealthV2).Health += Burger;
    11.     }
    12. }
    13.  
    14. function OnTriggerEnter (theCollider : Collider)
    15. {
    16.     if (theCollider.tag == "Player")
    17.     {
    18.         drawGUI = true;
    19.     }
    20. }
    21.  
    22. function OnTriggerExit (theCollider : Collider)
    23. {
    24.     if (theCollider.tag == "Player")
    25.     {
    26.         drawGUI = false;
    27.     }
    28. }
    29.  
    30. function OnGUI ()
    31. {
    32.     if (drawGUI == true)
    33.     {
    34.         GUI.Box (Rect (Screen.width*0.5-51, 200, 102, 22), "Press E to eat");
    35.     }
    36. }
     
  6. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    don't use direct access to another script's attributes. You'll just walk into the "how do i stop the health value going over the maximum" question next...

    add a function to Health which takes a value as a parameter. It can then handle "what happens when anything tries to add some health", clamp to 0/max/whatever, play sounds, trigger effects etc.

    food then just needs a reference (i.e. Health myHealth = ...) to the specific health script attached to the same gameobject (as above) and call

    Code (csharp):
    1.  
    2. myHealth.AddHealth(food);
    3.  
     
    Last edited: Jul 29, 2014
  7. Quist

    Quist

    Joined:
    Feb 25, 2014
    Posts:
    284
    the food is seperate to the player, so the 2 scripts aint on the same object.
    What do i do exactly to make it work?
     
  8. Quist

    Quist

    Joined:
    Feb 25, 2014
    Posts:
    284
    He says what i have to do and thats great, but when i ask and someone says i should make a parameter and stuff, i prefer to get told what to do in scripting.

    I´m pretty new to this and i dont know what all in coding is yet, so when he says that i should do that, again, i would like to have an example of how you do it in coding
     
  9. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    the error you posted is because you didn't follow both steps in dee's post. You just did the second one.


    my post was regarding the "health += food" vs "Health.AddHealth(food)"... once you've got a reference to the "health" you want to improve from what Dee has posted.
     
  10. Ian094

    Ian094

    Joined:
    Jun 20, 2013
    Posts:
    1,548
    Make sure your "Health" script is attached to the same gameObject as the "Food" script.
     
  11. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    I'm usually more of a "teach to fish" guy, but I've just put two and two together and realised you were the forum member having trouble with the health/hunger script linkage a few days back... so I threw the below together as an example. Bare in mind I'm usually a c# scripter and I've not got a compiler handy to check for errors so typos are likely.

    Things to note:
    no script directly modifies another scripts variables (they're all public so they show up in the inspector, you might want to make some private etc. when you understand more).

    each script does "it's own thing" without worrying about what another script is doing (in reference to the previous threads).

    functionality is put into functions, so they can be reused (i.e. Apply####Damage functions are the only place where the values are reduced and it is there which the value is clamped)

    Hunger, Health and Player go on a player object (you'll need to add some sort of movement management either in Player or in another script attached to the same game object). Food goes on the food (obviously?).

    Food doesn't have "eat" function, food doesn't eat, it is eaten. The player Eats, so it makes more sense for a script to do with the player to handle that, when you Eat you eat Food, so Eat takes a Food object parameter. (note: sentence being turned into Objects and Functions here.)

    I'd suggest you look into "Object Orientated Design Principles" (i.e. google it) and try to understand how Objects, Functions and Attributes should be arranged.


    Code (csharp):
    1.  
    2.  
    3. //---------- Food ----------\\
    4. public var hungerValue : float = 10; // different values for health and hunger
    5. public var healthValue : float = 2;
    6.  
    7. function Eaten()
    8. {
    9.     //handle other stuff before being destroyed
    10.     Destroy(gameObject);
    11. }
    12.  
    13. //---------- Hunger ----------\\
    14. public var myHealth : Health;
    15.  
    16. public var currentHunger : float;
    17. public var maximumHunger : float = 100;
    18.  
    19. public var intervalDuration : float = 5;
    20. public var intervalStart : float = 0;
    21.  
    22. public var hungerDamage : float = 1;
    23. public var healthDamage : float = 5;
    24.  
    25. function Start()
    26. {
    27.     myHealth = gameObject.GetComponent(Health);
    28.     if(!myHealth)
    29.     {
    30.         Debug.Log("Health script missing on " + gameObject.name);
    31.     }
    32.     currentHunger = maximumHunger;
    33. }
    34.  
    35. function Update()
    36. {
    37.     if(Time.time >= intervalStart + intervalDuration) // check hunger
    38.     {
    39.         intervalStart = Time.time; // reset for next interval
    40.         ApplyHungerDamage(hungerDamage);
    41.         if(IsHungry()) // we're hungry take damage
    42.         {
    43.             myHealth.ApplyHealthDamage(healthDamage);
    44.         }
    45.     }
    46. }
    47.  
    48. function ApplyHungerDamage(d: float);
    49. {
    50.     currentHunger -= d; // apply the damage
    51.     currentHunger = Mathf.Clamp(currentHunger, 0, maximumHunger); // make sure we don't go negative or over maximum
    52. }
    53.  
    54. function IsHungry() : bool
    55. {
    56.     return currentHunger <= 0;
    57. }
    58.  
    59. function Eat(Food foodItem)
    60. {
    61.     myHealth.ApplyHealthDamage(-foodItem.healthValue);
    62.     ApplyHungerDamage(-foodItem.hungerValue);
    63.     foodItem.Eaten();
    64. }
    65.  
    66.  
    67. //---------- Health ----------\\
    68.  
    69. public var currentHealth : float;
    70. public var maximumHealth : float = 100;
    71.  
    72. function Start()
    73. {
    74.     currentHealth = maximumHealth;
    75. }
    76.  
    77. function ApplyHealthDamage(d : float)
    78. {
    79.     currentHealth += d;
    80.     currentHealth = Mathf.Clamp(currentHealth, 0, maximumHealth);
    81. }
    82.  
    83.  
    84. //---------- Player ----------\\
    85. public var myHealth : Health;
    86. public var myHunger : Hunger;
    87.  
    88. function Start()
    89. {
    90.     myHealth = gameObject.GetComponent(Health);
    91.     myHunger = gameObject.GetComponent(Hunger);
    92.     if(!myHealth)
    93.     {
    94.         Debug.Log("Health script missing on " + gameObject.name);
    95.     }
    96.     if(!myHunger)
    97.     {
    98.         Debug.Log("Hunger script missing on " + gameObject.name);
    99.     }
    100. }
    101.  
    102. function OnTriggerEnter(other : Collider) // assuming "walk into food => eat food"
    103. {
    104.     oFood = other.GetComponent(Food); // try to get the food component
    105.     if(oFood) // if we find one we can use it
    106.     {
    107.         myHunger.Eat(oFood);
    108.     }
    109. }
    110.  
    111.  
     
    Last edited: Jul 29, 2014