Variables, Constants, Enums & Static Typing

Default values: int → 0, float → 0.0, bool → false, String → "", Vector2 → (0, 0), objects → null, Array → [].

6.1 Declaring variables

Dynamic (Variant); any type can be assigned later var x: int = 5 Static type hint

Static, type inferred from the initializer Static, default value (0 for int)

Default values: int → 0, float → 0.0, bool → false, String → "", Vector2 → (0, 0), objects → null, Array → [].

var health = 100              # dynamic: can later hold any type
var player_name: String = "Ada"   # explicit type hint
var speed := 250.0            # inferred type (float) — static, cannot change type
var target: Node2D            # typed, default null
var items: Array[String] = [] # typed array

6.2 Scope

Member variables (declared at the top level of a script) belong to the instance.

Local variables live inside a function or block.

Static variables (4.1+) belong to the class and are shared by all instances:

class_name Enemy
extends CharacterBody2D

static var alive_count := 0

func _ready() -> void:
	Enemy.alive_count += 1

func _exit_tree() -> void:
	Enemy.alive_count -= 1

6.3 Constants

Constants must be known at compile time. Arrays and dictionaries declared const are read-only (Godot 4).

const MAX_SPEED := 600.0
const GRAVITY: float = 980.0
const DIRECTIONS := [Vector2.UP, Vector2.DOWN, Vector2.LEFT, Vector2.RIGHT]
const BulletScene := preload("res://bullet.tscn")   # preload is a constant expression

6.4 Enums

A named enum is a constant Dictionary mapping names to ints, and also a type usable in type hints and @export.

Enum values are ints; cast with state = State.JUMP or state = 2 as State.

Enums declared with class_name are accessible elsewhere: Player.State.RUN.

enum { NORTH, EAST, SOUTH, WEST }        # unnamed: creates constants NORTH=0, EAST=1 ...

enum State { IDLE, RUN, JUMP, FALL }     # named enum
enum Element { FIRE = 1, WATER = 2, EARTH = 4, AIR = 8 }

var state: State = State.IDLE

func _ready() -> void:
	print(State.RUN)                     # 1
	print(State.keys())                  # ["IDLE", "RUN", "JUMP", "FALL"]
	print(State.find_key(state))         # "IDLE"
	print(State.size())                  # 4
	for s in State.values():
		print(s)

6.5 Static typing in depth

Static typing gives you:

Errors at compile time instead of runtime crashes.

Better autocompletion.

Faster execution (typed instructions; no runtime type checks for many operations).

Error if a non-int is assigned (ints convert to float automatically for float) var a:= 1.5 Type fixed to float func f() -> int: -> void for none

Objects: returns null on failure; built-ins: converts or errors Works for built-ins, classes, scripts

Array[int], Dictionary[String, int] (4.4+) Elements checked on insert

The editor marks type-safe lines with a green line number. In *Project Settings → Debug → GDScript* you can turn warnings like UNTYPED_DECLARATION, UNSAFE_PROPERTY_ACCESS, and UNSAFE_METHOD_ACCESS into errors to enforce fully typed code.

Godot 3 note: static typing arrived in 3.1; := and typed arrays exist in 4.x only in their current form (3.x had no typed arrays).

func heal(amount: int) -> void:
	health = min(health + amount, max_health)

func get_direction() -> Vector2:
	return Input.get_vector("left", "right", "up", "down")

var enemy := $Enemy as CharacterBody2D       # cast; null if the node is not that type
if body is Enemy:                            # type check (works with class_name)
	(body as Enemy).take_damage(10)

6.6 null and Variant

Variant is the universal type that can hold any value. Untyped variables are Variants. null is the "no value" value; accessing a member on null is a runtime error:

is_instance_valid(obj) also detects objects that were freed (a freed object is not automatically null).

var target: Node2D = null
if target != null and is_instance_valid(target):
	look_at(target.global_position)