0
\$\begingroup\$

I am currently working on a small 2D game which has a few different scenes, which are each a different level. I want to use my object prefabs from one scene in the others, but these do not include references to objects when I add the prefabs to my new scene.

Is it best to just manually add the references in the new scene to each object for every level, which is quite a long process, or is it better to change my script to use Find()?

What's a good practice when creating lots of levels with slight changes each time?

\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

Similar to an answer here, an intermediate option you can use is to put the "Find" logic in OnValidate, so it runs once at edit time to save you the manual step of populating the references, without any runtime overhead in-build.

Something like this:

public class GameManager : MonoBehaviour {

    // Save these references at edit time and allow editing in the inspector.
    [SerializeField] PlayerController _player;
    [SerializeField] Spawner _allySpawner;
    [SerializeField] Spawner _enemySpawner;

    // Run in-Editor only: when the prefab is placed in the scene,
    // on scene load, on enter/exit play mode, when any changes 
    // are made to this component instance in the Inspector,
    // or when reloading the script assembly after a code change.
    void OnValidate() {
        this.TryGetSceneReference(ref _player);
        this.TryGetSceneReference("Ally Spawner", ref _allySpawner);
        this.TryGetSceneReference("Enemy Spawner", ref _enemySpawner);
    }
}

Here I assume you probably want to wire up several of these dependencies, so I packaged the boilerplate into an extension method you can put in a separate file - so each call is just a one-liner:

public static class SceneDependencyHelper
{
    public static bool TryGetSceneReference<T>(this MonoBehaviour script, ref T reference) where T:Component {
        if (reference != null) return true;

        reference = Object.FindObjectOfType<T>();

        if (reference != null) return true;

        Debug.LogWarning($"{script.name} ({script.GetType().Name}) needs a reference to a {typeof(T).Name}, but none was found in the scene.");
        return false;
    }

    public static bool TryGetSceneReference<T>(this MonoBehaviour script, string name, ref T reference) where T : Component
    {
        if (reference != null) return true;

        var namedObject = GameObject.Find(name);
        if (namedObject != null) {
            if (namedObject.TryGetComponent(out reference)) return true;
        }

        Debug.LogWarning($"{script.name} ({script.GetType().Name}) needs a reference to a {typeof(T).Name} named {name}, but none was found in the scene.");
        return false;
    }
}

This handles doing no work if the reference has already been found, and logging useful warnings if the reference was not found.

\$\endgroup\$
1
  • \$\begingroup\$ Thank you so much! Very clear! \$\endgroup\$ Mar 19, 2023 at 16:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .