Using Doors to go to different levels in 3D

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By psoyboy

Hey guys, just started playing around with Godot and I’m trying to figure out the best way to handle level switching in my game.

The game world is split into 3 distinct levels:

  1. Outside
  2. Inside Level 1
  3. Inside Level 2

Outside and Inside Level 1 are connected, and Inside Level 1 and Level 2 are connected

I need a way to make it so that when a player interacts with a door object the game loads the level necessary AND spawns the player at the correct spawn point.
So when the player goes from Inside Level 1 to Outside, they need to spawn right infront of the door object in the Outside Level instead of Outside’s default spawn location. The same is true of when the Player goes from Inside Level 2 back to Inside Level 1.

I just learned about singletons/autoload so I figure I need to set up some kind of level manager but Im not exactly sure how. I also don’t know how to set the player’s transform to be the same as the spawn point.

:bust_in_silhouette: Reply From: BigTuna675

Hi! You could setup your scene tree so that you have a level manager node, like you said, and its child is the level. You will probably also want to use an autoload/singleton like you said, to connect a signal between the manager node and the triggering node.

For example- Autoload script “SignalManager”.
Scene tree - Has a “LevelManager” node, and its child is the current active level.
In the SignalManager, create a signal called “on-level-changed” or something.

In the LevelManager node ready function, connect itself to the SignalManager signal of “on-level-changed”.

func _ready():
    var _throwAway1 = SignalManager.connect("on-level-changed",self,"changeLevels")

func changeLevels():
    get_child(0).queue_free()
    var nextLvl = lvlPath.instance() #const lvlPath = preload("res://path of your level scene")
    call_deferred("add_child",nextLvl)

Adjusting the player’s spawn point can be done by emitting a signal from the ready signal of the new level and passing the spawn point global position, which can be placed by you in the editor. Add a position2d node and place it on where the player should spawn. In the new level script, save it as onready var spawnPoint = $position2d. The player will be connected to/listening for this signal.

Passing an argument in a signal is done like so (in the ready function of the next level)

func _ready():
    SignalManager.emit_signal("change_player_pos",spawnPoint.global_position)

and then in the player’s script

func _ready():
    var _tempThrowaway123 = 
    SignalManager.connect("change_player_pos",self,"adjustPos")

func adjustPos(globPos):  #globPos is passed via the emitted signal from the new level
    set_deferred("global_position",globPos)

That’s pretty much how I deal with changing levels. You can get fancy with keeping track of what level you’re on, what’s the next level etc, but sometimes its best to keep it simple especially early on. Learning how to switch levels is a little cumbersome at first but it will make sense if you keep trying!! Good luck!!

PS an alternative solution is to keep the player as a child of the levels. So each level scene has a player node in it. Then when you switch levels the player comes along for free (as a new node). This works well for games that don’t require variables from the player to carry over. If you’re making a bit of an open world approach then you probably don’t want to do this method, or you’ll need to save the players variables in an autoload/dictionary or something else and re-initialize the players stats when switching scenes