Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

How to use GetComponent

Discussion in 'Getting Started' started by basementApe, Oct 16, 2015.

  1. basementApe

    basementApe

    Joined:
    Oct 2, 2013
    Posts:
    19
    I'm trying to access a variable from another gameobject, in this case the parent, without much success. The script looks like this:
    Code (csharp):
    1.  
    2. #pragma strict
    3.  
    4. private var et_player: ET_Player = GetComponent(ET_Player);     // FAILS
    5. private var Anim_Idle : AnimationState;
    6. private var Anim_Walk : AnimationState;
    7. private var Action : int = 1;
    8. private var Frame : float = 0f;
    9.  
    10. function Start ()
    11. {
    12.     // Nicked from someone who knows what they're doing...
    13.     Anim_Idle = GetComponent.<Animation>()["P2_Idle3_Baked"];
    14.     Anim_Walk = GetComponent.<Animation>()["P2_Walk3"];
    15.     // Clam[Forever is necessary to keep the last frame of the animation accessible from script,
    16.     // looping is done manually in script anyway.
    17.     Anim_Idle.wrapMode = WrapMode.ClampForever;
    18.     Anim_Walk.wrapMode = WrapMode.ClampForever;
    19.  
    20. }
    21.  
    22. function Awake()
    23. {
    24. }
    25.  
    26. function Update ()
    27. {
    28.      // FAILS
    29.     if (et_player.Action == 1)
    30.     {
    31.     }
    32.     if (Frame < 12)
    33.     {
    34.         Frame = Frame + (1*Time.deltaTime);
    35.     }
    36.     else
    37.     {
    38.         Frame = Frame - 12;
    39.     }
    40.  
    41. }
    42.  
    Ideally I'd like to have a way to access global variables from anywhere, that is abstracted in a way that I don't need to do GetComponent all the time. Is that even possible? OOP... it's killing my poor brain :p
     
  2. Adam-Buckner

    Adam-Buckner

    Joined:
    Jun 27, 2007
    Posts:
    5,664
    I think the first thing to understand is the difference between a GameObject and a Component.
    http://unity3d.com/learn/tutorials/...or/game-objects-and-components?playlist=17090

    The GameObject is the THING that holds all of the Components. The Components are the little detailed containers that defines what the GameObject does. The Transform is a Component. On a light, the Light is a Component.

    In your code: private var et_player: ET_Player = GetComponent(ET_Player); ET_Player is a Script that defines a Type and creates a Component on a GameObject.

    Get Component finds a component by Type on the same GameObject as the GameObject referenced.

    When you say LoremIpsum myLorem = GetComponent <LoremIpsum>(); you are expecting to find it on THIS GameObject, as there is no additional GameObject reference. This is great if you have, say, a PlayerController script that needs to access the Rigidbody or AudioComponent on that same Player GameObject with Rigidbody rb = GetComponent <Rigidbody>(); and then rb.AddForce(someValue);.

    Now, if you need a component on ANOTHER GameObject, then you need a reference to that GameObject first.

    HOWEVER - you may just want a reference to the COMPONENT itself.

    One way of doing this is by associating your other GameObject and its Component with a variable that can be seen in the Inspector.

    public LoremIpsum myLorem; works.

    If you want to have the variable private but need to access it in the Inspector, then try:
    [SerializeField]
    private LoremIpsum myLorem;

    Then you can drag the GameObject you want to reference into the slot.

    Unity is smart and will find the correct Component on the GameObject to match the Type (in this case our made up LoremIpsum type) of the Component with the Field reference Type.

    If you must find the component at runtime, then you must find the GameObject first. You can do a GameObject.Find, but I would suggest trying to use GameObject.FindByTag() or one of the other finds.

    Once you have found the GameObject that has the Component you want, you can then use
    theGameObjectIFound.GetComponent<LoremIpsum>(); to get the Component from that GameObject.

    You can also see this in Trigger events, like "OnTriggerEnter". This will give you a reference to the other Collider you hit. With the reference to the collider, you can get a reference to the GameObject. With the reference to the GameObject, you can get the Component:

    Code (csharp):
    1.  
    2. void OnTriggerEnter(Collider other) {
    3.      LoremIpsum myLorem = other.gameObject.GetComponent<LoremIpsum>();
    4.      myLorem.SomeFunction(someValue);
    5. }
    Does this make sense?
     
  3. Adam-Buckner

    Adam-Buckner

    Joined:
    Jun 27, 2007
    Posts:
    5,664
    May I ask why you are approaching animation like this?

    Have you considered doing this in Mecanim?

    Or am I missing something?
     
  4. basementApe

    basementApe

    Joined:
    Oct 2, 2013
    Posts:
    19
    Thanks for the detailed reply, I really appreciate it :) I'll go through it properly and post again a bit later.

    About animation, just trying to keep it simple and sticking to an approach I'm already familiar with. I've done quite a bit of (very) high-level programming, all procedural with an exposed main game loop that I've stuck functions in. I had a look at the Mecanim way but it seemed convoluted compared to Legacy. Also, I need control on a frame to frame level, both to simulate a stop-motion look and to trigger new events at specific points in a clip. It just seemed like the sensible way to go about it for me with my rudimentary programming skills :)
     
  5. Adam-Buckner

    Adam-Buckner

    Joined:
    Jun 27, 2007
    Posts:
    5,664
  6. basementApe

    basementApe

    Joined:
    Oct 2, 2013
    Posts:
    19
    Oh no. I think maybe my brain is too small to handle Unity scripting.

    So if I understand it right in your example myLorem represents the current script which is a component of the gameobject it's attached to. public LoremIpsum myLorem; means you make the variable LoremIpsum within the script public and available to the Inspector. So far so good? But if I try the same declaration:

    public var P_Action ET_Player; // ET_Player = this script

    I get informed that a semicolon is expected. Is this because LoremIpsum in your example isn't a variable at all and I misunderstood? This works though:

    public var P_Action : ET_Player;

    But later on in the other script, the one attached to the child object, the code still bombs out:

    Code (csharp):
    1.  
    2. #pragma strict
    3.  
    4. private    var P2_player;
    5.  
    6. private var Anim_Idle : AnimationState;
    7. private var Anim_Walk : AnimationState;
    8. private var p_action : int;
    9. private var Frame : float = 0f;
    10.  
    11. function Start ()
    12. {
    13.     P2_player = GameObject.Find("Object_P2");        // Object_P2 is the parent of this GameObject. This GameObject is
    14.                                                     // the animated mesh, which is why (presumably) GetComponent.<Animation> works.
    15.     p_action = P2_player.GetComponent<et_player>();    // This line goes boom: "Unexpected token". Whatever that means...
    16. // p_action = P2_player.GetComponent<P_Action>();    // same thing with this...
    17.  
    18.     Anim_Idle = GetComponent.<Animation>()["P2_Idle3_Baked"];
    19.     Anim_Walk = GetComponent.<Animation>()["P2_Walk3"];
    20.     // ClampForever is necessary to keep the last frame of the animation accessible from script,
    21.     // looping is done manually in script anyway.
    22.     Anim_Idle.wrapMode = WrapMode.ClampForever;
    23.     Anim_Walk.wrapMode = WrapMode.ClampForever;
    24.    
    25. }
    26.  
    27. function Awake()
    28. {
    29. etc...
    30.  
    Thanks for the links btw! I'll probably revisit Mecanim in the future once I get a better grip on the basics.
     
  7. Schneider21

    Schneider21

    Joined:
    Feb 6, 2014
    Posts:
    3,510
    Not exactly. Adam's code was C#, where as you're writing in UnityScript. Their syntax is slightly different.

    In C#, you declare a variable by setting its access operator, the type, the variable name, and optionally assigning a value. If this variable is of a custom type (like your own class), you'd have to assign a valid instance of that class (using the 'new' keyword and an appropriate constructor).
    Code (CSharp):
    1. public ClassName myVariable = new ClassName();
    It's a little different in UnityScript, where you declare the access level, the variable name, a colon, and then the type.
    Code (JavaScript):
    1. public var myVariable: ClassName = new ClassName();
    So with the code you wrote, you have an extra word in there, as if you're combining C# and UnityScript.

    The reason the code bombs out later is for a totally different reason.
    Code (CSharp):
    1. p_action = P2_player.GetComponent<et_player>();
    The part inside the < > for GetComponent is a type. So that means a class name or one of Unity's component types. It looks like you're trying to pass it a variable of some sort, though I don't see where you have et_player defined. "Unexpected Token" is a good hint that your code is just written wrong syntactically.

    It's also worth nothing that GetComponent is written differently in C# and UnityScript. Check out the reference to see how they differ. In general, it's important to understand the constructs of the language you're working with, and ensure you're using the right one for the language you're using when copying code from tutorials.
     
    basementApe likes this.
  8. Adam-Buckner

    Adam-Buckner

    Joined:
    Jun 27, 2007
    Posts:
    5,664
    WHOOPS!

    Sorry, yes, I was writing in C-Sharp. I'm so used to reading both, I didn't notice it was Unity's JavaScript. And I'm used to writing in C-Sharp, so didn't convert my code to your language.
     
    basementApe likes this.
  9. kdubnz

    kdubnz

    Joined:
    Apr 19, 2014
    Posts:
    177
    I really enjoyed this generic sample ... very clever.
     
  10. basementApe

    basementApe

    Joined:
    Oct 2, 2013
    Posts:
    19
    et_player is a pointer to the script attached to the other gameobject, so should be a component of that object. Just put that in for testing, what I really wanted to get access to was the P_Action variable declared within that script. I'm still struggling to wrap my head around the difference between types, components and class variables tbh. For instance; aren't variables declared within a class supposed to become a component of that class?

    Thanks for the help fellas, I'll try more later and see if I can figure it out :)
     
  11. Schneider21

    Schneider21

    Joined:
    Feb 6, 2014
    Posts:
    3,510
    Even still, the content between the angled brackets should be a type, not an instance of an object, component or otherwise.

    Type - A reference to a class. This is a general programming, and in turn, a C#/UnityScript construct.
    Component - A type of class that inherits from MonoBehavior. These are Unity terminology. The neato thing about components is they can be attached to GameObjects and provide built in methods (from MonoBehavior) that allow you to tap into your game's update methods, access sibling components, etc.
    Class variables - A variable defined within a class. So if I have a class Car, and within that, a variable called maximumSpeed, maximumSpeed is a class variable of Car.

    Class variables are not components of that class. A component is only created when you attach a script that inherits from MonoBehavior (either one you write or a built-in Unity class like Rigidbody) to a GameObject.

    Everyone seems to want to skip past them to get to the fun stuff, but if you haven't gone through all of them, it's worth following along with each and every one of Unity's scripting tutorials. Hell, even if you have gone through them, go through them again! It answers a lot of this kind of stuff.

    And if it's not clicking, don't feel bad. It took me a year of school until these concepts really started to sink in.
     
    basementApe likes this.
  12. Adam-Buckner

    Adam-Buckner

    Joined:
    Jun 27, 2007
    Posts:
    5,664
    FWIW: I'd definitely suggest going through the basics learn videos as well, and also run through roll-a-ball and space shooter which will give you the basics.
     
  13. Adam-Buckner

    Adam-Buckner

    Joined:
    Jun 27, 2007
    Posts:
    5,664
    Here's my original reply translated (and in a few cases - updated) to UnityScript:

    -

    I think the first thing to understand is the difference between a GameObject and a Component.
    http://unity3d.com/learn/tutorials/modules/beginner/editor/game-objects-and-components?playlist=17090

    The GameObject is the THING that holds all of the Components. The Components are the little detailed containers that defines what the GameObject does. Components are created when you add a script to a GameObject. The Transform is a Component. On a light, the Light is a Component. If you write a custom class, say PlayerController.cs; when you add this script to a game object, it creates a Component on the GameObject.

    In your code: private var et_player: ET_Player = GetComponent(ET_Player); ET_Player is a Script that defines a Type and creates a Component on a GameObject when it's attached.

    Get Component finds a component by Type (which is the name of the class and name of the script) on the GameObject that is referenced in the GetComponent call. If no GameObject is specified, the call assumes you mean on the GameObject that the script/component is attached to.

    When you say:
    var myLorem : LoremIpsum = GetComponent.<LoremIpsum>();

    ... you are expecting to find an instance of LoremIpsum on THIS GameObject, as there is no additional GameObject reference.

    This is great if you have, say, a PlayerController script that needs to access the Rigidbody or AudioComponent on that same Player GameObject. Simply use:
    var rb : Rigidbody = GetComponent.<Rigidbody>();

    ... and then later in your code, use:
    rb.AddForce(someValue);.

    Now, if you need a component on ANOTHER GameObject, then you need a reference to that GameObject first.

    HOWEVER - you may just want a reference to the COMPONENT itself.

    One way of doing this is by associating your other GameObject and its Component with a variable that can be seen in the Inspector.

    public var myLorem : LoremIpsum; works.

    If you want to have the variable private but need to access it in the Inspector, then try:
    [SerializeField]
    private var myLorem : LoremIpsum;

    Then you can drag the GameObject you want to reference into the slot.

    Unity is smart and will find the correct Component on the GameObject to match the Type (in this case our made up LoremIpsum type) of the Component with the Field reference Type.

    If you must find the component at runtime, then you must find the GameObject first. You can do a GameObject.Find, but I would suggest trying to use GameObject.FindByTag() or one of the other finds. To find more information on the GameObject find calls, please check the documentation and be aware that they are slow, so you should cache the reference in Start.

    Once you have found the GameObject that has the Component you want, you can then use
    theGameObjectFound.GetComponent.<LoremIpsum>(); to get the Component from that GameObject.

    You can see this in Trigger events, like "OnTriggerEnter". The trigger event callback will give you a reference to the other Collider you hit. With the reference to the collider, you can get a reference to the GameObject. With the reference to the GameObject, you can get the Component:

    Code (csharp):
    1. function OnTriggerEnter(other : Collider) {
    2.      LoremIpsum myLorem = other.gameObject.GetComponent<LoremIpsum>();
    3.      myLorem.SomeFunction(someValue);
    4. }
    Does this make sense?
     
    basementApe likes this.
  14. basementApe

    basementApe

    Joined:
    Oct 2, 2013
    Posts:
    19
    Hehe hm. Yep I'm guilty of that. I have some understanding of programming concepts and even enjoy the problem-solving aspect to an extent, but programming isn't the thing I excel at. Still, I thought it would be enough to carry me through some quick prototyping at least. OOP seems to require a different way of thinking than the procedural approach I'm used to tho.

    But I'm learning! Good stuff. Part of the problem was also that I didn't really know what end to begin in or even how to ask about what I don't understand because I don't have the terminology or concepts down. So thanks again for taking the time to clear some of these things up, it's been really helpful :)
     
    Schneider21 likes this.