extends Node class_name InteractiveItems # Emits the node with the `item_group_name` group set. signal item_clicked(node: Node) @export var item_group_name: String = "item" @export var call_interact: bool = true @export var show_debug_label: bool = true var label var current_object func find_interactive(): return get_tree().get_nodes_in_group(item_group_name) func list_nodes(node: Node, parent: bool = true) -> Array[Node]: var res: Array[Node] = [node] if parent and node.get_parent(): res.append(node.get_parent()) res.append_array(node.get_children()) return res func get_collision(mesh: MeshInstance3D) -> CollisionObject3D: for node in list_nodes(mesh): if node is CollisionObject3D: return node mesh.create_convex_collision() return mesh.get_child(mesh.get_child_count() - 1) func _on_mouse_entered(node: Node3D, entered: bool): current_object = node if entered else null if label: label.text = node.name if entered else &"" func do_interact(node: Node): for child in list_nodes(node, false): if child.has_method("interact"): child.call("interact") return func setup_label(): if not show_debug_label: return label = Label.new() label.position = Vector2(20, 20) add_child(label) func _ready(): setup_label() for item in find_interactive(): var col := get_collision(item) col.input_ray_pickable = true # make sure Input.Ray Pickable is Off for invisible walls col.connect("mouse_entered", _on_mouse_entered.bind(item, true)) col.connect("mouse_exited", _on_mouse_entered.bind(item, false)) func _unhandled_input(event): if event.is_action_pressed("ui_accept"): if current_object: #print(current_object) if call_interact: do_interact(current_object) item_clicked.emit(current_object)