GDScript Basics

Godot Fundamentals

Chapter 2 · GDScript Basics

Chapter 1 attached a first script with extends and touched _ready() without explaining GDScript itself. This chapter covers the language properly: variables and typing, the built-in types, functions, and control flow — the same territory a first Python chapter would cover, and for good reason, since GDScript's own syntax was deliberately modeled on Python's.

Coming from Python This whole chapter will feel like a dialect of something you already know rather than a new language. Blocks are still indentation-based, there are still no semicolons or curly braces, and func plays the exact role def does. The differences worth tracking as you go: GDScript adds optional static typing that Python doesn't have (without a separate tool), it has no elif-free equivalent quirks — it actually spells it elif, same as Python — and its match statement (covered below) predates Python's own match by several years, though the two look similar today.

Variables & Type Hints

A variable is declared with var. Like Python, GDScript doesn't require a type at all — but unlike Python, it lets you add one directly, and the editor will then catch a type mismatch before you ever run the game.

# No type hint - inferred at runtime, same as Python. var health = 100 var player_name = "Sam" # Explicit type hint - the editor enforces this. var lives: int = 3 var speed: float = 150.0 # Inferred typing with := - GDScript figures out the type from the # value on the right, and still enforces it afterward. var is_alive := true

A const works the same way but can never be reassigned after it's set — used for values that are genuinely fixed, like a maximum speed or a gravity constant.

const MAX_SPEED = 300.0 const GRAVITY = 980.0
Type hints are optional, but worth the habit — a wrong-type mistake (assigning a String to a variable you meant to hold a number) is caught immediately in the editor instead of surfacing as a confusing runtime error mid-game. Later chapters use type hints throughout for exactly this reason.

Built-in Types

TypeExampleNotes
intvar lives: int = 3Whole numbers
floatvar speed: float = 150.0Decimal numbers
boolvar is_alive := truetrue/false, lowercase
Stringvar name := "Sam"Text — capital S, unlike Python's lowercase str
Arrayvar items = [1, 2, 3]Like a Python list; can optionally be typed, e.g. Array[int]
Dictionaryvar d = {"hp": 100, "mp": 50}Like a Python dict, key/value pairs
Vector2var pos = Vector2(10, 20)Godot-specific — an (x, y) pair used constantly for position/movement
Coming from Python Array and Dictionary map directly onto Python's list and dict — same square-bracket and curly-brace literal syntax, same mixed-type-by-default flexibility. Vector2 has no direct Python equivalent in the standard library (it's closer to a NumPy array of length 2) — it's Godot's own building block for anything with an x/y position, and it shows up everywhere starting in Chapter 4.

Functions

Functions are declared with func, and — like variables — parameters and return values can optionally be typed.

# No type hints - works, but nothing is enforced. func add(a, b): return a + b # Typed parameters and a typed return value. func take_damage(amount: int, current_hp: int) -> int: return current_hp - amount # A default parameter value - just like Python's own default arguments. func greet(name: String = "Player") -> void: print("Hello, " + name + "!")

A function with no meaningful return value is typed -> void, GDScript's explicit way of saying "this function doesn't return anything" — Python has no direct equivalent (a bare Python function implicitly returns None, with nothing written to say so).

Control Flow

if / elif / else

if health <= 0: print("Game over") elif health < 30: print("Low health!") else: print("Doing fine")

for loops

# Same shape as Python's for-in-range(). for i in range(5): print(i) # Iterating directly over an array, same as Python. for enemy_name in ["Slime", "Goblin", "Dragon"]: print(enemy_name)

while loops

var countdown = 3 while countdown != 0: print(countdown) countdown -= 1

match — GDScript's switch statement

Python only gained match in version 3.10; GDScript has had one from early on. The shape is familiar if you've used Python's version: match a value against several patterns, with _ as the catch-all default.

match weapon_type: 0: print("Sword") 1: print("Bow") _: print("Unknown weapon")
Indentation is significant, exactly like Python — a stray tab/space mismatch produces a real parse error. Godot's own script editor defaults to tabs for GDScript files; mixing tabs and spaces in the same file is the single most common source of a confusing "unexpected indent" error for anyone new to the language.

Coding Challenges

Challenge 1
Write a typed function calculate_damage(base: int, multiplier: float) -> int that returns the base damage multiplied by the multiplier, rounded down to a whole number. Call it with a few different values and print the results.
→ Solution
Challenge 2
Build an Array of five enemy names as Strings. Using a for loop, print each name along with its position in the array (e.g. "1: Slime").
→ Solution
Challenge 3
Write a script that starts a player at 100 health and, using a while loop, subtracts 15 health per iteration. Inside the loop, use if/elif/else to print "Critical!", "Hurt", or "Healthy" depending on the current health, and stop the loop once health reaches 0 or below.
→ Solution

Quick Reference — GDScript Basics

  • var name: Type = value — typed; var name := value — inferred; var name = value — untyped
  • const NAME = value — never reassigned
  • Core types: int, float, bool, String, Array, Dictionary, Vector2
  • func name(param: Type = default) -> ReturnType:
  • if / elif / else, for x in range(n), for x in array, while, match
  • Indentation-based blocks, no semicolons — same as Python