Procedural Instantiating scenes not added to a tree

Godot Version

4.2

Question

Hi,

I am trying to create a basic level generator that will simply generate map for my game.

It is a very basic game, spaceShooter like, where player moves up the screen on a map that is proceduraly generated.

The idea is that I have couple of scenes created as pieces(terrain.tscn with Terrain.gd script) of the entire map.

LevelGenerator class(responsible for map generation) has a variable defined as arrays where you can put terrain pieces that are supposed to be spawned when game starts. Then I instanciate terrains in Ready() function:

#LevelGenerator.gd
class_name LevelGenerator extends Node2D

@export var mapSegments: int = 10 #number of TileSets to repeat
@export var tilesToGenerate: Array[PackedScene]

func _ready():
	#await get_tree().create_timer(0.0).timeout #TODO
	createLevel()

func createLevel():
	for i in min(tilesToGenerate.size(), mapSegments):
		var lvl = tilesToGenerate[i].instantiate()
		get_parent().add_child(lvl)
		lvl.z_index = -999
		lvl.global_transform = Transform2D(0, Vector2(0, i * 490 * -1))

For some reason when I run the game terrain scenes are not instanciated.

When I change the code by adding await function befor createLevel() it works. Even if it’s set to wait 0 sec.

await get_tree().create_timer(0.0).timeout #TODO

Any idea why this is working that way ?

Some additional resources:

You need to load() or preload() the scenes before you can instantiate them. Your array is probably holding some kind of reference to the scenes, not the actual PackedScene data. Personally, I’d use a text file with the filenames instead of an exported array in the editor. Or an array of paths, instead of scenes.

1 Like

In addition to the previous reply, I’d also add that it can create issues when changing the tree structure of parent nodes within _ready()

This can be avoided by calling add_child indirectly using call_deferred()

1 Like

Thanks for replies. Adding load and call_deffered actually works. Couldn’t use preload since it requires path to be fixed String value.

Nevertheless I still am wondering why it was not working. Many people are showing this kind of assigment (using @export and then drag and drop) as dependency injection examples (spawning bullets etc.). In addition it actually was working fine with just adding some delay before. Which would suggest some sort of resource load order issue.

Glad you got it working! I expect the zero ms delay had a similar effect as call_deferred. Not sure about the load as I haven’t had a chance to test

Scene instancing is not the same as Node instancing. There is a lot to unpack there, metaphorically and literally. It’s not a simple thing and you can learn more about it in the manual, but I don’t think it’s worth your time learning the internals. Just know it is not quite the same. Maybe worth a bug report/feature request on the git, tho.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.