How to preload A folders worth of images and put them into an array

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

I am making a starter project which should show a random image on the screen when I enter a certain area. However, the folder has a large amount of images in. How can I go about selecting a random image from this folder, resize it (somewhat) and then display on the screen?

My current plan is to preload all of the images in the folder and store them in an array, which I can then access using a random number when choosing which image to display to the screen (using the image as a texture on a large sprite).

Is there an easier/simpler way to do this? Like iterating over the folder and inserting all the images into an array, there are too many for me to type in each pre-loaded image manually.

Thanks.

Sounds like a perfectly fine solution to me. What’s bothering you about it?

Depending on the amount (and size) of images, you might of course be better off selecting loading it at runtime (instead of preloading all of them in advance - which seems a bit wasteful, if all you need is one image).

njamster | 2020-02-24 12:23

Loading at runtime might be what I end up doing, sounds like a good practice I should get into doing. But really the question was regarding how to do it, although I was open to suggestions if there was a better way I didn’t know of (such as your suggestion to load at runtime, thanks for that).

Rickers | 2020-02-24 18:39

:bust_in_silhouette: Reply From: Magso

You can get all files from a directory and store them like this.

var path = "path/to/folder"
var dir = Directory.new()
dir.open(path)
dir.list_dir_begin()
while true:
    var file_name = dir.get_next()
    if file_name == "":
        #break the while loop when get_next() returns ""
        break
    elif !file_name.begins_with("."):
        #get_next() returns a string so this can be used to load the images into an array.
        your_image_array.append(load(path + file_name))
dir.list_dir_end()

Thank you very very much, going to try implementing this now.

Rickers | 2020-02-24 18:50

Alright so after implementing, I thought i’d post the altered code.

Your code was pretty much perfect, although I forgot to add a “/” to the appended path+filename, this probably won’t be a problem for most people.

Also, I found that I was importing two objects per image in the file, a jpg and a .import. The .import returns nulls and so need to be left out when appending the image to the pics list. Should say this once again is probably an issue on my end rather than anything you put my way. Either way here’s the finished product for other people:

extends Sprite
var pics = []
func _ready():
	var path = "res://path/to/folder"
	var dir = Directory.new()
	dir.open(path)
	dir.list_dir_begin()
	while true:
		var file_name = dir.get_next()
		if file_name == "":
			#break the while loop when get_next() returns ""
			break
		elif !file_name.begins_with(".") and !file_name.ends_with(".import"):
			#if !file_name.ends_with(".import"):
			pics.append(load(path + "/" + file_name))
	dir.list_dir_end()

Thanks for helping me out.

Rickers | 2020-02-25 15:20

1 Like

Seems like Directory doesn’t work anymore in Godot 4.6; here’s what I made:

func load_folder(path : String, format : String):
	var list: Array = []
	var dir = DirAccess.open(path)
	if dir:
		dir.list_dir_begin()
		var file_name = dir.get_next()
		while file_name != "":
			file_name = dir.get_next()
			if !dir.current_is_dir() and !file_name.begins_with(".") and file_name.ends_with(format):
				list.append(load(path + "/" + file_name))
		dir.list_dir_end()
	return list

Since it looks like people are still finding this archive question, I’ll share a shorter (but a bit more unreadable) way of doing it.

	var list: Array = Array(
			ResourceLoader.list_directory(dir_path)
		).filter(
			func (fp: String) -> bool: return fp.ends_with(file_ending)
		)

This one-liner uses the ResourceLoader class instead of DirAccess to list the files since ResourceLoader isn’t affected by the exported project having the files moved around (if you were using DirAccess, you’d need to look for .remap files since the original resources aren’t there anymore on export).

Then, since ResourceLoader.list_directory returns a PackedStringArray, the return value is converted into an Array so the filter function can be called on it. Array.filter takes a “Callable” as its only argument. In this case, Callable is just a function you make yourself.

Here, I’ve used a lambda function instead of declaring one outside of this line. The lambda function checks for the file ending with String.ends_with, and since it’s passed to the filter function, the final Array assigned to list will only have files ending with file_ending.

2 Likes

I use this to load scene files in a directory into an OptionButton.

const FOLDER_PATH = "res://my_folder/"

func _load() -> void:
	clear()
	
	var dir: DirAccess = DirAccess.open(FOLDER_PATH)
	if not dir:
		return
	var level_list: PackedStringArray = dir.get_files()
	
	for file_name: String in level_list:
		if file_name.contains(".tscn"):
			add_item(file_name.trim_suffix(".remap").trim_suffix(".tscn").capitalize())
1 Like

to be clear, would this load the resources as well or just list references that still need to be loaded?

It will list the file paths that need to be loaded. The original question was about randomly selecting an image from a folder of images, so it would be unnecessary to load all of them.

1 Like