Storing variables in scene transition (Teleport RPG)

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

I am trying to come up with a nice system to easily add new scene transitions, and make sure that the player is located in the right position when the scene has loaded.

This is how far i have come with a demo:

Think of 2 entrances, which will teleport you to 2 different scenes:

Currently i tried to create 2x area2d nodes, with a collision area. One named TeleportSource, and one named TeleportDestination.

I create an instance of TeleportSource and add it in front of the entrance. I then create an instance on the new Scene i am going to, and create an instance of TeleportDestination.

Gdscript for Source:

extends Area2D

export (PackedScene) var SceneDestination

func _on_TeleportSource_body_entered( body ):
	print("entered")
	get_tree().change_scene(SceneDestination.resource_path)

Then on Destination i have:

extends Area2D

export (PackedScene) onready var PlayerInstance
export (NodePath) onready var TeleportDestination

func _ready():
	var Player = PlayerInstance.instance()
	add_child(Player)
	Player.position = get_node(TeleportDestination).position
	print ("Teleporter is: ", get_node(TeleportDestination).position)
	print ("Player is at: ", Player.position)

So now i can freely enter the first room, and go back out again without any issues.

The problem exists when i have 2 entrances like on the picture, as there is no way for the engine to know which room i am coming from.

The question is then:
Is my approach totally wrong?
Or should i create a variable on each scene, that is then sent to a singleton, to let my script know where i came from?
Any other approaches?

:bust_in_silhouette: Reply From: Footurist

You need some kind of scene manager, that handles different scenes (which is a scene itself). This is what I do, I put variables in there, that are used globally, in a dictionary like this:

extends Node2D

var game_var = {"last_scene":"bla", "current_scene":bla2, "health":100}

It’s basically similar to singleton approach. This way you can access them anywhere and also easily store those needed variables in files, when you need to save your game.

:bust_in_silhouette: Reply From: hilfazer

Yes, use an autoload. Here’s official documentation:

And here’s my code based on official docs that handles passing parameters:

extends Node

var m_sceneParams = null     setget deleted, getParams
var m_currentScene = null    setget deleted


func deleted():
	assert(false)


signal currentSceneChanged()


func _ready():
	var root = get_tree().get_root()
	m_currentScene = root.get_child( root.get_child_count() -1 )


func switchScene(targetScenePath, params = null):
	# The way around this is deferring the load to a later time, when
	# it is ensured that no code from the current scene is running:
	call_deferred("deferredSwitchScene", targetScenePath, params)


func deferredSwitchScene(targetScenePath, params):
	if targetScenePath == null:
		return

	assert( m_sceneParams == null )
	m_sceneParams = params

	# Immediately free the current scene,
	# there is no risk here.
	m_currentScene.free()

	# Load new scene
	var newScene = ResourceLoader.load(targetScenePath)

	# Instance the new scene
	m_currentScene = newScene.instance()

	# Add it to the active scene, as child of root
	get_tree().get_root().add_child(m_currentScene)

	# optional, to make it compatible with the SceneTree.change_scene() API
	get_tree().set_current_scene( m_currentScene )
	emit_signal( "currentSceneChanged" )


func getParams():
	var params = m_sceneParams
	m_sceneParams = null
	return params

Notice that getParams() will nullify parameters after one call. This is done to ensure scenes are getting their parameters.
m_sceneParams can be anything. Use Dictionary if you have no better idea :slight_smile: