Why can't I change scenes without hard coding?

Godot Version

Godot 4.5

Question

So I’m trying to make Metroidvania style doors that change scenes, but I want to use a main scene that I instantiate my rooms into which contains the player, ui, etc. However, I can’t find a good method for making this work. Here’s the code, but I’m not very attached to it so change it as you would like

extends Node

@export var level_1: PackedScene
var current_room

func _ready():
load_room(level_1)

func load_room(destination):
# Remove the old room if it exists
if current_room:
current_room.queue_free()

var new_scene = destination.instantiate()
current_room = new_scene
add_child(new_scene)

Thanks for any help you can give me

Hi,

Your method seems fine to me, at least it’s a correct place to start.

You probably need to find a way to assign rooms to your doors, so that whenever a door is triggered, you call the load_room function with the destination room of that door.

You will probably need to implement a way to know from what door the player comes from, so that if a room has many entrances, you position the player at the right position. Having a main scene that handles the rooms instantiation is a good thing here, as you can store such an info inside your script.

Is there anything specific you have trouble with? Because your code seems okay so far.

1 Like

Yes I have a door script that theoretically should work right here:

extends Area2D

@export var target_room: PackedScene

func _on_body_entered(body: Node2D) → void:
if body is Player:
Main.load_room(target_room)

But I get this error when I try to start the game:

E 0:00:02:330 load_room: Invalid call. Nonexistent function ‘instantiate’ in base ‘Nil’.
main.gd:14 @ load_room()
main.gd:14 @ load_room()
main.gd:7 @ _ready()

You have failed to assign a value to target_room for one of your doors. @export variables will appear in the inspector, from there you can assign a unique room to each door without opening the code editor.

Just a quick note. You will find these things easier to debug if you statically type everything. For instance:

# Difficult to debug
func load_room(destination):

# Easier to debug as errors get caught cleanly
func load_room(destination: Node2D) -> void:

Another example:

# too loose:
var new_scene = destination.instantiate()

# Better
var new_scene: Node2D = destination.instantiate()

In the project settings somewhere you can set to warn on non statically typed variables. It is very useful if you get into the habit of it.

1 Like