unity-game-enginegameobjectunity-components

Why does Camera in unity not available in the next scene?


I have a start scene which has a start button. The start scene has a Camera adaptor gameobject. Camera adaptor gets main camera and performs some operations on every scene. When I click on start and the next scene is loaded, the camera adapter object is available in next scene but the camera is missing. here is my code and configuration:

Start scene hierarchy

Start scene inspector

Level1 hierarchy

level1 inspector

I have added the below code in my CameraAdapter script:

public class CameraAdaptor2D : MonoBehaviour

{

float displayWidth;
float displayHeight;


[SerializeField] Camera cam;


   void OnEnable()
{
    SceneManager.sceneLoaded += OnSceneLoaded;
}

void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
    cam = Camera.main;
}

// called when the game is terminated
void OnDisable()
{
    Debug.Log("OnDisable");
    SceneManager.sceneLoaded -= OnSceneLoaded;
}

private void Awake()
{
    DontDestroyOnLoad(this.gameObject);
}
// Start is called before the first frame update
void Start()
{
    cam = Camera.main;
    displayWidth = Screen.width;
    displayHeight = Screen.height;
positionCamera();}
   void PositionCamera()
    {
        Vector3 vector = new Vector3(0.0f,0.0f,0.0f);
        cam.transform.position = vector;
    }

What happens is when I click on the start button, unity loads the next level. But with the above code, I cannot get the camera of the current scene. Even when I added a breakpoint, the next scene is not pausing at the breakpoint. Is there something that I am missing to add in the code or is there another way to get the cam on every scene?


Solution

  • When using DontDestroyOnLoad all references that are scene specific are wiped when loading into a new scene. You will need to subscribe to sceneLoaded and assign the reference there.

    void OnEnable()
    {
        SceneManager.sceneLoaded += OnSceneLoaded;
    }
    
    void OnSceneLoaded(Scene scene, LoadSceneMode mode)
    {
          // assign the reference here 
    }
    
    void OnDisable()
    {
        // make sure to unsubscribe or you will get multiple calls after multiple scene loads 
        SceneManager.sceneLoaded -= OnSceneLoaded;
    }
    

    Another option is to put the object this script is on in every scene and assign the reference, then in Awake look for another instance of the script in the scene, then assign the older objects references to the current and destroy the current.

    void Awake()
    {
        CameraAdaptor2D obj =  Object.FindObjectOfType<CameraAdaptor2D>();
    
        if (obj != null)
        {
            // assign the other object here 
            obj.AssignCamera(cam);
            Destroy(this.gameObject);
            return;
        }
    
        DontDestroyOnLoad(this.gameObject);
    }
    
    public void AssignCamera(Camera c)
    {
        cam = c;
    }
    

    I should also mention, both answers use DontDestroyOnLoad. The first requires there exists one instance in the first scene you load and you will never load this scene again in the same session. The second requires there to be the same object in every scene so the reference can be set by the local instance of the object in that scene. Let me know if you want any more details as to how either implementation works.