Best way to attach a reference to an object in the scene to an instantiated object?

I’m new to Unity and was following a tutorial to make a FlappyBirds clone. It shows to make a pipe prefab and instantiate them from a PipeSpawner object in the scene. There is also an object to keep track of the score. The problem is connecting the instantiated pipes to the ScoreManager. It doesn’t let me drag the ScoreManagerScript to the pipe prefab in the editor. The video showed using FindGameObjectWithTag and GetComponet on start for the pipe.

This didn’t seem like a great way to do it since you had to keep finding the exact same reference for every pipe that was created. When I looked into it lots of people say to try to avoid using FindGameObject as it is expensive to run. So, what is a better way to add a reference to the ScoreManagerScript on all the pipe instances?

I thought of just adding the reference to the ScoreManagerScript inside the PipeSpawnerScript and then just attach it from there when a pipe is instantiated. That seems to work fine but I still have to use GetComponent on the pipe instance to get the script for it to add the reference to. Is that fine or is there a better way?

I haven’t looked into singletons much yet, would it be a good idea to just make the ScoreManager a singleton and be able to easily access it?

Here is the tutorial with the relevant timestamp

I did name some things a bit different from the tutorial like LogicManager → ScoreManager but it is mostly the same.

Any help is appreciated.

You’re definitely on the right track by having the spawning object provide the necessary references, otherwise known as dependencies.

When you reference a prefab, you can reference it via any component on its root game object. Instantiating it via the component will copy the whole game object of course, but return a reference to the component you instanced it from. That will save you from doing the GetComponent<T> call.

1 Like

I’m a little confused on what you mean. This is my PipeSpawnerScript that is attached to the pipe prefab

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PipeSpawnScript : MonoBehaviour
{
    [SerializeField] GameObject pipe;
    [SerializeField] float spawnRate;
    float timer = 0;
    float heightOffset = 9;
    [SerializeField] ScoreManagerScript scoreManagerRef;

    // Start is called before the first frame update
    void Start()
    {
        SpawnPipe();
    }

    // Update is called once per frame
    void Update()
    {
        if (timer < spawnRate)
        {
            timer += Time.deltaTime;
        }
        else
        {
            SpawnPipe();
            timer = 0;
        }

    }

    void SpawnPipe()
    {
        float lowestPoint = transform.position.y - heightOffset;
        float heighestPoint = transform.position.y + heightOffset;

        GameObject newPipe = Instantiate(pipe, new Vector3(transform.position.x, Random.Range(lowestPoint, heighestPoint), 0), transform.rotation);
        PipeScript pipeScript = newPipe.GetComponent<PipeScript>();
        pipeScript.scoreManager = scoreManagerRef;
        
    }
}

Are you saying I could change the

[SerializeField] GameObject pipe;

to instead hold the PipeScript and if I instance that it will still instance the whole pipe prefab but return the PipeScript? So I could just do

newPipe.scoreManager = ScoreManagerRef;

instead of

PipeScript pipeScript = newPipe.GetComponent<PipeScript>();
pipeScript.scoreManager = scoreManagerRef;

or am I misunderstanding?

Nope, you are understanding correctly!

Reference the prefab via the PipeScript component. Instantiate via that reference, which returns a reference to the newly instanced component (attached to the instanced game object).

If I keep

[SerializeField] GameObject pipe;

as is, I don’t see any way to attach the script in the inspector

Imgur

and if I change it to

[SerializeField] PipeScript pipe;

I get an error on the line instantiating the pipe saying

Cannot implicitly convert type ‘PipeScript’ to ‘UnityEngine.GameObject’

I’m not sure how to reference the pipe prefab via the PipeScript.

And this is what the pipe prefab looks like incase I have something setup wrong there

Imgur

If you have a field that references a component type, you will need to drag either the component itself, or a game object with a component on it into the field.

Yes, you will need to change the variable you declare on line 39 in your posted code to be typed to PipeScript rather than GameObject, as you’re returning a value typed to the former, not the latter anymore.

Or you can use the shorthand var:

var newPipe = Instantiate(pipeScriptPrefab // etc etc
1 Like

For some reason I thought I had to keep it as a GameObject to instantiate it, after changing it to PipeScript it works fine. Thanks for all the help!

1 Like