Functions, Lambdas & Callables
Static functions cannot access instance members (no self), but can use static variables.
12.1 Defining functions
Parameters can have type hints and default values (defaults must come last).
Return type with ->; -> void for no value. Functions without return return null.
There is no function overloading; use default arguments or different names.
Functions starting with _ are a convention for private or engine virtual methods.
func greet(name: String, greeting: String = "Hello") -> String:
return "%s, %s!" % [greeting, name]
func _ready() -> void:
print(greet("Ada")) # Hello, Ada!
print(greet("Linus", "Hi")) # Hi, Linus!12.2 Static functions
Static functions cannot access instance members (no self), but can use static variables.
class_name MathUtils
static func clamp_length(v: Vector2, max_len: float) -> Vector2:
return v.limit_length(max_len)
# elsewhere:
var v := MathUtils.clamp_length(input, 10.0)12.3 Lambdas (anonymous functions)
Captures: lambdas capture local variables by value at creation time. Reassigning a captured local inside the lambda doesn't change the outer variable — but mutating a captured Array/Dictionary/Object does affect the shared instance:
var double := func(x: int) -> int: return x * 2
print(double.call(4)) # 8
var greet_lambda := func(name):
print("Hi ", name)
return name.length()
$Button.pressed.connect(func(): print("clicked"))
# Named lambda (for recursion and stack traces)
var factorial := func fact(n: int) -> int:
return 1 if n <= 1 else n * fact.call(n - 1)var count := 0
var counter := {"n": 0}
var inc := func():
count += 1 # modifies the lambda's copy only
counter.n += 1 # modifies the shared dictionary
inc.call(); inc.call()
print(count, " ", counter.n) # 0 212.4 Callables
func say(text: String, times: int) -> void:
for i in times: print(text)
func _ready() -> void:
var c := Callable(self, "say") # or simply: var c := say
c.call("hi", 2)
c.callv(["hey", 1]) # arguments as array
var bound := say.bind(3) # bound args are appended at the end
bound.call("yo") # say("yo", 3)
say.call_deferred("later", 1) # run at the end of the current frame (idle time)
print(c.get_method(), c.is_valid())
var no_args := say.bind("x", 1).unbind(2) # ignore 2 incoming args (useful for signals)12.5 Variadic functions (4.5+)
Godot 4.5 added rest parameters:
On earlier versions, accept an Array parameter (sum([1, 2, 3])) or use callv(). Built-in functions like print(), str(), and max() have always been variadic.
func sum(...numbers: Array) -> float:
var total := 0.0
for n in numbers:
total += n
return total
func _ready() -> void:
print(sum(1, 2, 3.5)) # 6.512.6 Recursion and early return
func count_nodes(node: Node) -> int:
var total := 1
for child in node.get_children():
total += count_nodes(child)
return total12.7 Built-in global functions you'll use constantly
print, push_error, push_warning, assert Output & checks load, preload is_instance_valid, instance_from_id
str, int, float, bool, type_string, typeof range, len
randf, randi, randf_range, randi_range, randfn min, max, clamp, lerp, abs, sign, snapped
🧪 Part I Exercises
Install Godot 4, create a project with the Compatibility renderer, and make a scene with a Sprite2D that rotates and moves in a circle using _process(delta).
Write a script that prints every node in the current scene with indentation showing depth (use recursion over get_children()).
Declare a named enum Weapon { SWORD, BOW, STAFF }, export a variable of that type, and print its name with Weapon.find_key().
Write a fully statically typed function average(values: Array[float]) -> float; enable the UNTYPED_DECLARATION warning as an error and fix all warnings.
Format a string showing a player's name, level, and HP with two decimal places using both % and format().
Given an array of 20 random ints, use filter, map, and reduce to compute the sum of squares of the odd numbers.
Build an inventory as a typed Dictionary[String, int] (or untyped on 4.3); write add_item, remove_item, and print_inventory functions.
Write a match statement that parses command dictionaries like {"cmd": "move", "dir": "left"} and {"cmd": "say", "text": "hi"}.
Write a lambda-based counter generator that returns a dictionary of callables inc, dec, and get that share state.
Use Vector2.direction_to() and move_toward() to make a sprite follow the mouse (get_global_mouse_position()) at a constant speed, stopping exactly on the cursor.