I’m using Godot 4.4.1.stable and have an issue with UI.
I have three scenes:
- fish_inventory.tscn — this is the inventory background with a frame and some containers (for items).
extends Control
var is_open := false
var tween: Tween
@onready var chat_ui = null
var input_cooldown := 0.0
func _ready():
visible = false
modulate.a = 0.0
scale = Vector2(1.0, 1.0)
await get_tree().process_frame
chat_ui = get_tree().get_first_node_in_group("chat_ui")
if not chat_ui:
chat_ui = get_tree().get_root().find_child("ChatUI", true, false)
func _process(delta):
if input_cooldown > 0:
input_cooldown -= delta
func _input(event):
if event.is_action_pressed("fish_inventory") and input_cooldown <= 0:
input_cooldown = 0.2
toggle_inventory()
get_viewport().set_input_as_handled()
func toggle_inventory():
var player = get_tree().get_first_node_in_group("player")
if player and player.get("is_showing_fish") and player.is_showing_fish:
return
if player and player.get("controls_locked") and player.controls_locked and not is_open:
return
if is_open:
close_inventory()
else:
open_inventory()
func open_inventory():
if is_open:
return
is_open = true
visible = true
var player = get_tree().get_first_node_in_group("player")
if player:
player.controls_locked = true
if player.has_method("stop_movement"):
player.stop_movement()
if player.get("velocity") != null:
player.velocity = Vector2.ZERO
var idle_animation = "idle_down"
if player.get("last_direction") != null:
var last_dir = player.last_direction
if last_dir.y < 0:
idle_animation = "idle_up"
elif last_dir.y > 0:
idle_animation = "idle_down"
elif last_dir.x < 0:
idle_animation = "idle_left"
elif last_dir.x > 0:
idle_animation = "idle_right"
if player.has_node("AnimatedSprite2D"):
var sprite = player.get_node("AnimatedSprite2D")
if sprite.has_method("play"):
sprite.play(idle_animation)
elif player.get("animated_sprite"):
if player.animated_sprite.has_method("play"):
player.animated_sprite.play(idle_animation)
elif player.has_method("set_idle_animation"):
player.set_idle_animation()
for child in player.get_children():
if child is AnimatedSprite2D:
child.play(idle_animation)
break
if player.get("is_moving") != null:
player.is_moving = false
if chat_ui:
chat_ui.visible = false
if tween:
tween.kill()
tween = create_tween()
tween.tween_property(self, "modulate:a", 1.0, 0.3)
func close_inventory():
if not is_open:
return
is_open = false
var player = get_tree().get_first_node_in_group("player")
if player:
player.controls_locked = false
if chat_ui:
chat_ui.visible = true
if tween:
tween.kill()
tween = create_tween()
tween.tween_property(self, "modulate:a", 0.0, 0.2)
await tween.finished
visible = false
func _on_fish_item_selected(fish_data):
close_inventory()
var player = get_tree().get_first_node_in_group("player")
if player and player.has_method("show_fish_in_hands"):
player.show_fish_in_hands(fish_data)
func add_fish_item(fish_texture: Texture2D, fish_name: String, fish_size: float):
var fish_item_scene = preload("res://scenes/fish_inventory_item.tscn")
var fish_item = fish_item_scene.instantiate()
var container = $ScrollContainer/VBoxContainer
container.add_child(fish_item)
await get_tree().process_frame
fish_item.custom_minimum_size = Vector2(64, 64)
fish_item.size_flags_horizontal = Control.SIZE_EXPAND_FILL
fish_item.size_flags_vertical = Control.SIZE_EXPAND_FILL
fish_item.setup(fish_texture, fish_name, fish_size)
if not fish_item.fish_selected.is_connected(_on_fish_item_selected):
fish_item.fish_selected.connect(_on_fish_item_selected)
fish_item.mouse_filter = Control.MOUSE_FILTER_STOP
if fish_item.has_node("Background"):
var bg = fish_item.get_node("Background")
bg.mouse_filter = Control.MOUSE_FILTER_STOP
- fish_inventory_item.tscn — this is a single inventory item: just a background, an icon, and some text. It has hover animation using mouse_entered/mouse_exited signals, and it works perfectly if I run this scene alone and the animation are there.
extends Control
@onready var background = $Background
@onready var fish_icon = $FishIcon
@onready var fish_label = $FishLabel
@onready var size_label = $SizeLabel
const FONT_PATH = "res://assets/sprites/GUI/Peaberry-Bold.ttf"
const LABEL_COLOR = Color(0.91, 0.75, 0.48)
const SIZE_LABEL_COLOR = Color(0.8, 0.8, 0.8)
var fish_data: Dictionary = {}
var original_scale: Vector2
var is_hovered: bool = false
var tween: Tween
signal fish_selected(fish_data)
func _ready():
var font = preload(FONT_PATH)
fish_label.add_theme_font_override("font", font)
fish_label.add_theme_color_override("font_color", LABEL_COLOR)
fish_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
if size_label:
size_label.add_theme_font_override("font", font)
size_label.add_theme_color_override("font_color", SIZE_LABEL_COLOR)
size_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
original_scale = scale
mouse_filter = Control.MOUSE_FILTER_STOP
if not mouse_entered.is_connected(_on_mouse_entered):
mouse_entered.connect(_on_mouse_entered)
if not mouse_exited.is_connected(_on_mouse_exited):
mouse_exited.connect(_on_mouse_exited)
if not gui_input.is_connected(_on_gui_input):
gui_input.connect(_on_gui_input)
size = Vector2(64, 64)
if background:
background.custom_minimum_size = Vector2(64, 64)
func setup(fish_texture: Texture2D, fish_name: String, fish_size: float):
fish_data = {
"texture": fish_texture,
"name": fish_name,
"size": fish_size
}
fish_icon.texture = fish_texture
var size_category = get_size_category(fish_name, fish_size)
var fish_text = "%s (%.1f cm)" % [fish_name.capitalize(), fish_size]
fish_label.text = fish_text
var size_category_text = size_category.capitalize()
if size_label:
size_label.text = size_category_text
else:
fish_label.text = "%s\n%s" % [fish_text, size_category_text]
fish_data["size_category"] = size_category
func get_size_category(fish_name: String, size: float) -> String:
return FishDatabase.get_size_category(fish_name, size)
func _on_mouse_entered():
is_hovered = true
if tween:
tween.kill()
tween = create_tween()
tween.parallel().tween_property(background, "modulate", Color(1.15, 1.15, 1.15), 0.15)
tween.parallel().tween_property(background, "scale", Vector2(1.15, 1.15), 0.15)
func _on_mouse_exited():
is_hovered = false
if tween:
tween.kill()
tween = create_tween()
tween.parallel().tween_property(background, "modulate", Color.WHITE, 0.15)
tween.parallel().tween_property(background, "scale", Vector2(1, 1), 0.15)
func _on_gui_input(event):
if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
var player = get_tree().get_first_node_in_group("player")
if player and player.get("is_showing_fish") and player.is_showing_fish:
return
fish_selected.emit(fish_data)
if tween:
tween.kill()
tween = create_tween()
tween.tween_property(background, "scale", Vector2(1.25, 1.25), 0.09).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
tween.tween_property(background, "scale", Vector2(1.15, 1.15), 0.09).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_IN)
await tween.finished
if is_hovered:
if tween:
tween.kill()
tween = create_tween()
tween.parallel().tween_property(background, "scale", Vector2(1.15, 1.15), 0.1)
else:
if tween:
tween.kill()
tween = create_tween()
tween.parallel().tween_property(background, "scale", Vector2(1, 1), 0.1)
- main.tscn — this is my main scene. Here, I simply add the fish_inventory.tscn scene as a child.
And this is the code that adds fish in the items:
func _on_fish_caught(fish_data):
fish_sprite.texture = fish_data.texture
fish_sprite.visible = true
fish_sprite.rotation_degrees = -45
var scale_factor = fish_data.size / FISH_DISPLAY_BASE_CM
fish_sprite.scale = Vector2.ONE * scale_factor
is_showing_fish = true
controls_locked = true
show_fish_catch_view()
play_idle_animation()
fish_sprite.start_jumping()
var fish_inventory = null
for node in get_tree().get_root().find_children("*", "", true, false):
if node.get_script() and node.get_script().get_path().ends_with("fish_inventory.gd"):
fish_inventory = node
break
if fish_inventory:
fish_inventory.add_fish_item(fish_data.texture, fish_data.name, fish_data.size)
print("The fish was added into the inventory through the code")
else:
print("FishInventory not found")
- In fish_inventory_item.tscn, mouse hover/tween animation works fine: mouse_entered, mouse_exited, and gui_input signals are triggered, and the background animates on hover.
- When I instance this item into my main scene (via code), the item is visible, but the animation on hover does NOT work. The mouse signals do not fire at all.
- Mouse filter is set to STOP for Control, which is root for fish_inventory_item.tscn. ScrollContainer and its parents are set to IGNORE in the fish_inventory.tscn.
- I need the animation and the button to work in the main scene.
Thanks for your help in advance!