A simple and efficient Godot utility for finding nodes in your scene tree. This tool lets you recursively search the current scene, a specific branch, or a sub-viewport to find nodes based on custom logic.
It's designed as a static utility class. You don't need to instance it; just load or preload the script and call its functions directly.
- Find by Filter: Use a custom function (
Callable) to find the first node or all nodes that match any criteria (type, name, group, properties, etc.). - Find by Type: A simple wrapper to find the first or all nodes of a specific type.
- Flexible Type: Works with built-in types (
Control),class_names (Player), or loadedScripts (preload("res://player.gd")). - Recursive Search: Searches the entire tree from a given root.
- Scoped Search: Start the search from any node, not just the scene root. Ideal for searching within
SubViewports. - Visibility Filter: Safely filter for visible-only nodes. It correctly handles
CanvasItems,Node3Ds, and non-visual nodes. - Viewport Helper: Includes a utility to find the root scene node of any
SubViewport.
To use the tool, preload or load the script into a constant or variable. You can then call its static functions from that variable.
func _ready():
# Now you can use 'Search' to call its functions
var player_node = SearchObjectByType.find_node_by_type(Player)
if player_node:
print("Found the player!")static func find_node_by_filter(filter: Callable, root_node: Node = null) -> Node
Returns the first Node that returns true for the provided filter function. This is highly efficient as it stops searching on the first match.
filter: ACallable(function) that takes oneNodeargument and returns abool.root_node: (Optional) The node to start searching from. Ifnull, uses the entire current scene.
static func find_nodes_by_filter(filter: Callable, root_node: Node = null) -> Array[Node]
Returns an Array of all Nodes that return true for the provided filter function.
- Parameters are identical to
find_node_by_filter.
static func find_node_by_type(type: Variant, visible_only: bool = true, root_node: Node = null) -> Node
Returns the first Node found that matches the type.
type: The class to search for (e.g.,Control,Player, orpreload("player.gd")).visible_only: (Optional) Iftrue, only returns nodes that are visible in the tree. Defaults totrue.root_node: (Optional) The node to start searching from. Ifnull, uses the entire current scene.
static func find_nodes_by_type(type: Variant, visible_only: bool = true, root_node: Node = null) -> Array[Node]
Returns an Array of all Nodes found that match the type.
- Parameters are identical to
find_node_by_type.
static func get_main_scene_of_viewport(obj: Node) -> Node
Finds and returns the root scene node to which obj belongs, even if it's inside a SubViewport.
# --- Type-Based Examples ---
# Example 1: Find the Player node, wherever it is
var player_node: Player = SearchObjectByType.find_node_by_type(Player)
if player_node:
player_node.heal(10)
# Example 2: Find all visible enemies in the entire scene
var all_enemies: Array[Node] = SearchObjectByType.find_nodes_by_type(Enemy, true)
for enemy in all_enemies:
print(enemy.name)
# Example 3: Find the first "Item" node, but only inside the "Inventory" container
var inventory_node: Node = $UI/Inventory
var first_item: Item = SearchObjectByType.find_node_by_type(Item, true, inventory_node)
if first_item:
first_item.use()
# --- Filter-Based Examples (Advanced) ---
# Example 4: Find all enemies in the "zombies" group with low health
var filter_func := func(node: Node):
return (
node is Enemy and
node.is_in_group("zombies") and
node.health < 20
)
var low_health_zombies: Array[Node] = SearchObjectByType.find_nodes_by_filter(filter_func)
for zombie: Enemy in low_health_zombies:
zombie.start_fleeing()
# Example 5: Find a specific button by its name
var start_button: Button = SearchObjectByType.find_node_by_filter(
func(node: Node):
return node is Button and node.name == "StartButton"
)
if start_button:
start_button.grab_focus()
# --- Utility Example ---
# Example 6: Get the root node of the current scene (even if inside a SubViewport)
var my_scene_root: Node = SearchObjectByType.get_main_scene_of_viewport(self)
print(my_scene_root.name)This tool is excellent for breaking hard-coded get_node paths. A UI scene can find the Player node to read its health without needing a fragile path like get_node("../../World/Player").
func _process(delta):
var player = SearchObjectByType.find_node_by_type(Player)
if player:
value = player.healthWhen you receive a network packet, you often need to find a local node (like an enemy or player) based on an ID or other data. The filter functions are perfect for this.
func _on_packet_received(data: Dictionary):
if data.type == "enemy_update":
# Find the specific enemy this packet is for using its network ID
var filter = func(node: Node):
return node is Enemy and node.network_id == data.id
var enemy_node: Enemy = SearchObjectByType.find_node_by_filter(filter)
# Now that we've found the node, we can apply the networked data
if enemy_node:
enemy_node.global_position = data.positionFor more detailed examples, check out the example scenes included in this repository. You can load and run these scenes in Godot to see SearchObjectByType in action.
- The
typeparameter is aVariantand can be aclass_name(e.g.,Player), aStringName(e.g.,"Player"), or aScriptobject (e.g.,preload("res://player.gd")). - The
visible_onlyfilter is safe. It correctly checksis_visible_in_tree()forCanvasItemandNode3Dnodes. Non-visual nodes (likeTimer) are considered "visible" by default.
This asset is provided under the MIT License.