Using Godot 4.4.dev1, I have created two scenes that I use for my HUD. One for abilities and one for keyboard keys. Both have exported variables that contain information about textures that I load in the editor into child nodes. When I play the game in the editor, everything loads fine. When I export the game to Windows or the Web, they do not.
I partially fixed the problem by enabling Editable Children. (See the in-game screenshot below where the 1, and the first ability on the bottom and right appear correctly.) However this has three drawbacks. 1.) I have to enable editable children. 2.) If I further embed them in other scenes, editable children no longer solves the problem. 3.) The _input events for keypresses no longer work in the export. (When you press the 1 key it's supposed to show you that it was pressed.)
I suspected it might have something to do with being a tool script, but I commented that line out, and no change.
I also tried the reparenting suggested in this thread: https://forum.godotengine.org/t/programmatically-changed-scene-instance-wont-save/37413 I tried it with the following code:
func _ready() -> void:
self.tree_entered.connect(_on_tree_entered)
func _on_tree_entered():
var root_node = get_tree().current_scene
self.owner = root_node
mask.owner = root_node
ability_icon.owner = root_node
Here is the HUD Ability Code:
@tool
extends Control
class_name HUDAbility
@export var ability_icon_64_x_64_px: Texture:
set(value):
if not is_node_ready():
await ready
ability_icon_64_x_64_px = value
ability_icon.texture = value
@export var is_round: bool = false:
set(value):
if not is_node_ready():
await ready
is_round = value
if is_round:
mask.set_clip_children_mode(Control.ClipChildrenMode.CLIP_CHILDREN_ONLY)
else:
mask.set_clip_children_mode(Control.ClipChildrenMode.CLIP_CHILDREN_DISABLED)
@onready var mask: TextureRect = $Mask
@onready var ability_icon: TextureRect = $Mask/AbilityIcon
@onready var level_label = $LevelLabel
var current_level: int = 0
func update_level(level: int):
current_level = level
if current_level > 0:
level_label.text = str(current_level)
self.show()
level_label.show()
else:
self.hide()
level_label.hide()
Here is the Keyboard Key Code:
@tool
extends Control
@export var key_enum: Key:
set(value):
if not is_node_ready():
await ready
key_enum = value
key_name = OS.get_keycode_string(key_enum)
@export var key_name: String:
set(value):
if not is_node_ready():
await ready
key_name = value
var filename = path + "keyboard_" + value
var extension = ".png"
var unpressed_filename = filename + "_outline" + extension
var pressed_filename = filename + extension
if ResourceLoader.exists(unpressed_filename):
key_unpressed.texture = load(unpressed_filename)
else:
key_unpressed.texture = null
if ResourceLoader.exists(pressed_filename):
key_pressed.texture = load(pressed_filename)
else:
key_pressed.texture = null
@onready var key_unpressed = $Key_Unpressed
@onready var key_pressed = $Key_Pressed
@onready var path: String = "res://assets/ui/icons/input/keys_flat/"
func _input(event):
if event is InputEventKey and event.pressed:
if event.keycode == key_enum:
key_unpressed.hide()
key_pressed.show()
if event is InputEventKey and not event.pressed:
if event.keycode == key_enum:
key_pressed.hide()
key_unpressed.show()
This is an editor view of the items in the HUD: This is what the game looks like when played from the editor (The '1' key is being pressed, hence its different appearance.): This is what the game looks like played from a Windows Export:
I'm open to alternate solutions or fixes to my code. As an added interesting piece, the keys can still receive mouse events. (That code isn't included, it's from another project.)