0
\$\begingroup\$

I am accessing the variable of one script from within another and I noticed there are multiple ways to do this, but two that are very similar. The first is to simply find the game object and reference it within the other script like so:

void Start(){
    private int bye = 1;
    GameObject player = GameObject.Find("Meh");
    Test2 externalScript = player.GetComponent<Test2>();
    externalScript.hello *= bye;
    Debug.Log(externalScript.hello);
}

The other way is to create a global instance of the object the script is attached to and reference it within the inspector, like so:

private int bye = 1;
public GameObject player;
void Start(){
    Test2 externalScript = player.GetComponent<Test2>();
    externalScript.hello *= bye;
    Debug.Log(externalScript.hello);
}

Which way would be best in terms of performance and practice? Would one way be better than the other when it comes to larger games and/or scripts?

\$\endgroup\$
  • 1
    \$\begingroup\$ One takes more initialization time and can be hard to point to a specific object of the same prefab/tag, while the latter has everything set up and you can point to a specific object of the Scene. \$\endgroup\$ – DH. Apr 24 '16 at 14:35
  • \$\begingroup\$ @DH You should write this as an answer and provide a few more details. \$\endgroup\$ – Robert Apr 24 '16 at 15:09
3
\$\begingroup\$

You can actually do one better. If it's the Test2 component you care about, then make that the type of the inspector variable you expose:

private int bye = 1;
public Test2 playerTestScript;
void Start(){
    playerTestScript.hello *= bye;
    Debug.Log(playerTestScript.hello);
}

This way you have absolutely no searching to do at runtime. Everything is wired-up in the inspector, and the type information lets the editor enforce valid references.

(In the example in the question, if the player GameObject existed but did not have a Test2 component attached, the editor would still let you assign the reference but you'd get a NullReferenceException at runtime when you try to access the Test2 instance that isn't there. Also, since the type is shown in the field, this advertises to someone unfamiliar with the script exactly what kinds of inputs it needs, making wiring it up less error-prone.)

Overall, I would strongly recommend against looking up GameObjects by name whenever it can be avoided. It's brittle if you ever want to re-use the script in a different context, or want to have two instances referencing different objects, and generally makes it very easy to accidentally introduce bugs when renaming, or changing from objects loaded with the scene to those spawned at runtime (which have their name altered when Instantiate()d), or dealing with Destroy()ed objects (which still get found by name until the next frame).

Wiring up a reference in the inspector is a bit of work, but no more work than naming an object a very specific string, and unlike the named approach what you need to do is advertised in the inspector fields, rather than hiding in the code.

Lastly, if the component you need to reference will be living on the same object, there's another pattern I like to use:

[RequireComponent(typeof(PrerequisiteComponent))]
public class DependentComponent : MonoBehaviour
{
    PrerequisiteComponent _prerequisite;

    void Awake()
    {
         _prerequisite = GetComponent<PrerequisiteComponent>();
    }
}

(This is great to use with Renderers, Colliders, Rigidbodies, etc. for scripts that need them)

This is the one case where I prefer a script to wire-up itself: when it can unambiguously identify the component it needs (because it's on the same object) and the [RequireComponent()] attribute lets the editor enforce this prerequisite for us, so the level designer doesn't have to remember it.

\$\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.