See all cheatsheets

Nodes, scenes, and signals

Nodes, scenes, and signals cheatsheet

This cheatsheet recaps many of the key concepts you need to know to work with nodes, scenes, and signals in Godot. You can learn about these essential concepts hands-on in Learn 2D Gamedev From Zero with Godot 4.
If you have feedback on this page, found a typo, or have a question, please contact us!
If you find any issue or typo, have feedback about this cheatsheet, or have a question about GDScript that's not covered here, we're always looking to improve and help. Please get in touch with us anytime via email or join our Discord community. We'll do our best to help you and use your feedback to improve the cheatsheet for everyone!
  • A node is like a Lego piece

    Nodes are small building blocks of Godot games, each with a unique purpose:
    • The AudioStreamPlayer node plays sounds.
    • The AnimationPlayer plays animations.
    • The Sprite2D node displays a sprite.
    • The Button node creates a clickable button.
    There are many types of nodes, and you can create your own by extending existing ones. Nodes are the equivalent of a game object with one or more components attached in an engine like Unity, depending on the node's type.
    In Godot, instead of having the separation between an object and its components to define functionality, you have a simpler system where a node has a specific purpose and all the required functionality is built into it.
  • Nodes form a tree

    In Godot, nodes are organized in a tree structure. Each node can have any number of children, and each child can have its own children. This structure is called the scene tree.
    A Godot game is a collection of nodes organized in a tree. The root node is the topmost node in the tree, a viewport automatically created by Godot, and all other nodes are its children or their descendants.
  • We assemble game entities using multiple nodes

    Just like you plug individual Legos into one another to create more complex pieces, you assemble game entities like characters, chests, collectibles, and more using multiple nodes.
    Here's an example of a simple 2D character composed of multiple nodes:
    • The CharacterBody2D node moves and detects collisions with the environment.
    • The CollisionShape2D node defines the character's collision shape and how it interacts with the environment.
    • The Sprite2D node displays the character's visual representation.
    • The AnimationPlayer node plays animations for the character.
  • Scripts give behavior to nodes

    By itself, a node is generally a static object. To give it behavior, you attach a script to it. The script contains the code that defines how the node behaves and interacts with other nodes in the scene.
    For example, you can attach a script to a Player node to define how the player moves, jumps, and interacts with the environment. The script can handle player input, control when to play animations, sounds, and define other game logic.
    The script code runs on the node to which it's attached. It can access the node's properties, methods, and signals, as well as other nodes in the scene.
  • A scene is a template composed of nodes, scripts, and resources

    You can save a hierarchy of nodes, scripts, and other resources into a file called a scene. A scene is a template you can reuse in your game to create multiple instances (copies) of the same entity.
    When you drag and drop a scene file into another scene in the Godot editor, you create an instance of that scene. The instance is a copy of the scene you can place in the game world and interact with at runtime. In the Scene dock, a scene instance looks like a single node, but it's a collection of nodes and resources. In code and in the editor, you can interact with scene instances as if they were a node: they work as a single entity.
  • Child nodes move with their parent

    When you move a parent node in the game world, all its children move with it by default. The position of child nodes is relative to their parent. If you move a parent node, all its children move with it, maintaining their relative positions.
    You can disable this behavior by toggling the Top Level property in the editor. When you set a node as top-level, it behaves as if it were a direct child of the root node, so it draws and moves independently of its parent.
  • Getting references to other nodes

    A script has access to the node to which it is attached. All the code you write in the script runs on that node. To run code on other nodes from a script, you first need to get a reference to them in code.
    You use the get_node() function to get a reference to a node. The function takes one argument: the path to the node you want to get. The path is the names of the child nodes separated by forward slashes (/).
    In the following example, the Player node has the script attached. The hitbox is a direct child of the node so the path to the hitbox is HitBox3D. The Camera3D node is a child of the Pivot node so the path to it is Pivot/Camera3D.
    func _ready() -> void:
    	var hitbox: Area3D = get_node("HitBox3D")
    	var camera: Camera3D = get_node("Pivot/Camera3D")
    
    Why are you getting nodes in the _ready() function?
    The _ready() function is called when the node and all its children were added to the scene tree and their _ready() function was called, meaning they are ready to be used. It's a good place to get references to other nodes because you're sure they exist.
    You can learn more about the _ready() function and how nodes are created in the study guide Node creation and the ready function.
    What is this colon for in the code?
    It's a type hint. It tells Godot the type of the variable. It's optional but recommended because it helps you catch errors early and makes your code easier to read. You can learn more about types and type hints in the GDScript cheatsheet.
  • Getting other nodes with the dollar sign

    Because we need to get nodes all the time in Godot, there is a shortcut to the get_node() function in GDScript: the dollar sign ($). You can write node paths after the dollar sign without quotes. The following function calls are equivalent. First, with get_node():
    func _ready() -> void:
    	var hitbox: Area3D = get_node("HitBox3D")
    	var camera: Camera3D = get_node("Pivot/Camera3D")
    
    And now with the dollar sign:
    func _ready() -> void:
    	var hitbox: Area3D = $HitBox3D
    	var camera: Camera3D = $Pivot/Camera3D
    
    What if there are spaces in the node name?
    If a node has spaces in its name, you can write the node path in quotes after the dollar sign. For example, if you have a node named Player Healthbar, you can get it with $"Player Healthbar".
  • Marking nodes as having unique names

    Referencing node by paths means that when you move a node in a scene, you need to go update the path in calls to get_node() in your code. To limit this problem, you can mark nodes as having a unique name in a scene. You can then reference the node using only its name in a script used within the same scene, regardless of where the node is in the scene tree.
    To mark a node as having a unique name, right click on it and select Access as Unique Name in the dropdown menu. A percent sign appears next to the node in the Scene dock to indicate it has a unique name. You can then reference the node using the percent sign in your script:
    func _ready() -> void:
    	var camera: Camera3D = %Camera3D
    
    This only works within a scene. You cannot use the percent sign to get a unique node on a scene instance from a script outside that scene.
    This method improves performance
    This feature improves performance when getting nodes frequently in complex scenes as Godot caches the reference under the hood. The more deeply nested the node is in the scene, the greater the performance benefit is compared to getting the node by path.
    The fastest way to access node references is to store them in a member variable though.
  • Storing references to nodes in onready variables

    A very common pattern with GDScript in Godot is storing references to nodes at the top of your scripts in "onready" variables for maximum access performance:
    @onready var hitbox: Area3D = $HitBox3D
    @onready var camera: Camera3D = $Pivot/Camera3D
    
    Variables marked with @onready are initialized right before the _ready() function call. Using the @onready annotation is a shorthand for defining empty member variables and calling get_node() at the top of _ready() function:
    var hitbox: Area3D
    var camera: Camera3D
    
    func _ready() -> void:
    	hitbox = $HitBox3D
    	camera = $Pivot/Camera3D
    
    With onready variables, you can access the nodes through the variables throughout the script.
    The main advantage of this approach is that at a glance, you can see at the top of the script which nodes are used in the script. Storing node references in onready variables also provides the best performance when accessing nodes in the script. The performance cost of getting references to nodes in simple projects is negligible, but in very complex projects it can add up.
  • Exported node references

    A good alternative to storing node references in onready variables is to export them as variables in the script. You can then set the node references in the editor, making it easier to configure the script for different scenes or instances.
    To export a node reference, you need to add the @export annotation before the variable declaration. You can then set the node reference in the inspector:
    @export var hitbox: Area3D
    @export var camera: Camera3D
    
    When you export a node reference, you can pick the node interactively in the Inspector. When you move or rename the node in the scene, the editor automatically updates the reference in the inspector.
    Should I always use this approach for getting references to nodes?
    Exported variables are a really good approach for getting nodes with a small trade-off: often, we need node references on the root node of a scene. So when creating scene instances, the inspector has the full list of exported node variables exposed.
    This approach doesn't automatically make it clear when a node reference is really meant to be changed on scene instances by teammates or when it's used as a mechanism internal to the scene for referencing child nodes.
    It's up to you to decide if that's fine by you or not. At GDQuest, we favor the scene unique name option and onready variables at the top of our scripts. This way, when we export node references it is clear that it is always a property you need to configure on the scene instance. But that's a personal preference and both approaches are about as good.
  • Getting the current node

    You never need to get a reference to the node a script is attached to. Code implicitly runs on the node to which the script is attached. So you never need to call get_node() for it.
    Writing get_node(".").position, which asks Godot to get the current node and then its position, has the same effect as writing just position, with an unnecessary performance cost.
  • Getting nodes with absolute paths

    You can get a reference to any node in the game using its absolute path in the scene tree. The absolute path is the path from the root node to the node you want to get. It starts with a forward slash (/) followed by root, the name of the root node, and then the names of the child nodes separated by forward slashes.
    You can call the get_node_or_null() function to get a reference to a node using its absolute path safely. The function returns null if the node doesn't exist.
    func _ready() -> void:
    	var hitbox: Area3D = get_node_or_null("/root/Player/HitBox3D")
    
    When should I use absolute paths?
    You may use absolute paths when you absolutely need to get a reference to a node in a separate node branch and you know for sure you will not change the scene structure. I'd say this technique can be useful in game jams or when prototyping, when you want to go as fast as possible.
    In larger projects, a good pattern to consider is the service locator pattern, which is trivial to implement in Godot. You can have an autoload singleton that holds references to all the nodes you need to access from anywhere in the game. This way, you can avoid using absolute paths and have a single place to manage all your node references.
  • Getting the parent node

    You can get a reference to the parent node of a node using the get_parent() function. The function returns the parent of the node on which it's called.
    It's useful for cases where a child node needs to communicate with its parent or when you need to access a sibling node of the parent node.
    func _ready() -> void:
    	var parent_node := get_parent()
    	var siblings := parent_node.get_children()
    
    When should I use get_parent()?
    Generally the guideline in Godot is to favor accessing nodes going down the scene tree rather than up. This way, nodes have a consistent control flow. But getting the parent node is sometimes necessary.
    For example, we made an addon to draw physics shapes in games for debugging purposes, and the debug drawing nodes are children of the collision nodes. In this case, we need to get the parent node to find what to draw.
    func _autodetect_shape() -> void:
    	var parent := get_parent() as CollisionShape
    	assert(has_valid_parent(), "Parent at '%s' isn't a valid CollisionShape" % [parent.get_path()])
    	if parent.shape is SphereShape:
    		shape_type = ShapeType.SPHERE
    		shape_size = Vector3(parent.shape.radius, parent.shape.radius, parent.shape.radius)
    	elif parent.shape is BoxShape:
    		shape_type = ShapeType.BOX
    		shape_size = parent.shape.extents
    	elif parent.shape is CapsuleShape:
    		shape_type = ShapeType.CAPSULE
    		shape_size = Vector3(parent.shape.radius, parent.shape.height, parent.shape.radius)
    	else:
    		push_error("Shape '%s' at '%s' isn't a supported shape" % [parent.shape, parent.get_path()])
    
  • Adding a node as a sibling

    To add a node as a sibling of a scene instance, from the scene's script, you can call the add_sibling() function as a shorthand for get_parent().add_child(node). This can be useful for mechanics like spawning items from a chest.
    # Items get set in the inspector.
    @export var items: Array[PackedScene] = []
    
    func spawn_items() -> void:
    	for item: PackedScene in items:
    		var new_item: Item = item.instance()
    		add_sibling(new_item)
    		new_item.global_position = global_position + Vector2(rand_range(-50, 50), rand_range(-50, 50))
    
  • Tagging nodes with groups

    Godot has a tagging system called "groups." You can assign one or more groups to a node in the editor or via code. Then, you can find all nodes with a given group at runtime.
    To assign a group to a node in the editor, select the node, go to the Node dock, click the Groups sub-tab, and add the name in the Groups section.
  • Defining global groups

    Starting in Godot 4.3, you can define global groups in the Project Settings under the Global Groups tab. Every group you define here is available in every scene in your project. New group names added directly in a given scene in the Node dock are local to that scene.
  • Finding all nodes in a group in code

    You can find all nodes in a group using the method SceneTree.get_nodes_in_group(). It takes the group name as an argument and returns an array of nodes in that group.
    Here's an example of how you could create an item that kills all mobs on the screen:
    func kill_all_mobs_on_screen() -> void:
    	var screen_rect := get_viewport().get_visible_rect()
    
    	var mobs := get_tree().get_nodes_in_group("mobs")
    	for mob: Mob in mobs:
    		if screen_rect.has_point(mob.global_position):
    			mob.die()
    
  • Adding nodes from groups in code

    You can add nodes to a group in code using the Node.add_to_group() method. The method takes the group name as an argument and adds the node to the group.
    func _ready() -> void:
    	add_to_group("mobs")
    
    When should I add nodes to groups in code as opposed to the editor?
    Adding nodes to groups in code is useful when you need to add and remove nodes to groups dynamically at runtime. For example, you might have chickens in your game that turn into mobs when they get angry. You can add them to the "mobs" group when they get angry and remove them when they calm down.
    It's also useful to add nodes to groups in code if you want to use constants to track group names and avoid typos. For example, imagine a game where you have a group for all the collectibles in the game. You can define and use a constant in your codebase to add and remove nodes from the group.
    In the groups.gd script:
    class_name Groups
    
    const COLLECTIBLES := "collectibles"
    
    In the collectible.gd script:
    class_name Collectible extends Node2D
    
    func _ready() -> void:
    	add_to_group(Groups.COLLECTIBLES)
    
  • Removing nodes from groups in code

    You can remove nodes from a group in code using the method Node.remove_from_group(). It takes the group name as an argument and removes the node from the group.
    func _ready() -> void:
    	remove_from_group("mobs")
    
  • Packed scene resources

    Godot's scenes are templates for re-creating a hierarchy of nodes and resources. That data is usually saved in a text file with the .tscn extension. You can use this file to create new instances of the scene in the editor or at runtime.
  • Instantiating a scene in the editor

    To create an instance of a scene in the editor, you can drag and drop the scene file from the FileSystem dock into the Scene dock. This creates a new instance of the scene in the scene tree and presents it as a single node with its internal structure hidden. You can also press ctrlshifta to quickly search and instantiate a scene in the editor (shifta on macOS).
    You can then place the instance in the game world, configure it in the Inspector, and interact with it at runtime.
  • Loading scenes with preload

    Before instantiating a scene at runtime, you need to load the scene file into memory. You can use the preload() function to load a scene file as a packed scene resource.
    const PlayerScene := preload("res://player/player.tscn")
    
  • Creating a preload call with Ctrl + click and drag

    In the Godot editor, you can create a preload() call for a resource by holding ctrl (or on macOS) and clicking and dragging the resource from the FileSystem dock into the script.
  • Instantiating scenes in code

    To create an instance of a scene at runtime, you can call the instantiate() method on the loaded packed scene resource. The method creates a new instance of the scene in memory. The instance is a new node that you can add to the scene tree by calling the add_child() method on the desired parent node.
    This code loads the bullet scene, creates an instance of it, and adds it as a child of the current node:
    const BulletScene := preload("bullet.tscn")
    var bullet: Bullet3D = BulletScene.instantiate()
    add_child(bullet)
    
  • Exporting a packed scene variable

    You can export a packed scene variable in a script to assign a scene file to load in the Inspector. To do this, add the @export annotation before the variable declaration and use the PackedScene type hint.
    This is useful to make a script more flexible and configurable in the editor. You can assign different scene files to the variable in the Inspector on different instances without changing the script code.
    @export var enemy_scene: PackedScene
    
  • Exporting an array of packed scenes

    You can export an array of packed scene variables in a script to assign multiple scene files to load in the Inspector. To do this, add the @export annotation before the variable declaration and use the Array[PackedScene] type hint.
    This feature is great for creating spawners, where you can assign multiple scene files to spawn different enemies.
    @export var enemy_scenes: Array[PackedScene]
    
    It's also useful for mechanics like putting multiple collectibles in a chest. Imagine you have a chest scene that loots items when the player interacts with it. You can export an array of packed scenes to assign the items you want the chest to contain in the Inspector.
    @export var contained_items: Array[PackedScene]