Dynamically set a spawn point

In my game, I have “gateways” which essentially send the player to the next scene, onTriggerEnter.

Due to player movement/interaction, I need to turn off NavMeshAgent when loading a scene, otherwise the player gets stuck on an object. There’s also a wait in order for things to “finish” - it may be redundant now.

Also, not sure on this, but I read somewhere that DoNotDestroyOnLoad isn’t the correct way to do this anymore.

That by the by, what I need is a way to grab the Transform Position of the loaded Gateway and position the player near it when the new level loads.

There are two levels: Campsite and Forest, and each has a Gateway to one another. In Campsite, there is a Gateway called Forest (which loads the Forest scene), and in Forest a Gateway called Campsite (which loads the Campsite scene).

The only way I can position the player is by manually entering in Vector3 co-ords.

This is the full Gateway.cs file, which sits on every Gateway.

public class Gateway : MonoBehaviour {
  void OnTriggerEnter(Collider other) {
    var currentScene = SceneManager.GetActiveScene().name;
    var nextScene = this.name;

    if(other.tag == "Player") {
      //  Dont destroy
      DontDestroyOnLoad(other.gameObject);

      //  Load the scene
      StartCoroutine(loadScene(other, currentScene, nextScene));
    }
  }

  IEnumerator loadScene(Collider other, string currentScene, string nextScene) {
    //  Get some variables
    var playerMotor = other.GetComponent<PlayerMotor>();
    var playerAgent = playerMotor.agent;

    //  Remove the player's destination
    playerAgent.ResetPath();
    //  Disable the navmesh
    playerAgent.enabled = false;

    //  Give a bit of time
    yield return new WaitForSeconds(0.1f);
    
    //  Load the next scene
    SceneManager.LoadScene(nextScene);

    //  Spawn point for player
    var spawnPoint = new Vector3(-15, 0, 17);
    // "Spawn" the player
    other.transform.position = spawnPoint;

    //  Enable the navmesh
    playerAgent.enabled = true;
  }
}

I am pretty sure DontDestroyOnLoad is still what you want. In regards to setting the position of your player: I suggest waiting for the scene to finish loading before you try to modify the positions of things. so instead of:

SceneManager.LoadScene(nextScene);

Do:

yield return SceneManager.LoadSceneAsync(nextScene);

I am not sure if that is what is causing your oddities but it may be. But I am a little unclear as to what exactly you want to do. You want to position the player near the gate in the new scene but I don’t see anything trying to do that in code. You would have to somehow get a reference to the other gateway and then use that transforms position instead of the hard coded spawn point vector.

the easier solution is creating in a second scrip called something like SpawnManager. have in each level a spawnmanager with A. points assign in the inspector B. find the start position of the object for example using

 GameObject.Find("Campsite");//or any other method

so in the awake you also find the player and move the player to the campsite position.
if you want to do it in that same script you need to wait for scene to be loaded 100% (sine loadscebe method is semi-synchronous, wont load all the scene before it continue with the corroutine so you cant find the objects just before the loadscene method) if you are used to events or want to try soomething a bit more complex (not hard but if you are not used to its different) you can use the onScenLoaded event an event that will be fired when the scene finisihes the load and then you can find thecampiste object and just set its transform.position.

@xxmariofer I’ve used what you’ve suggested and below is the updated code.

  void OnTriggerEnter(Collider other) {
    var currentScene = SceneManager.GetActiveScene().name;
    var nextScene = this.name;

    if(other.tag == "Player") {
      //  Dont destroy
      DontDestroyOnLoad(other.gameObject);

      //  Load the scene
      StartCoroutine(loadScene(currentScene, nextScene));
    }
  }

  IEnumerator loadScene(string currentScene, string nextScene) {
    AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(nextScene);
    while (!asyncLoad.isDone) {
      yield return null;
    }
  }

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

  void OnSceneLoaded(Scene scene, LoadSceneMode mode) {
    GameObject player = GameObject.FindWithTag("Player");

    player.GetComponent<PlayerMotor>().agent.ResetPath();
    player.GetComponent<PlayerMotor>().agent.enabled = false;
    player.transform.position = GameObject.Find("Campsite").transform.position;
    player.GetComponent<PlayerMotor>().agent.enabled = true;
  }

I switched Awake for Start, as it was giving an error about PlayerMotor Agent not being set (didn’t really affect the game; just for my own OCD).

I also added some variables to the OnSceneLoaded, as without any, it returned a game-stopping error; I just found them on the internet (no clue what they are for).

It now loads the level and positions the player on the Gateway.

But two issues now:

  1. The new Gateway instantly sends the player back a level (OnTriggerEnter)
  2. We need to pass the OnTriggerEnter Gateway to player.transform.position.

Any ideas to make it simple? I’m thinking maybe move the player to the Gateway, plus a little “in front” of it? Not sure how to pass the Gateway name to the Player transform position.