Syntax Cache
BlogMethodFeaturesHow It WorksBuild a Game
  1. Home
  2. GDScript
GDScript16 topics289+ exercises

GDScript Syntax Practice

Write GDScript that works on the first run, not the third.

Short daily reps. Spaced repetition automatically brings back what you keep forgetting.

Build a Game with GDScript

Complete 12 syntax-recall beats and watch a Godot game come to life stage by stage. No login required.

Try It Free

GDScript looks like Python but plays by different rules. Signals replace callbacks. Nodes replace objects. @export replaces config files. And every frame, _physics_process runs whether you remember the syntax or not.

SyntaxCache covers the GDScript you actually write in Godot 4: node references, signal connections, scene instancing, vector math. The exercises build toward an Arena Survivor game, one pattern at a time.

Popular topics include GDScript Foundations Practice, GDScript Movement Practice, GDScript Timers & Signals Practice.

Built for GDScript Learners

Great for
  • Indie devs building games in Godot 4.
  • Unity refugees learning the Godot way.
  • Hobbyists who know programming but not GDScript.
  • Game jam participants who need fast recall.
You'll be able to
  • Connect signals and handle collisions without checking the docs.
  • Instantiate scenes, spawn enemies, and manage the scene tree from memory.
  • Write vector math for movement, aiming, and projectiles on instinct.
  • Use @export, tweens, and timers without guessing at syntax.

Practice by Topic

Pick a concept and train recall with small, focused reps.

32 exercisesGotchas included

GDScript Foundations Practice

Nail the first 10 lines of every script: extends, typed vars, @export, @onready, _ready.

Show 3 gotchasHide gotchas
  • @onready runs at _ready() time, not parse time. Using it outside the tree crashes.
  • _init() runs before the node enters the tree. No $ paths work yet.
  • Forgetting extends defaults to RefCounted, not Node.
Learn more
24 exercisesGotchas included

GDScript Movement Practice

Stop copy-pasting CharacterBody2D code. Know velocity, move_and_slide(), and delta.

Show 3 gotchasHide gotchas
  • move_and_slide() takes no arguments in Godot 4. Set velocity first.
  • Use _physics_process(delta) for movement, not _process. Otherwise speed varies with FPS.
  • Input.get_vector() returns a normalized vector. No need to normalize again.
Learn more
15 exercisesGotchas included

GDScript Timers & Signals Practice

Connect signals, bind args, and use timers without double-fire bugs.

Show 3 gotchasHide gotchas
  • create_timer() has no cancel API. Use a Timer node if you need to stop it.
  • Connecting the same signal twice causes duplicate calls. Guard with is_connected().
  • Store bound callables (func.bind(arg)) if you plan to disconnect() later.
Learn more
13 exercisesGotchas included

GDScript Scene Instancing Practice

Spawn scenes correctly: preload, instantiate, add_child, set position.

Show 3 gotchasHide gotchas
  • Set global_position after add_child(), not before. No parent transform yet.
  • instance() was renamed to instantiate() in Godot 4.
  • Use add_child.call_deferred() when spawning during callbacks or _ready().
Learn more
9 exercisesGotchas included

GDScript Exports Practice

Tune gameplay from the Inspector with @export, ranges, enums, and groups.

Show 3 gotchasHide gotchas
  • @export replaced export() from Godot 3. Parentheses are gone.
  • @export_range(0.0, 1.0, 0.01) adds an Inspector slider. Third arg is step.
  • @export_group("Label") organizes exports visually. Does not affect code behavior.
Learn more
27 exercisesGotchas included

GDScript Vector Math Practice

Direction, distance, dot, cross, bounce. The Vector2 methods you use every frame.

Show 3 gotchasHide gotchas
  • distance_squared_to() skips the sqrt. Use it when comparing distances.
  • Vector2.ZERO.normalized() returns (0,0), not NaN. Manual v / v.length() does crash.
  • bounce() is for physics ricochet. reflect() is the mathematical mirror (rarely what you want).
Learn more
18 exercisesGotchas included

GDScript Tweens & Polish Practice

Code-driven animations: hit flashes, pop scales, smooth fades, chain sequences.

Show 3 gotchasHide gotchas
  • Tween.new() is invalid. Always use create_tween() from a node.
  • Each create_tween() auto-kills the previous tween on that node by default.
  • set_parallel() runs all subsequent steps at once. Without it, steps are sequential.
Learn more
7 exercisesGotchas included

GDScript Collisions Practice

Fix "body_entered not firing" and understand layers vs masks.

Show 3 gotchasHide gotchas
  • Layer = what I am. Mask = what I detect. A detects B if A's mask includes B's layer.
  • Area2D needs monitoring = true. RigidBody2D needs contact_monitor = true + max_contacts_reported > 0.
  • Missing CollisionShape2D is the most common reason signals never fire.
Learn more
33 exercisesGotchas included

GDScript Resources Practice

Custom data assets, shared-state bugs, and when to duplicate().

Show 3 gotchasHide gotchas
  • Resources are shared by default. Mutating one instance changes all references.
  • duplicate(true) does NOT deep-copy Resources inside Arrays. Manual copy needed.
  • Use preload() for compile-time paths, load() for runtime/dynamic paths.
Learn more
8 exercisesGotchas included

GDScript Randomness Practice

randf_range, randi_range, seeded RNG, weighted picks, shuffle bags.

Show 3 gotchasHide gotchas
  • randf_range(0.0, 1.0) is inclusive on both ends. randi_range(0, 5) includes 5.
  • For reproducible results, use RandomNumberGenerator with a fixed seed.
  • array.pick_random() is uniform. For weighted drops, build a cumulative threshold array.
Learn more
9 exercisesGotchas included

GDScript Groups & Pickups Practice

Tag nodes with groups and query/broadcast without hard-coded paths.

Show 3 gotchasHide gotchas
  • is_in_group() takes a StringName. Use &"group_name" for performance.
  • call_group() calls a method on every node in the group. No return values.
  • get_nodes_in_group() returns an Array. It may include nodes being freed this frame.
Learn more
35 exercisesGotchas included

GDScript Arrays & Loops Practice

Iterate, filter, sort, and safely remove elements from GDScript arrays.

Show 3 gotchasHide gotchas
  • Removing items while iterating forward skips elements. Iterate backward or filter.
  • array.sort_custom(func) sorts in-place and returns void.
  • Typed arrays (Array[int]) catch type mismatches at assignment time.
Learn more
27 exercisesGotchas included

GDScript Projectiles Practice

Spawn bullets with direction, lifetime, and collision filtering.

Show 3 gotchasHide gotchas
  • Set collision layers so bullets don't hit the shooter. Different layers for player vs enemy projectiles.
  • Every instantiate() needs a matching queue_free() or your scene tree grows forever.
  • Fast bullets can tunnel through thin walls. Use RayCast2D or ShapeCast2D for hit detection.
Learn more
12 exercisesGotchas included

GDScript UI & HUD Practice

CanvasLayer, anchors, containers, and signal-driven HUD updates.

Show 3 gotchasHide gotchas
  • Without CanvasLayer, your HUD moves with the camera.
  • Set root Control to Full Rect anchor preset so it fills the screen.
  • Use bind/unbind pattern for player respawn. Signals can fire after queue_free() until end-of-frame.
Learn more
9 exercisesGotchas included

Procedural Generation

Four dungeon algorithms: drunkard's walk, cellular automata, BSP, and noise terrain.

Show 3 gotchasHide gotchas
  • Cellular automata needs double-buffering. Reading and writing the same grid corrupts neighbor counts.
  • Drunkard's walk and BSP guarantee connectivity; cellular automata and noise terrain do NOT. Run flood fill.
  • Use seeded RandomNumberGenerator, not global randf(), so maps are reproducible for debugging.
Learn more
11 exercisesGotchas included

TileMapLayer

set_cell, erase_cell, map_to_local, and the TileMapLayer migration from Godot 4.3+.

Show 3 gotchasHide gotchas
  • get_cell_source_id() returns -1 for empty cells, NOT 0. Source ID 0 is a valid tileset.
  • map_to_local() returns the tile CENTER, not the top-left corner.
  • The old TileMap node is deprecated in Godot 4.3. Use individual TileMapLayer nodes instead.
Learn more

GDScript Cheat Sheets

Copy-ready syntax references for quick lookup

SignalsVectorsNode OperationsTweensInput HandlingResourcesArrays & Dictionaries

What You'll Practice

Real GDScript patterns you'll type from memory

CharacterBody2D movement
var direction := Input.get_vector("left", "right", "up", "down")
velocity = direction * speed
move_and_slide()
Signal connection
timer.timeout.connect(_on_timeout)
button.pressed.connect(_on_pressed)
Scene instancing
const BulletScene: PackedScene = preload("res://scenes/bullet.tscn")
var bullet := BulletScene.instantiate() as Area2D
add_child(bullet)
bullet.global_position = muzzle.global_position
@export with range
@export var speed: float = 200.0
@export_range(0.0, 1.0, 0.01) var friction: float = 0.8
Tween chain
var tween := create_tween()
tween.tween_property(self, "modulate", Color.RED, 0.05)
tween.tween_property(self, "modulate", Color.WHITE, 0.1)
Collision signal
func _on_body_entered(body: Node2D) -> void:
	if body.is_in_group(&"enemy"):
		take_damage(body.damage)
Vector2 direction
var dir := global_position.direction_to(target.global_position)
velocity = dir * chase_speed
Inline delay
await get_tree().create_timer(0.25).timeout

Sample Exercises

Example 1Difficulty: 2/5

Apply movement to a CharacterBody2D using direction and speed. Set velocity, then move. (Assume direction and speed exist.)

velocity = direction * speed
move_and_slide()
Example 2Difficulty: 2/5

In 3 lines: instantiate enemy_scene into enemy, set enemy.global_position to spawn_point, add to parent.

var enemy = enemy_scene.instantiate()
enemy.global_position = spawn_point
get_parent().add_child(enemy)

Done Googling GDScript syntax?

Ten minutes a day. No setup. The syntax sticks.

Why this works

GDScript fades fast if you only touch Godot on weekends. The algorithm brings back each pattern right before you'd blank on it. After a few rounds, the syntax is there when you need it.

What to expect

Week 1: You'll see exactly what trips you up. Maybe it's signal.connect() syntax, maybe it's forgetting global_position after add_child(). The algorithm finds the gaps.

Week 2-4: Intervals stretch. Patterns you got right move to 2-day, 4-day, then weekly review. You stop reaching for the docs on basics like @export and move_and_slide().

Month 2+: Core GDScript is automatic. Reviews take 10 minutes. You still practice new concepts (resources, UI, randomness), but the foundations don't need refreshing anymore.

FAQ

Is this for Godot 3 or Godot 4?

Godot 4 only. All exercises use modern syntax: @export, move_and_slide() with no args, signal.connect(callable).

Do I need Godot installed?

No. Everything runs in the browser. The exercises teach syntax recall, not editor workflow.

I know Python. Will GDScript be easy?

The syntax is similar but the concepts differ. Signals, nodes, and the scene tree are Godot-specific and need their own drilling.

Is GDScript the best language to start with for Godot 4?

For most solo and small-team Godot projects, yes. GDScript has the tightest integration with the editor, the best documentation coverage, and the quickest edit-run loop.

Is GDScript dynamically typed or statically typed?

Both. GDScript is gradually typed: you can write quick dynamic code, then add type hints where you want safety, editor autocomplete, and fewer runtime surprises.

How does GDScript in Godot 4 differ from Godot 3?

The biggest day-to-day differences are callables/signals (less stringly-typed), @export/@onready annotations, and updated physics APIs like CharacterBody2D using a velocity property with move_and_slide() taking no arguments.

What's the difference between Node2D and CharacterBody2D?

Node2D is the base for 2D objects with position/rotation/scale. CharacterBody2D extends it with physics collision and move_and_slide() for kinematic movement. Use Node2D for simple objects; use CharacterBody2D when you need collision response.

Why does my movement feel different on fast PCs?

You're probably using _process instead of _physics_process, or forgetting to multiply by delta. _physics_process runs at a fixed rate (60 Hz by default) regardless of FPS.

Do I have to use typed GDScript?

No, but you should. Type hints catch errors at parse time, enable better editor autocomplete, and make code self-documenting. Use `: Type` for variables and `-> Type` for return values.

Sources
GDScript Reference (Godot 4 Docs)CharacterBody2D TutorialSignals (Godot 4 Docs)Vector Math Tutorial

Try it. It takes two minutes.

Free daily exercises with spaced repetition. No credit card required.

Syntax Cache

Build syntax muscle memory with spaced repetition.

Product

  • Pricing
  • Our Method
  • Daily Practice
  • Design Patterns
  • Interview Prep

Resources

  • Blog
  • Compare
  • Cheat Sheets
  • Vibe Coding
  • Muscle Memory

Languages

  • Python
  • JavaScript
  • TypeScript
  • Rust
  • SQL
  • GDScript

Legal

  • Terms
  • Privacy
  • Contact

© 2026 Syntax Cache

Cancel anytime in 2 clicks. Keep access until the end of your billing period.

No refunds for partial billing periods.