Bite-Sized Godot: Five small GDScript tips


As I work with Godot, I come across a variety of useful tidbits too small to make their own post about, so here’s a few of those items:

Custom string casting with _to_string

By default, when you cast a node or custom class to a string, you tend to get a pretty ugly and unusable output:

extends Node2D

var title: String = 'Player 1'
var health: float = 99.0
var mana: float = 15.0

# Will print something like [Node2D:1920]
func _ready() -> void:
	print(self)

But by overriding the _to_string() function, you can choose what should be returned when the node is cast to a string:

extends Node2D

var title: String = 'Player 1'
var health: float = 99.0
var mana: float = 15.0

# Will print 'Player 1  |  Health: 99  |  Mana: 15'
func _ready() -> void:
	print(self)

func _to_string() -> String:
	return '%s  |  Health: %s  |  Mana: %s' % [title, health, mana]

While you’ll probably want to define a custom function for most player-facing strings, this can be very helpful for debugging your game or even just casually tracking changes to certain elements while playtesting it.

Exporting values to a dropdown

It’s often helpful to have exported variables that come from a fixed set of options, rather than having to manually remember and parse strings or integers. If you have an enumerator containing your values, you can use it as the exported variable type (export (MyEnum) var value). If you want to manually define values, you can use the type of int or string followed by a comma separated list of choices, ie export (int, "Chaotic", "Neutral", "Lawful") var alignment or export (String, "Sara", "Jonathan", "Ashton") var party_member, depending on if you want the value returned to you in code to be an integer or a string.

enum WeaponType {
	Sword,
	Bow,
	Staff
}
export (WeaponType) var weapon

# Will return the string value of the selection
export (String, "Sara", "Jonathan", "Ashton") var party_member

# Will return an integer value, similar to the enumerator above
export (int, "Chaotic", "Neutral", "Lawful") var alignment

Safe lines

Ever noticed that the line numbers in Godot’s built-in script editor aren’t always the same color? That’s due to safe lines, a built-in feature that can detect whether or not a line is type-safe before running your project. If a line number is highlighted, that means Godot is able to reasonably verify that the code on a line matches up with the expected types of the objects being acted upon. If a line isn’t highlighted, that means Godot is unable to verify that everything is type-safe. It doesn’t necessarily mean there’s a problem, just that the line can’t be verified before running the app. You can also help Godot out with this by using as to cast objects of an unclear type.

If desired, you can go into your editor settings to disable / enable this feature or to change the highlight color:

Using underscores to make large numbers more readable

Have some big numbers in you code and wish they were easier to read? Underscores are ignored at compile time for numbers and are a great way to add readability to your code.

extends CenterContainer

var my_big_number = 1_000_000_000_000

func _ready() -> void:
	$Label.text = str(my_big_number)

Snapping / rounding a number to a specific increment using stepify()

And lastly, we have the stepify() function, which let’s you snap a value to a given step. For example, you can use this function to round a float to a certain number of decimal places, or to snap it to the nearest X:

extends CenterContainer

onready var label_top = $VBoxContainer/label_top
onready var label_bottom = $VBoxContainer/label_bottom

func _ready():
	randomize()
	
	# Round to two decimal places
	label_top.text = str(stepify(randf(), 0.01))
	
	# Pick a number between 0 and 100,000 but round the label to the nearest hundred
	label_bottom.text = str(stepify(randf() * 100000, 100))

Conclusion

And that’s a quick look at some handy GDScript tips. Expect more in the future!