See all cheatsheets

GDScript cheatsheet

GDScript cheatsheet

This cheatsheet recaps all the key points to know about the GDScript programming language and its syntax in Godot 4, organized by category. It's a living reference you can search and use to quickly find the information you need when coding in GDScript.
It's designed for two types of people:
  1. Beginners who learned GDScript with other resources like Learn GDScript From Zero and who need a reference to look up the syntax and concepts. You can use the search bar at the top to find the information you need.
  2. Experienced programmers who want to learn GDScript quickly. If you know how to program, you can read this cheatsheet from top to bottom to learn GDScript in one sitting.
Bookmark this page to look up key aspects of GDScript anytime!
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!
  • GDScript is a game scripting language

    GDSript is a high-level, gradually typed, interpreted programming language designed for game development. It's one of two official scripting languages for the Godot game engine, the other being C#. GDScript is the most popular choice for Godot developers because it's easy to learn and use, and it's tightly integrated with the engine as it's part of it.
  • GDScript is a C-family language

    GDScript is an imperative and object-oriented game scripting language inspired primarily by Squirrel, another game scripting language. The base concepts of GDScript are similar to those of other C-family languages like C++ and C#, so if you know one of these languages, it only takes a little time to get used to GDScript. GDScript is designed to be faster to learn and easier to use.
  • GDScript was made to avoid the pitfalls of third-party languages

    Various older versions of Godot integrated Python and then Lua as scripting languages. However, the integration cost, lack of control over the language, difficulties supporting certain platforms, and the lack of a good multithreading model led to the creation of GDScript. GDScript was designed to give the Godot developers full control over the language, and because it's embedded in the engine, it automatically supports all the engine's features and works on every platform.
    Note that Godot also officially supports C# as a scripting language, which is a good alternative if you're already familiar with it.
  • A GDScript file is a component

    In Godot, a GDScript file is a component that you attach to a node. The GDScript file defines the behavior of the node to which it's attached.
    This has one important consequence: all the code you write implicitly runs on the node or object the GDScript file is attached to. So, unlike in languages like Python or JavaScript, you rarely need to use keywords like this or self to refer to the object you're working with. In GDScript, when you write position, you're implicitly referring to the position property of the object to which the script file is attached.
    Note that you can attach a single script file to a given node.
  • A GDScript file is a class

    Every GDScript file is implicitly a class definition. This has two consequences:
    1. A GDScript file can only define variables, constants, methods, functions, and subclasses. You cannot write most instructions outside of a function.
    2. Even if you don't explicitly inherit from an engine class, the GDScript file implicitly inherits from the RefCounted class in the Godot engine, which does reference-counted memory management for you.
    Can I do my own memory management in GDScript?
    Yes, sure! You can explicitly extend the Object class to manage memory yourself. If you have very specific memory requirements and you know what you're doing, this gives you more control over memory management.
    Though, in general, for more fine-grained control over memory and performance, we recommend using C or C++ with Godot with the GDExtension API.
  • Single-line comments

    You can write single-line comments by starting a line with a # character. The computer ignores comments, so they are useful to document your code. You'll see comments used in this cheatsheet!
    # This is a single-line comment. The computer ignores this line.
    
  • Multi-line comments

    There's no special syntax for multi-line comments in GDScript. You can write multiple single-line comments to achieve the same effect.
    # This is a multi-line comment.
    # It's made of multiple single-line comments!
    
  • Documentation comments

    Godot and GDScript have a built-in documentation system that uses special comments to document your code. These comments start with two hash signs, ##, and are called documentation comments, documentation strings, or docstrings for short.
    ## This is a documentation comment. Godot will generate a documentation page for GDScript files based on these comments.
    ## You can find the generated documentation by going to Help -> Search Help... in the Godot editor.
    var my_variable := 100
    
    This code produces the following documentation page:
    Generated documentation page
  • Defining a variable

    To define a variable, use the var keyword followed by the variable name. This declares a dynamically typed variable: you can assign any value to it later.
    # This defines a variable named `character` with no initial value. Its value is 'null'.
    var character
    
    # This defines a variable named `health` with an initial value of 100.
    var health = 100
    
  • Setting the type of a variable

    You can set the type of a variable by adding a colon : followed by the type name when you define a variable. This is called static typing.
    var health: int = 100
    var display_name: String = "Player"
    
    If you keep the colon but don't specify a type, GDScript will infer the type from the value you assign to the variable. This code has the same effect as the previous one:
    var health := 100
    var display_name := "Player"
    
  • Assigning values to variables

    You can assign a value to a variable using the = operator. You can do it when you define the variable or later in your code. This line assigns the value 100 to the variable health when defining it:
    var health := 100
    
    You can also assign a value to an existing variable, but only inside a method or a function:
    func heal(amount: int) -> void:
    	health += amount
    
  • Why use types

    GDScript supports optional static types. Static typing helps to document code, catch errors early, and improve autocompletion and performance. Statically-typed GDScript code runs up to twice as fast compared to dynamic code.
  • Defining a constant

    To define a constant, use the const keyword followed by the constant name and its value. You cannot assign new values to constants, so you must initialize them when declaring them.
    const MAX_HEALTH := 100
    const SPEED := 1000.0
    
    Constants in GDScript can store any value, even one mutable like an array. The value needs to be known at compile time, so you can't assign the result of a call to load(), get_node(), or something like this to a constant. You have to use constant expressions. Here are two more examples:
    const BOARD_SIZE := Vector2i(10, 10)
    const PLAYER_NAMES := ["Gobot", "Sophia", "GDBot"]
    
    Does this mean I can add values to a constant array?
    Yes, you can call the append() method on a constant array, which adds a value to the array. What you cannot do is assign a new value to a constant.
    So, the following code is valid:
    func _ready() -> void:
     const PLAYER_NAMES := ["Gobot", "Sophia"]
     PLAYER_NAMES.append("GDBot")
    
    But the following code is not valid:
    func _ready() -> void:
     const PLAYER_NAMES := ["Gobot", "Sophia"]
     PLAYER_NAMES = ["Gobot", "Sophia", "GDBot"]
    
  • Variable scope

    Variables have a limited scope. In GDScript, you can define variables at the top level of a script, inside a function, or inside a block of code:
    1. Variables defined at the top level are properties of the script and are accessible anywhere in the script and from other scripts.
    2. Variables defined inside a function are local to that function and accessible only inside it.
    3. Variables defined inside a code block are local to that block and only accessible inside it.
    # These properties are accessible anywhere in the script
    # and from other scripts.
    var health := 100
    var armor := 5
    
    func take_damage(base_amount: int) -> void:
    	# This variable is local to the function and is only accessible inside it.
    	var calculated_damage := base_amount - armor
    	if calculated_damage > 0:
    		health -= calculated_damage
    		play_damage_animation()
    
  • Static variables

    You can define static variables using the static keyword. The data assigned to these variables is shared by and accessible to all instances. Static variables are useful to store data that should be shared among all class instances, like a counter of the number of instances created.
    static var spawn_mob_count := 0
    
    func _ready() -> void:
    	# Lower the count when a mob exits the scene.
    	tree_exited.connect(func (): spawn_mob_count -= 1)
    
    func spawn() -> void:
    	spawn_mob_count += 1
    	# ...
    
  • Defining constants

    You can define a constant using the const keyword. This keyword is similar to var, but it's used for values that shouldn't change at runtime. Constants are immutable and must be initialized when declared.
    const MAX_HEALTH := 100
    const MAX_SPEED := 1000.0
    
    Constants are always statically typed, even if you omit the colon. However, we often include the colon for consistency with other statically-typed variables.
  • Defining local constants

    You can define constants inside functions or code blocks to give them a limited scope, just like variables. This is useful when you want to name a value that shouldn't change but is only relevant to a specific part of your code.
    This example defines a constant that represents a maximum iteration count for a loop:
    func find_free_position() -> Vector2:
    	const MAX_ATTEMPT_COUNT := 100
    
    	var free_position := Vector2.INF
    	for i in MAX_ATTEMPT_COUNT:
    		# ... try to find a free position.
    	return free_position
    
  • Built-in value types

    GDScript has many built-in value types that you can use to store data. Some basic types include:
    • int: A whole number (an integer). It's a 64-bit signed integer supporting values from -2^63 to 2^63 - 1.
    • float: A floating-point number. It's a 64-bit double-precision floating-point number.
    • bool: A boolean value that can be either true or false.
    • String: A sequence of characters.
    • Array: A dynamic array storing any data type.
    • Dictionary: A collection of key-value pairs.
    There are many types specific to game development, like Vector2, Vector3, Color, Rect2, Basis, Transform2D, or Transform3D, to name a few.
  • The Variant type

    At the core of Godot is the Variant type. It is the equivalent of any in some other programming languages. It's a type that can represent and store any of Godot's core value types: int, float, String, Vector2, Vector3, Array, Dictionary, objects, and more.
    It is the default type of dynamic variables in GDScript and the underlying mechanism for storing any type of data in a single variable.
    var example_variant = 100
    
    func _ready() -> void:
    	example_variant = "Hello, world!"
    
    You can find the full list of types supported by Variant in the Godot documentation.
  • Defining a new type globally

    You can define a new type in GDScript by creating a new class. To do this, you use the class_name keyword followed by the name of the class. You can then define properties, methods, and signals in the class.
    class_name Player2D extends CharacterBody2D
    
    signal health_changed(new_health: int)
    
    var max_speed := 600.0
    var jump_power := 1000.0
    
    func _ready() -> void:
    	# ...
    
    You can write the extends keyword after the class name or on a separate line to specify the class the script inherits from. In this example, the Player class inherits from CharacterBody2D.
    You can then use the new type throughout your project like any other built-in type and get full auto-completion for it. If you extend a node class, your class will also show up in the node creation dialog in the Godot editor.
  • Defining a type locally

    You can define a new type locally in a script file by preloading another script file. This is useful when you want to define a type that's only relevant to a specific script. We often use this pattern in plugins to avoid polluting the global namespace.
    # Defines the type Bullet3D locally in the script.
    const Bullet3D := preload("projectiles/bullet_3d.gd")
    
    @export var bullet_scene := preload("projectiles/rifle_bullet.tscn")
    
    func shoot_bullet() -> void:
    	# We can use the Bullet3D type as it's defined above.
    	var bullet: Bullet3D = bullet_scene.instantiate()
    	%BulletSpawningPoint.add_child(bullet)
    
    On top of defining a type locally, this also gives you access to the corresponding class:
    const ThemeUtils := preload("./utils/theme_utils.gd")
    
    func _ready() -> void:
    	theme = ThemeUtils.apply_editor_scale(theme)
    
    This also means that when you preload a script, it simultaneously becomes a type definition, a reference to the corresponding class, and a loaded script resource.
  • Circular references

    GDScript supports circular references. You can define a type that refers to itself, and Godot will handle it correctly. This is useful when you want to define a recursive data structure like a tree or a graph.
    Types can also reference each other in a circular way. This is useful when you have two types that need to know about each other like a StateMachine that contains State objects, and each State object needs to know about the StateMachine it belongs to request a state change.
    Here's an example of a state machine and state class definitions, starting with the state machine.
    # In the finite_state_machine.gd script.
    class_name StateMachine
    
    enum States { Idle, Run, Jump, ... }
    
    var current_state: State = null
    # ...
    
    func change_state(new_state: State) -> void:
    	# ...
    
    The State class references the StateMachine class:
    class_name State
    
    var state_machine: StateMachine = null
    
    func update(delta: float) -> void:
    	# ...
    
    Finally, a RunState class inherits from the State class and controls the character's running state. When the player presses jump, the state can directly request a state change:
    class_name RunState extends State
    
    func update(delta: float) -> void:
    	# ...
    	if Input.is_action_pressed("jump"):
    		state_machine.change_state(state_machine.States.Jump)
    
    This example is a straightforward way to write a state machine using circular references that can do the job for small games.
  • Converting values between types

    You can convert a value from one type to another with type conversion functions:
    • str(): Converts a value to a String, calling an object's to_string() method if it exists.
    • int(): Creates an integer from a boolean, string, or float, truncating the decimal part. For strings, it tries to parse a number from the beginning of the string.
    • float(): Converts a number or a string to a floating-point number. For strings, it tries to parse a number from the beginning of the string.
    • bool(): Converts a number to a boolean. 0 becomes false, and any other value becomes true.
  • Adding type hints to variables and constants

    You can add type hints to variables by adding a colon : followed by the type name. This is called static typing. It helps document your code, catch errors early, and improve autocompletion and performance.
    var health: int = 100
    var display_name: String = "Player"
    
    If you don't specify a type, GDScript will infer the type from the value you assign to the variable. This code has the same effect as the previous one:
    var health := 100
    var display_name := "Player"
    
    Constants don't require type hints because they're always statically typed. However, you can include the colon for consistency with other statically-typed variables:
    const MAX_HEALTH := 100
    const MAX_SPEED := 1000.0
    
  • Adding type hints to function return values

    You can add type hints to function return values using an arrow -> followed by the type name:
    var strength: int = 10
    var dexterity: int = 15
    var critical_hit_chance: float = 0.5
    
    func calculate_damage() -> int:
    	var damage := strength
    	if randf() < critical_hit_chance:
    		damage *= dexterity / 10.0
    	return damage
    
  • Adding type hints to parameters

    You can add type hints to function and signal parameters by adding a colon : followed by the type name:
    signal health_changed(new_health: int)
    
    var health := 100
    
    func take_damage(amount: int) -> void:
    	health -= amount
    	health_changed.emit(health)
    
    As function parameters can take default values, you can also use type inference for them. In this example, the type of the amount parameter is int:
    func heal(amount := 10) -> void:
    	health += amount
    	health_changed.emit(health)
    
  • Adding type hints to arrays

    You can specify the type of values in an array by adding square brackets [] after the type name. This is useful when you want to ensure that an array only contains values of a specific type.
    var inventory: Array[Item] = []
    var equipped_weapons: Array[Weapon] = []
    
    If you try adding a value of the wrong type to an array with a type hint, Godot will raise an error in the editor.
    Under the hood, the generic GDScript Array type always has a list of Variant values. The type hint is a way to document your code and catch errors early. It doesn't change the behavior of the array at runtime or improve performance.
    Assigning a list of values to a statically typed array
    In Godot 4.2, you cannot always directly assign an array to a statically typed array variable. Because arrays use the Variant type under the hood, many operations that work with arrays produce untyped arrays. For example, this is the case for the Array.map() and Array.filter() methods.
    To assign a list of values to a statically typed array, use the Array.assign() method and pass the new array as an argument. Using the type casting keyword as does not work.
    The example below shows how to filter displayed items in an inventory menu based on the items' category and assign the filtered items to a statically typed array:
    var inventory: Array[Item] = [...]
    var displayed_items: Array[Item] = []
    
    func filter_items(category: String) -> void:
    	var filtered_items := inventory.filter(func (item: Item): return item.category == category)
    	displayed_items.assign(filtered_items)
    	# ...
    
    You cannot assign the filtered items using the as keyword:
    func filter_items(category: String) -> void:
    	# This code will raise an error.
    	displayed_items = inventory.filter(func (item: Item): return item.category == category) as Array[Item]
    	# ...
    
    Future versions of Godot may address this limitation.
    Are there typed arrays that improve performance?
    Yes, there are! Godot provides typed arrays like PackedVector2Array, PackedColorArray, PackedStringArray, and more. These arrays use specific code under the hood to store and operate on values in a more efficient way. They are useful when you need to store a large number of values of the same type and want to improve performance.
    To find all included packed array types, go to HelpSearch Help... in the Godot editor and search for Packed.
    Note that packed arrays have a smaller API compared to regular arrays. They are more efficient but less flexible.
  • Adding type hints to dictionaries

    Unlike arrays, dictionaries don't support static typing in Godot 4.3. You can't specify the type of keys or values in a dictionary yet. Work is in progress to add this feature to a future version of Godot. You can follow it here:
  • Casting values to different types

    You can cast a value to a different type using the as keyword. This is useful to convert a value to a different type without changing the original value.
    This example uses the as keyword to cast a node to a more precise type:
    extends Area3D
    
    var target: Mob3D = null
    
    func find_closest_target() -> void:
    	var overlapping_areas := get_overlapping_areas()
    
    	# We cast the first element of the array to the Mob3D type.
    	var closest := overlapping_areas.front() as Mob3D
    	var closest_distance := global_position.distance_to(closest.global_position)
    
    	for node: Area3D in overlapping_areas:
    		var new_distance := global_position.distance_to(node.global_position)
    		if new_distance < closest_distance:
    			closest = node as Mob3D
    			closest_distance = new_distance
    
  • Creating closures with lambda functions

    When connecting signals, you often need to bind or pass arguments to the function you want to call. You can use lambda functions to create closures that capture variables from the surrounding scope.
    This example is from an RPG project where we want an attack to deal damage after the attack animation finishes:
    const Slash := preload("res://assets/vfx/slash.tscn")
    
    var hit := calculate_hit()
    
    func apply_attack() -> AttackResult:
    	# ...
    	for target: Battler in targets:
    		var slash := Slash.instantiate()
    		add_child(slash)
    		slash.global_position = target.global_position
    		slash.finished.connect(func() -> void:
    			target.take_hit(hit)
    		)
    	# ...
    
    In this code, the lambda function captures the value of the hit member variable and the target variable from the surrounding scope. When the finished signal of the slash node emits, the lambda function calls the take_hit() method on the target with the hit value.