Go, Go, Godot!
  • 0

Ditch @onready, use @export instead

April 20, 2024

Are you using @onready to reference nodes? There’s a better way!

Here’s a simple example of how many tutorials use @onready to reference nodes:

extends CanvasLayer


const DEFAULT_HEALTH = 100


func _ready():
	$HealthBar.value = DEFAULT_HEALTH
	
	
	

That script is attached to a CanvasLayer node with a ProgressBar called HealthBar. And yet, when running the scene, it will throw an error:

This is because there’s actually a spelling error; instead of HealthBar, the node is called HeatlhBar. It’s easy to miss, and we all occasionally make spelling errors.

Since you can easily drag nodes into scripts and create @onready references by holding down CTRL before releasing the mouse button, another version of the script might look like this:

extends CanvasLayer


const DEFAULT_HEALTH = 100

@onready var heatlh_bar = $HeatlhBar

func _ready():
	heatlh_bar.value = DEFAULT_HEALTH

Now it works, because it’s consistently misspelled.

If you now notice the misspelling in the Scene Tree and fix the node name, but don’t adjust the script, it’ll break again:

A better way is to use @export instead:

extends CanvasLayer


const DEFAULT_HEALTH = 100.0

@export var health_bar: ProgressBar


func _ready():
	health_bar.value = DEFAULT_HEALTH

With the script in place, the health_bar node can be assigned via the Inspector:

Initially, this may seem like a bit more work, to first have to declare it and then assign it, but it is the most reliable, flexible solution to referencing nodes. You can even rename the HealthBar node, and the health_bar node reference will update accordingly.

This approach is especially helpful when building complex user interfaces where you might rearrange nodes a lot. One concern is having a long list of export properties, some of which are actually used to reference nodes internal to the scene. That’s why I typically group them with @export_group :

extends CanvasLayer


@export_range(10, 100, 0.1) var default_health = 100.0

@export_group("Internal")

@export var health_bar: ProgressBar


func _ready():
	health_bar.value = DEFAULT_HEALTH

That way, it’s clear in the inspector which properties are meant to be modified from outside the scene:

In addition, this separation between script and scene is a form of dependency injection that provides greater flexibility, so a script can be attached to a scene that has a completely different layout.

I’ve been using this technique almost exclusively, and rarely use @onready to assign a node reference via $ or get_node() .

developer experiencegdscriptgodotprogramming
Posted in DX, Godot.
Share
PreviousInventory System v1.13 available
NextInventory System v1.12 available

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Related Posts

  • December 23, 2023

    godot-matcha: Free multiplayer without a server

    Godot-matcha is an addon that lets you use WebRTC for multiplayer games by handling matchmaking using WebTorrent trackers. Conceptually it’s quite an interesting, novel approach. WebTorrent uses a modified BitTorrent protocol that allows it to work with WebSockets. A WebTorrent tracker is essentially a directory service that keeps track of torrents offered by users. A …

  • February 15, 2024

    Inventory System v1.8 available

    The latest version includes a few new enhancements, and an experiment: The sequencer demo uses inventory instances to hold music notes, which can be played back. This was inspired by music trackers that were popular in the 90s, such as Scream Tracker and Impulse Tracker. The sequencer isn’t meant to be a production-ready digital audio …

  • Godot Game Engine Logo
    June 1, 2023

    Godot Engine 4.1.dev4 is available

    Development snapshot #4 of Godot Engine 4.1 is here. Among many other changes, it fixes a lighting issue related to using Light-only mode in CanvasItemMaterial (#44559). Unfortunately, it also introduced a UX issue with gradient color pickers (#77745), which makes it quite difficult to work with gradients at all. If you use gradients, I recommend …

  • February 18, 2024

    Inventory System v1.9 available

    Another quick inventory system update. The Resizable Container Demo now includes preliminary support for controllers. Features: Additional bug fixes:

    © 2025 GoGoGodot.io. All rights reserved.