0 votes

I'm making a spelling game, and the words to be spelled are encoded as the filenames of the image resources of the game. This works fine on desktop, however, once deploying to Android, it fails miserably.

The code in question is:

var _words : Array = Array()

func _init() -> void:
    var dir = Directory.new()
    if dir.open("res://assets/images/words") == OK:
        dir.list_dir_begin()
        var filename = dir.get_next()
        while (filename != ""):
            if filename.ends_with(".png"):
                _words.append(filename.left(filename.length()-4))
            filename = dir.get_next()

The issue is that the _words array is empty on the Android device. I've tried adding the resources using the Project -> Export -> Android -> Resources -> Filters to export non-resource files, where I set the filter to *.png. I've also tried adding a Node that refers to all the images by including them as sprites. As neither of these tricks work, I've come to the conclusion that the dir() function in combination with res:// paths does not work on Android. Is that by design, or should I report a bug?

asked Jan 26 in Engine by e8johan (14 points)

Are you sure that you did write the directory path correctly? Especially in terms of uppercase/lowercase characters? Remember that Android (just like i.e. linux) is case sensitive in path and file names (extensions as well).

If you develop on Windows then you wouldn't notice it as Windows isn't case sensitive on file names.

I would start opening just res:// and listing the contents to output (and check the output either with adb logcat or inside the godot IDE.

It works on Linux (debian), so I think the case sensitivity should be ok. I'll add some output and see what goes on on the phone compared to desktop.

1 Answer

0 votes

Interesting - I just stumbled into a similar situation after writing a Singleton AudioManager. In my case, I wanted to load a bunch of OGG files at runtime - similar to what your attempting to do. While the resources were properly loaded while running in-editor, they did not load when running in an exported build (Android or PC in my case).

After a lot of poking around, I discovered that the problem lies in the way resources are packaged into the build. They are not left in their original locations and they do not have their original names - which will trip up some of your code. Specifically, I think this code is likely failing in your case:

if filename.ends_with(".png"):

If you actually debug this on an Android device, you'll see the folder you're iterating does not contain the files you expect. It'll only contain a variation of those file names that ends with .import. So, for example, if the folder originally contained a file named image.png, it will now contain one named image.png.import. The real image will have been moved to the .import folder, and will have been renamed to something like image.png.<hash>.<ext>

Where <hash> is some hash or GUID and <ext> is some other file extension.

Interestingly, Godot's ResourceLoader.load() command knows how to deal with the mapping from original folder / original filename to new folder / new filename.

So, even in the face of the above example, you can still do a ResourceLoader.load("res://assets/images/words/image.png") and Godot will happily load the file you intended.

So, if you can get appropriate file names to the resource loader, things will work as expected.

However, you not getting that far as (I think) your code is failing at the point where it checks for a "png" extension, because there is no file there with a png extension.

So, how do you fix it?

Assuming you that ultimately load the resources via the resource loader, I'd guess something as simple as this might fix the issue:

    while (filename != ""):
        filename = filename.replace('.import', '') # <--- remove the .import
        if filename.ends_with(".png"):

Essentially, that just removes the ".import" from the end of the filename that was found in the folder, which should return the name your code is expecting. Assuming you eventually tell the ResouceLoader to load the files, giving it that original name should work, even though it'll need to work some magic in the background to follow the folder and name mapping outlined above.

A similar change to my AudioManager's loading mechanism fixed my runtime resource loading issues.

answered Jan 27 by jgodfrey (1,241 points)
edited Jan 27 by jgodfrey
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.