Search Unity

public variable vs GetComponent()

Discussion in 'Scripting' started by VitorPM, Jan 13, 2014.

  1. VitorPM

    VitorPM

    Joined:
    Jan 13, 2014
    Posts:
    4
    You created a script that needs another one's variables, then:

    What you guys think is best to use?

    public variable and drag them from the inspector or GetComponent<script>() on Start() ?

    Is there any performance difference?


    Thanks
     
  2. MDragon

    MDragon

    Joined:
    Dec 26, 2013
    Posts:
    329
    This is, for me at least, like this:

    - Use drag for something "simple", already in the scene, and doesn't need too many pieces attached. Also, it's not used in every single scene, where you have to reattach every single part again and again

    - Use GetComponent for something that is necessary/central, you always know its location (like on a permanent empty GameObject called "Control Center" or something), and the biggest reason why I'd use this is if it's used a lot (in terms of different objects). Also, if it's instantiated mid-game, I'd use this.

    Also, for something like the Main Camera being attached to the player, vice versa, or something similar, I tend to use both as a "just in case". So, if(!player) GetComponent or FindObject or such. :)
     
  3. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    A reference is a reference; once you have the reference it doesn't matter how you got it.

    --Eric
     
  4. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    Yep. So which one is better depends on how you want to work with the data in the Editor, rather than on what your code does with it at runtime.

    Do you want to set it up in the Inspector, or do you want the component to find the reference automatically so you don't have to?

    The former is good when you want to use the same component with different values. A good example of that would be a "Look At" script. There's no real way to know what it's meant to be looking at just from the object you've stuck it on, and you'll probably want to be able to look at different things, so there are two really good reasons to set the value up manually each time you use the component.

    The latter is good if there's clear logical rules about what the reference should point to and you'll never want it to point to other things. For instance, if you're making a component that relies on having another component already present. It's a waste of time to make people set that up in the Inspector, and that would make it more error prone, and it's something that you easily and reliably have the script figure out for itself. So that's three really good reasons to use the latter approach.
     
  5. BillyMFT

    BillyMFT

    Joined:
    Mar 14, 2013
    Posts:
    178
    what about in terms of runtime performance? I assume having a variable set in the inspector is slightly faster than using GetComponent() in the Start function?
     
    dunloip likes this.
  6. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    It's drastically faster to use direct reference.
    Under the hood, GetComponent<T> uses lookup table to find if specific type of component is present on the gameObject.

    TL;DR, From fastest to slowest:
    Direct Ref < GetComponent<T> < GetComponentInChildren<T> < GetComponentInParent<T> < Find
     
    scarface117 likes this.
  7. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    It's totally irrelevant in Start. You're just doing it once, so it doesn't matter if it takes .001ms or .005ms.

    --Eric
     
    kaancetinkayasf and GeorgeCH like this.
  8. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,445
    Unless you're Start'ing 1000 objects in one or two frames, like chunks loading in a streaming world.
     
    valeriopavan, JackS1001 and alexr1221 like this.
  9. GeorgeCH

    GeorgeCH

    Joined:
    Oct 5, 2016
    Posts:
    222
    A lot of it is down to personal preference. I also don't like relying on the Inspector's drag-and-drop as it's prone to breaking whenever you rearrange your scene's hierarchy. The last thing I want to do is to re-drag and re-drop things in multiple scripts whenever I change something.

    My personal attitude is to have each class resolve its own dependencies as much as possible, which means I tend to avoid exposing variables unless I absolutely have to and rely on GetComponent/FindObjectOfType (for singletons only) as much as I can. As @Eric5h5 mentioned, the performance cost of using GetComponent is irrelevant as long as it is done only once.

    GetComponent() calls get a bad rep, but using them every now and again even outside the scope of the Start/Awake function is perfectly fine if so warranted. I develop for mobile, too, so performance is something I think about all the time.
     
    Sluggy likes this.
  10. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Hopefully you're not actually loading 1000 objects in one frame, since the overhead of doing so will dwarf any differences regarding direct reference vs GetComponent. The point is to not get hung up on micro-optimizations when you should be looking at the bigger picture.

    Drag and drop won't break by rearranging the scene hierarchy though. Indeed that's one reason to use it, because you can move stuff around rather than relying on a hard-coded path (which will break).

    --Eric
     
    Bunny83 likes this.
  11. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    On the other hand, drag-and-drop references will break if you need to delete the targeted object/component and re-create it.

    For instance, if you replace an existing component with a new subclass, a GetComponent() will still find it, but any existing references you've set up in the scene will be broken.

    Or if you're in the unfortunate position of needing 2 people to work on different parts of the same scene at the same time, you might end up trying to copy/paste the modified elements from one person's edited copy into the other...
     
  12. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    It is relevant. All the service location should be shifted to the OnValidate instead.

    Reducing number of these calls in Awake / Start does produce decent speed boost for scene loading time on mobile devices. As a bonus - better code structure.
     
    StudioGenesis, srgskiri and dunloip like this.
  13. whileBreak

    whileBreak

    Joined:
    Aug 28, 2014
    Posts:
    289
    If you are working with other people is easier to understand a drag and drop on the inspector. Having to open the code and see from where and how a reference is assigned is not the best.
     
  14. kru

    kru

    Joined:
    Jan 19, 2013
    Posts:
    452
    Furthermore, using GetComponent enforces a structure to the scene. It binds the hands of the scene builders. For example, if a dev decides that mesh objects should be moved to a child of a logic object, then any code with GetComponent<MeshFilter> in start or awake will break, and require a code change.

    An ideal middle ground is to add some scene validation code to components using ContextMenu and the Reset() or OnValidate() methods.
     
  15. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    I think that depends on context. If you're primarily making edits to the scene, then stuff in the scene is "easy" to see, and stuff in the code takes work to see. But if you're primarily making edits to the code, then stuff in the code is "easy" to see...