Detecting mouse over children

Godot Version

v4.2.2.stable.official [15073afe3]

Question

Hello friends! I’m trying to make a skill tree menu with several skill nodes. When you move your mouse over a skill node, I want that’s node’s description to appear in a label box down below by changing the label’s text to match the node’s description text. The nodes and the label are all children of a parent skill tree control node, so how do I check if one of them is being moused over? I know the nodes have a mouse_entered() signal but it would be inefficient to link up each skill to the parent tree and have each of them be their own function. Thank you for the help!

I’d suggest hooking up mouse_entered() for each thing, but doing something like this:

# skill node

func handle_mouse_entered() -> void:
    $Label.set_description("Wrestling Pose", "Strike a dramatic pose on a turnbuckle or a nearby tactical rock for a bonus 15% damage on the next attack.")

Then in the label:

# label script

func set_description(title: String, desc: String) -> void:
    $Title.text       = title
    $Description.text = desc

You can bind extra data when connecting signals, I recommend connecting to the mouse_entered signal and binding the skill nodepath (so you can get the description from the skill) or the entire description directly, the latter is much worse to work in and edit.

How your skill descriptions stored influences this decision, if each skill node has the same script you could connect and bind dynamically on _ready, I believe would be the simplest outcome with about two lines of code.

What’s annoying is that using a set_description function would allow me to basically use the same code for each mouse_entered() function:

_on_skill1_mouse_entered():
$Label.set_description($skill1.desc)

_on_skill2_mouse_entered():
$Label.set_description($skill2.desc)

_on_skill3_mouse_entered():
$Label.set_description($skill3.desc)

Is there a way I can combine these all into one function that automatically gets called whenever one is moused over and it passes in which one is moused over? mouse_entered doesn’t pass in anything since it’s unique to each skill node

Yes. Instead of connecting through the editor you can group or child to a common parent and iterate. Using bind to make each function call unique.

func _ready() -> void:
	for skill in $Skills.get_children():
		var bound_function: Callable = $Label.set_description.bind(skill.desc)
		skill.mouse_entered.connect(bound_function)

This code assumes each skill is a child of “Skills”, but you could use groups instead such as for skill in get_tree().get_nodes_in_group("skills") since you may not want to change the scene tree for UI.

This is helpful, especially for checking if the mouse entered each of the children, but how exactly do I bind a function? Sorry if this is a simple question, but I haven’t seen any documentation on this feature yet.

Using .bind on any function is how you can bind it, the .bind returns a Callable function, which is what you connect to.

If you don’t really have a set_description function then I suppose set_text will work for a Label.

Thank you for the help! This allowed me to directly set the label text to any of the moused over children’s descriptions. I think $label.text = skill.desc would’ve worked too, but this is still helpful for including multiple strings.

You can only use .bind on a Callable/function, and assignment is not a function. You could make your own function to bind if the description is more complicated than only setting text

func set_description(new_description: String) -> void:
	$Label.text = new_description
	print("Now with a new description! ", new_description)
	# AND show text over time
	var visible_tween := create_tween()
	visible_tween.tween_property($Label, "visible_ratio", 1.0, 0.2).from(0.0)


func _ready() -> void:
	for skill in $Skills.get_children():
		# Now using set_description
		skill.mouse_entered.connect(set_description.bind(skill.desc))