Godot Version
4.4
Question
How can I reparent the player node after switching scenes? Currently it throws an infinite loop.
#Trigger.gd
extends Area2D
@export var scene:String
@export var spawn:String = "SpawnPoint"
func _on_body_entered(body: Node2D) -> void:
if body is Player:
if scene:
SceneSwitcher.player = body
SceneSwitcher.switch_scene(str("res://scenes/", scene, ".tscn"))
#SceneSwitcher.gd
extends Node
var current_scene:Node
var player: Node
func _ready() -> void:
var root = get_tree().root
current_scene = root.get_child(root.get_child_count() - 1)
func switch_scene(scene_path):
var new_scene = load(scene_path).instantiate()
get_tree().root.add_child(new_scene)
player.call_deferred("reparent", new_scene)
current_scene.queue_free()
current_scene = new_scene
get_tree().set_current_scene(current_scene)
When reparented does your new scene place the player in another Trigger.gd area?
No it places the player in another scene. I have two scenes called level1 and level2. The game starts on level1.
My goal is to move the player to the location of the spawn point, but it crashes before then.
Does level 2 have any Trigger.gd areas within it?
Yes level1 and level2 both have instances of Area2D that use the Trigger.gd script.
I made that Area2D into a reusable scene.
Is “SceneSwitcher.gd” an autoload? Or is it inside the main scene?
SceneSwitcher is an autoload script
From these two snippets of code the only way I see a infinite loop error occuring is from the new scene instantiating another Trigger.gd on top of the player, are you absolutely sure the player won’t occupy the second Trigger.gd space when instantiated?
I removed the area2d from level2 and it still crashes like before.
However if I remove the player from the current_scene
manually and add it to the new_scene
it does not crash. See below:
Whenever I remove the player from its parent like player.get_parent().remove_child(player)
it freezes and crashes.
func switch_scene(scene_path):
var new_scene = load(scene_path).instantiate()
get_tree().root.add_child(new_scene)
current_scene.remove_child(player)
new_scene.add_child(player)
current_scene.queue_free()
current_scene = new_scene
get_tree().set_current_scene(current_scene)
1 Like
I noticed that the _on_body_entered
event is called twice whenever I reparent the player. Is there a way to only call it once?
func _on_body_entered(body: Node2D) -> void:
if body is Player:
print("switch scene")
body.call_deferred("reparent", SceneSwitcher.current_scene)