func _ready():
	for x in 5:
		var tile = preload("res://scenes/hex.tscn").instantiate()
		add_child(tile)
		tile.position.x = 2*x

I seem to have to instantiate the preload immediately or I get some kind of error, so I have to keep loading it on every cycle.

  • like this?

    var tile = preload("res://scenes/hex.tscn")
    var tile_instance = tile.instantiate()
    add_child(tile_instance)

like this?

var tile = preload("res://scenes/hex.tscn")
var tile_instance = tile.instantiate()
add_child(tile_instance)

I thought I did that, but it works. Thanks.

The way I always thought it worked is you should preload stuff outside of where you instantiate it, like with an onready var.

onready var some_file = preload("res://something.tscn")

That works, and so does

var some_file = preload("res://something.tscn")

Then in a function somewhere:

var debris = poopFile.instantiate()

I was testing this out in 3.5 though, so make sure to tag your version when starting a thread.

Yes, you should preload at the top of the script (only once, you can instantiate as many copies as you like). You actually don't need onready since it's implied when using preload.

I don't think it matters when exactly you call preload(). According to documentation, it is executed when the script is parsed, so before _ready(), even before _init() or any script properties initialization. From this also follows that it doesn't matter how may times you call it. It'll just return a reference to previously loaded resource. You can safely call it inside loop like in the initial example, although it stylistically looks better if you call it once at initialization. Here's what the docs have to say about preload():
During run-time, the resource is loaded when the script is being parsed. This function effectively acts as a reference to that resource

Depends how the compiler works, but it seems safer to put it at the top. In the best case you are still defining a new variable unnecessarily.

    cybereality put it at the top

    I think that's the best way. It's also clear. And you can use a constant.

    # Instanced to spawn a bullet.
    const Bullet: PackedScene = preload("bullet.tscn")

    This is one place where there's a conflict in following the style guide naming conventions. Since it's a constant, it should be UPPER_SNAKE_CASE. But since it's something that's instanced, it should be PascalCase. I chose to use the latter, since that seems to be the more important characteristic.

    It just looks bad when you call it in a loop or in the middle of some random function, but performance and footprint wise it doesn't make a difference. It's dealt with at the parser level. The thing is loaded (only once) even before the script is compiled, and all calls to preload() are replaced with references to the resource object by the parser. That's also the reason why it only allows string constants for the path argument.

    At least that's my understanding of what the docs say.

    This makes sense but it wouldn't hurt if somebody actually stress-tested this to confirm it. We all know how Godot documentation can sometimes get a little whacky 🙂

    --

    EDIT: I made a quick test running a scene with two sibling nodes, each having a script that preloads the same resource in the _ready() callback.
    test_1.gd:

    extends Node
    
    func _init():
    	print("init")
    	
    func _ready():
    	print("ready")
    	print(preload("res://icon.png"))

    test_2.gd:

    extends Node
    
    func _init():
    	print("init 2")
    	
    func _ready():
    	print("ready 2")
    	print(preload("res://icon.png"))

    With verbose flag on, we get this printed in the console:

    Loaded builtin certs
    Loading resource: res://test.tscn
    Loading resource: res://test_1.gd
    Loading resource: res://icon.png
    Loading resource: res://test_2.gd
    init
    init 2
    ready
    [StreamTexture:1259]
    ready 2
    [StreamTexture:1259]

    We can see that the resource (icon.png) is loaded only once, immediately after loading the first script that calls preload(). Way before you'd expect if preload() was a regular function call that follows the order of execution. The resource is loaded before objects that "call" preload() are even created. I in fact think they should have used a special syntax for preloading to avoid this confusion.
    If we just replace each preload() with load(), the order becomes as expected, because load() is a regular function call and the resource is loaded exactly after the call (although the second call probably just returns cached data):

    Loaded builtin certs
    Loading resource: res://test.tscn
    Loading resource: res://test_1.gd
    Loading resource: res://test_2.gd
    init
    init 2
    ready
    Loading resource: res://icon.png
    [StreamTexture:1267]
    ready 2
    Loading resource: res://icon.png
    [StreamTexture:1270]

      xyz It just looks bad

      Perhaps, but usually ugly code means you don't quite understand the logic, and are prone to make mistakes.

      • xyz replied to this.

        cybereality Sure, for anything more serious than demo code I'd prefer seeing preloads at the top. But it's good to know exactly what they do, however one decides to use them stylistically.

        The fact that load() and preload() are syntactically consistent only adds to the confusion, implying they behave similarly. Imho they should've used something like @preload for preloads, while keeping load() a regular function. This would also strongly encourage people to put them at the top.