Search Unity

Question How to load a scene from another, with an elevator connecting the two on Unity3d ?

Discussion in 'Scripting' started by Log_Zero_Fox, Mar 14, 2023.

  1. Log_Zero_Fox

    Log_Zero_Fox

    Joined:
    Sep 21, 2022
    Posts:
    3
    Hello everyone, I'm having trouble with the loading system in Unity3D, especially with how to handle it when you want to go from one scene to another via a gameobject. What I mean by that is :
    - I have a GameObject, an Elevator;
    - The Elevator can go up or down, depending on what direction the elevator comes from. It can only go to another floor, which is always the same. So two elevators in two distinct scenes are corelated by ID;
    - The Elevator is in a State Machine, to better handle the multiple states it can assume;
    - The Elevator, when taken, triggers an animation (the doors closes, the elevator goes up or down), and when the animation ends, the script triggers a
    ElevatorLoadScene(int ElevatorID, string SceneName)
    method;

    I almost never worked with the SceneManager in Unity, so I don't know why my code is not good, but here it is :

    Code (CSharp):
    1. /// <summary>
    2.     /// Loads a scene when you use an elevator.
    3.     /// </summary>
    4.     /// <param name="SceneName">The scene's name.</param>
    5.     /// <param name="ElevatorID">The elevator's ID.</param>
    6.     public void ElevatorLoadScene(string SceneName, int ElevatorID)
    7.     {
    8.         Scene sceneType = SceneManager.GetSceneByName(SceneName);
    9.         SceneManager.LoadScene(SceneName);
    10.  
    11.         // Check every elevator in the list.
    12.         ElevatorList.Clear();
    13.  
    14.         if (sceneType.IsValid()) TMPobjects = sceneType.GetRootGameObjects();
    15.  
    16.         // For each GameObject with layer Elevator, add it to the list.
    17.         foreach (GameObject gameObject in TMPobjects)
    18.         {
    19.             if (gameObject.layer == 12)
    20.             {
    21.                 ElevatorList.Add(gameObject);
    22.             }
    23.         }
    24.  
    25.         // For each Elevator in ElevatorList, check if the ID is the right one.
    26.         foreach (GameObject ElevatorGM in ElevatorList)
    27.         {
    28.             ElevatorObject ElevatorGMC = ElevatorGM.GetComponent<ElevatorObject>();
    29.             if (ElevatorGMC.ElevatorID == ElevatorID)
    30.             {
    31.                 // Assigns the elevator's position.
    32.                 if (ElevatorGMC.IsGoingUp) ElevatorGMC.ElevatorRenderer.transform.position = ElevatorGMC.ElevatorUpPosition;
    33.                 else ElevatorGMC.ElevatorRenderer.transform.position = ElevatorGMC.ElevatorDownPosition;
    34.  
    35.                 // Assigns the player's position to the elevator's position.
    36.                 Vector3 elevatorPos = ElevatorGMC.ElevatorRenderer.transform.position;
    37.                 Quaternion elevatorRot = ElevatorGMC.ElevatorRenderer.transform.rotation;
    38.                 Player.PlayerInstance.transform.position = elevatorPos;
    39.                 Player.PlayerInstance.transform.rotation = elevatorRot;
    40.  
    41.                 // Launches the elevator's next state.
    42.                 ElevatorGMC.ElevatorRenderer.SetActive(true);
    43.                 ElevatorGMC.SwitchState(ElevatorObject.comingWithThePlayerState);
    44.                 break;
    45.             }
    46.         }
    47.     }
    The code runs fine until it reaches the
    if (sceneType.IsValid()) TMPobjects = sceneType.GetRootGameObjects();
    line, where it seems the scene is not valid. I simply want the player to be on the next scene ElevatorRenderer's position, when I launch this method. I tried to find solutions on the internet, but now I just can't seem to understand what I'm doing wrong. If someone is kind enough to take some time and explain what's the problem, or simply redirect me, I would gladly appreciate. Thank you !
     
    Last edited: Mar 15, 2023
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,914
    Code (CSharp):
    1. Scene sceneType = SceneManager.GetSceneByName(SceneName);
    This is only going to give you a valid scene if the scene represented by
    SceneName
    is already loaded.

    As per the docs https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager.GetSceneByName.html:
    So we know this won't work for a scene that is not loaded yet. Indeed the Scene struct is only meant to represent already loaded scenes.

    This:
    Code (CSharp):
    1. sceneType.GetRootGameObjects();
    Is of course even more egregious when the scene is not loaded yet.

    Long story short - you need to load the scene before you can start interacting with it.
     
    Log_Zero_Fox and Homicide like this.
  3. Log_Zero_Fox

    Log_Zero_Fox

    Joined:
    Sep 21, 2022
    Posts:
    3
    Okay I get it.
    I did not specify in this post since I did not thought about talking about it at all, but I tried with a coroutine, using a
    yield return new WaitForSeconds(1f);
    and/or a
    yield return null;
    as specified in some other forum post. But it did not work anyway. So do you have a quick solution or a ressource that could give a working example ?
     
  4. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,914
    I don't understand what this has to do with your issue. As I mentioned above you need to actually load the scene before you interact with it. Are you actually loading the scene somewhere? Because the code you shared doesn't load the scene at any point.
     
  5. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,445
    The best way to be able to reference scenes which have not yet been loaded is by their index number in the Build Settings dialog box. The reason for this is that ONLY scenes which are mentioned in this dialog box are included in your build by default. By default, if it's not in the list, it can't be loaded. So have your TOP-OF-ELEVATOR scene understand what index represents your BOTTOM-OF-ELEVATOR scene, use that index to load the desired scene, and vice versa.

    https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager.LoadScene.html
     
  6. Log_Zero_Fox

    Log_Zero_Fox

    Joined:
    Sep 21, 2022
    Posts:
    3
    Oh god damnit I edited the script I pasted on here because there was a line that was useless, and did not check if everything was here.
    In line 9 there is supposed to be a
    SceneManager.LoadScene(SceneName);
    line.
    I'm sorry, I should have read my post twice.

    I edited the script so you can see. It explains why I did not understand your first comment... Anyway, the thing is, the scene is supposed to be loaded right ?