Question about loading images through JSON

Godot Version

4.6

Question

I’m trying to make a visual novel using Godot, but given I want a lot of control, I’m doing it myself (I know about Dialogic)

I was wondering if its not too out-there of a question, if its possible to store image paths from a JSON file and then change the talking sprites of a visual novel using an image path within that JSON file instead of coding a long manual switch of portraits for each new line of text. I’m already using a JSON file to store all of my dialogue and that works fine, but trying to use an image path for data gives me an error that I’m trying to assign a String to a Sprite2D texture.

You don’t even need a Json file to store image paths. You can save the paths you will need for a specific scene or chapter inside a Dictionary and using relative paths. Say your dictionary looks like this:

var chapter_1_dictionary: Dictionary = {
"john_happy": "res://character/textures/john/john_happy.png",
"john_sad": "res://character/textures/john/john_sad.png"
}

Then you can load in bulk all the images stored inside that dictionary before you even start the chapter, saving you lag spikes from loading images during gameplay.

Remember that the image path is different from a loaded image. You have to load the image in code with the path saved inside the dictionary.

I seem to be getting the same error when trying to use the image paths in a Dictionary. Is there perhaps a certain way to reference them?

Yes you can use image paths, you need to load the resource before using it

$Sprite2D.texture = load(dialogue_image_path)
var image = Image.load_from_file(chapter_1_dictionary["john_happy"])
var texture = ImageTexture.create_from_image(image)
$Sprite2D.texture = texture

Something like this should work. As you can see you load the image by referencing the dictionary and using the key, then you load the image as a texture compatible to the sprite2d and you assign it.

This will actually only work for in-editor testing, not exported games. Runtime loading of res:// paths is dicey as most imported resources are converted and they are no longer runtime loadable from that path. Use the global scope load or ResourceLoader.load to load res:// resources.

I tried this as well to the best of my ability, I believe I did it correctly? One thing that concerns me is that the textures don’t show up and throw me an error (which does not crash my game) that’s along the lines of the texture being null.

Can you share some of your code? What paths are you feeding it? What error message do you get exactly?

	if current_dialogue_id == 0:
		image = ResourceLoader.load(sprites["van_upset"])

This is the error I get from a later line,

var texture = ImageTexture.create_from_image(image)

And this is the error

E 0:00:00:782   start: Failed to instantiate an autoload, path is not pointing to a scene or a script: res://visual_variables.tres.
  <C++ Error>   Condition "!n" is true. Continuing.
  <C++ Source>  main/main.cpp:4422 @ start()


E 0:00:00:809   VisualHandler.gd:46 @ next_script(): Invalid image: null
  <C++ Error>   Condition "p_image.is_null()" is true. Returning: Ref<ImageTexture>()
  <C++ Source>  scene/resources/image_texture.cpp:57 @ create_from_image()
  <Stack Trace> VisualHandler.gd:46 @ next_script()
                VisualHandler.gd:61 @ start()
                VisualHandler.gd:53 @ _ready()

The top might be unrelated, but I included it anyways incase.

So your sprites["van_upset"] may be an invalid path, can you share what that path is? Are you certain it exists in your project?

This line probably doesn’t need to exist, load on the path will by default produce a Texture2D you can use immediately, not an Image. So trying to create a ImageTexture from an already Texture2D will give you an error, but currently image is null, so we have to figure out your path problem.

I tried this after you mentioned that in case as I wasn’t sure if there was anything wrong with the path,

"van_upset" : load("res://Dialogue/json/van_upset_new.png")


This did not work unfortunately. However originally as of testing that and getting the error, this is what I put:

"van_upset" : "res://Dialogue/json/van_upset_new.png"

This path is valid, JSON can’t use functions such as load

Now are you sure the path is correct? If you find this file in your FileSystem panel you can right click it and select “Copy Path” to compare/be sure. Did you change any of this image’s import settings?

I haven’t changed any import settings, I also did verify this was the correct filepath.

one thing I will note is that I get this warning from the previous method of adding the image:

W 0:00:01:548   VisualHandler.gd:42 @ next_script(): Loaded resource as image file, this will not work on export: 'res://Dialogue/json/van_upset_new.png'. Instead, import the image file as an Image resource and load it normally as a resource.
  <C++ Source>  core/io/image.cpp:2766 @ load_from_file()
  <Stack Trace> VisualHandler.gd:42 @ next_script()
                VisualHandler.gd:62 @ start()
                VisualHandler.gd:54 @ _ready()

I’m a bit unsure what its telling me to do exactly, but.

Should work then, could you share more of your script? Assigning at type to image would help, and confirm current_dialogue_id is equal to 0

I think assigning a type worked, thankfully.

It shouldn’t work on it’s own, adding a type would produce more and better errors

I see. I’ll have to investigate it later. After adding a type the sprites showed up again and I stopped getting errors, though I wonder what exactly it changed.