1
\$\begingroup\$

There are two main ways I am aware of to modify an attached component. Say, the component attached to an object is of type Animator and the name is animator.

So, in the script, I can write

private Animator animator;

and then call the function

animator = GetComponent<Animator>();

Or, I can define the variable as public

public Animator animator

and then, drag&drop in the Unity UI. Which one is the better practice?

\$\endgroup\$
2
\$\begingroup\$

There's a third option I sometimes like to use:

[RequireComponent(typeof(Animator))]
public class MyScript : MonoBehaviour {

    [SerializeField, HideInInspector]
    private Animator _animator;

    void OnValidate() {
        _animator = GetComponent<Animator>();
    }
}

Breaking this down...

  • RequireComponent ensures the object actually has the component I need, and Unity will add it at edit time if I forget it, or complain at me if I try to remove it.

  • Using both SerializeField and HideInInspector ensures we can save a value to the variable at edit time and have it save with the scene / carry through into game, without cluttering the Inspector with something we don't need to set manually.

  • OnValidate() gets called when we add or modify this component, only in the editor, so it can automatically wire up the reference for us without any search cost at runtime.

I wouldn't say this is "the best practice" — a public or serialized private variable is a lot more concise and does basically the same job, this just insulates you against forgetting to assign it. It's a little cheaper than finding the component on startup, but that cost isn't huge, so you can weigh whether the alternatives are worth the extra typing or hook-up. ;)

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I'm a little confused, how is using [SerializeField, HideInInspector] any different than just not having either (excluding custom editors more complex things like that)? If it's hidden how are you setting values to it in edit? \$\endgroup\$ – Jay Apr 20 at 11:13
  • 1
    \$\begingroup\$ @Jake with this method, you don't manually assign the reference in the Inspector. The OnValidate method does it for you in code. That's why we hide it from the inspector. But in order for that reference that was assigned in code at edit time to be saved in the scene/prefab and survive into the built game, it needs to be serialized. Unity's serializer skips over private fields by default, so we need to tell it to save this one as an exception to the rule. \$\endgroup\$ – DMGregory Apr 20 at 11:15
1
\$\begingroup\$

First of all when you type

public Animator animator

what you're talking about is a SerializedField. You can do the same with private variables by doing

[SerializeField] private Animator animator

But as for your question the second one is better because it is faster. Using one or two GetComponent<>() calls generally isn't too bad, but if you use many in a single frame it could be a problem.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.