Syntax Cache
BlogMethodFeaturesHow It WorksBuild a Game
  1. Home
  2. GDScript
  3. GDScript Arrays & Loops Practice
GDScript35 exercises

GDScript Arrays & Loops Practice

Learn GDScript arrays and loops in Godot 4 with game-ready patterns: iterating with indices, safe removal, sorting enemies by distance, and choosing Array vs typed vs packed arrays.

Common ErrorsQuick ReferencePractice
Warm-up1 / 2

Can you write this from memory?

Declare an array called upgrade_names containing the strings 'speed', 'damage', and 'health'.

On this page
  1. 1Three Loop Patterns You'll Actually Use
  2. 1. Loop Over Values
  3. 2. Loop With Index
  4. 3. Early Break When Found
  5. 2Closest Enemy in One Pass
  6. 3Sorting by Distance
  7. 4Safe Removal During Iteration
  8. Option 1: Iterate Over a Copy
  9. Option 2: Backward Index Loop (fastest, no allocation)
  10. Option 3: filter() for Clean Code
  11. 5Choosing the Right Collection
  12. 6Array vs Dictionary
  13. 7Related Pages
Three Loop Patterns You'll Actually UseClosest Enemy in One PassSorting by DistanceSafe Removal During IterationChoosing the Right CollectionArray vs DictionaryRelated Pages

In GDScript, auto-targeting weapons need to find the closest enemy. That means getting all enemies from a group, looping through them, and comparing distances.

Practice array operations and group queries, and your weapon targeting logic writes itself.

Quick Answers:

  • How do I loop with index?
  • How do I remove items safely?
  • How do I get the closest enemy?
  • Array vs PackedArray—when to use which?
Related GDScript Topics
GDScript FoundationsGDScript Timers & SignalsGDScript Groups & PickupsGDScript ProjectilesGDScript Procedural Generation

for-in for values, range() for index access, early return for search. Pick the simplest pattern that fits your use case.

1. Loop Over Values

var items: Array[String] = ["sword", "shield", "potion"]

for item in items:
    print(item)

2. Loop With Index

for i in range(items.size()):
    print(i, ": ", items[i])

3. Early Break When Found

func find_item(target: String) -> int:
    for i in range(items.size()):
        if items[i] == target:
            return i  # Found it, stop searching
    return -1  # Not found

Ready to practice?

Start practicing GDScript Arrays & Loops with spaced repetition

Sorting is O(n log n). If you just need the closest, do it in O(n):

func get_closest_enemy() -> Node2D:
    var enemies := get_tree().get_nodes_in_group(&"enemy")
    var closest: Node2D = null
    var min_dist_sq := INF

    for node in enemies:
        var enemy := node as Node2D
        if enemy == null:
            continue
        # distance_squared_to avoids sqrt—faster for comparisons
        var dist_sq := global_position.distance_squared_to(enemy.global_position)
        if dist_sq < min_dist_sq:
            min_dist_sq = dist_sq
            closest = enemy

    return closest

In real games: Prefer one-pass closest target if you do this every frame. Save sorting for when you need the full ordered list.


When you need enemies sorted (e.g., chain lightning, splash damage falloff):

func get_enemies_sorted_by_distance() -> Array[Node2D]:
    var enemies := get_tree().get_nodes_in_group(&"enemy")

    # Sort using distance_squared_to (faster, same ordering)
    enemies.sort_custom(func(a: Node, b: Node) -> bool:
        var dist_a := global_position.distance_squared_to((a as Node2D).global_position)
        var dist_b := global_position.distance_squared_to((b as Node2D).global_position)
        return dist_a < dist_b
    )

    # Cast to typed array
    var result: Array[Node2D] = []
    for e in enemies:
        if e is Node2D:
            result.append(e)
    return result

Note: get_nodes_in_group() returns Array[Node], not Array[Node2D]. Filter/cast before using global_position.


Never erase while iterating with for-in. Use backward index loop (fastest, no allocation), filter() (cleanest), or duplicate() (safe middle ground).

Godot warns: Erasing while iterating is unsupported and can behave unpredictably. Use one of these safe patterns:

# WRONG: Skips elements, unpredictable behavior
for enemy in enemies:
    if enemy.is_dead:
        enemies.erase(enemy)  # Don't do this!

Option 1: Iterate Over a Copy

for enemy in enemies.duplicate():
    if enemy.is_dead:
        enemies.erase(enemy)

Option 2: Backward Index Loop (fastest, no allocation)

for i in range(enemies.size() - 1, -1, -1):
    if enemies[i].is_dead:
        enemies.remove_at(i)

Option 3: filter() for Clean Code

# Rebuild the list with only living enemies
enemies = enemies.filter(func(e): return not e.is_dead)

Trade-offs: Backward loop is fastest (no allocations). filter() is most readable. duplicate() is a safe middle ground.


Use Array[T] for gameplay objects (enemies, items). Use PackedArrays for large numeric buffers (paths, geometry). Use Dictionary for key-value lookups with O(1) access.

TypeBest ForTrade-offs
ArrayGeneral collections, mixed typesFlexible, slower than typed
Array[T]Gameplay objects (enemies, items)Type safety, autocomplete, good performance
PackedVector2ArrayLarge numeric data (paths, geometry)Contiguous memory layout like C arrays—better cache locality and lower per-element overhead than generic Arrays
DictionaryKey-value lookups (stats, config)O(1) access by key, preserves insertion order

In real games: Use Array[T] for gameplay collections (enemies, items, projectiles). Use Packed arrays for raw numeric buffers like navigation paths or vertex data where you iterate thousands of elements. Each element in a generic Array is a Variant (20+ bytes overhead per element), while PackedFloat32Array stores raw 4-byte floats—a significant memory difference at scale.


For a printable reference of collection methods, see the GDScript arrays & dictionaries cheat sheet. For real-world dictionary patterns in Godot 4, see our dictionary map blog post.

ArrayDictionary
Ordered, integer-indexedKey-value pairs
items[0]stats["hp"]
Use for lists, sequencesUse for named lookups
# Array: ordered collection
var inventory: Array[String] = ["sword", "potion", "key"]

# Dictionary: key-value mapping
var stats: Dictionary = { "hp": 100, "attack": 10, "defense": 5 }

Note: Dictionaries preserve insertion order when adding entries, but they're not automatically sorted. If you need sorted keys, extract and sort explicitly.


  • Previous: Foundations — Script structure, lifecycle
  • Next: Timers & Signals — Event-driven patterns
  • See also: Groups & Pickups, Projectiles

When to Use GDScript Arrays & Loops

  • Iterating over enemies, collectibles, or scene groups with get_tree().get_nodes_in_group()
  • Storing and looking up game data with Dictionaries for items, stats, or configuration
  • Finding the nearest node by looping through an array and comparing with distance_squared_to()
  • Safely removing items during iteration using filter(), backward loops, or duplicate()

Check Your Understanding: GDScript Arrays & Loops

Prompt

Check Your Understanding: Why use distance_squared_to() instead of distance_to() when finding the closest enemy?

What a strong answer looks like

distance_to() computes sqrt(dx² + dy²), while distance_squared_to() returns just dx² + dy². The sqrt operation is expensive. When comparing distances (closest, in-range checks), relative order is preserved without sqrt: if A² < B², then A < B. Only use distance_to() when you need the actual distance value (e.g., displaying "50 meters away"). In hot loops like per-frame targeting, distance_squared_to() is measurably faster.

What You'll Practice: GDScript Arrays & Loops

Array literal syntaxfor item in array: loopsget_tree().get_nodes_in_group()distance_squared_to() for efficient comparisonsfilter/map for functional transformsSafe removal patterns (backward loop, filter, duplicate)

Common GDScript Arrays & Loops Pitfalls

  • Modifying an Array while iterating with for-in—Godot warns this is unsupported and causes unpredictable behavior; use duplicate(), backward index loop, or filter() instead
  • Using get_nodes_in_group() every frame—allocates a new Array each call; cache the result or use signals for dynamic membership
  • Assuming get_nodes_in_group() returns typed nodes—it returns Array[Node], not Array[Node2D]; cast/filter before accessing global_position
  • Using distance_to() in hot loops when you only need relative comparisons—distance_squared_to() avoids the expensive sqrt operation
  • Dictionaries preserve insertion order but are not sorted—if you need sorted keys, extract keys() and sort explicitly

GDScript Arrays & Loops FAQ

How do I loop with index in GDScript?

Use range(): for i in range(items.size()): print(items[i]). This gives you the index i to access elements by position or modify the array.

How do I get the closest enemy in GDScript?

Loop through get_nodes_in_group(&"enemy"), track minimum distance using INF as the starting value. Use distance_squared_to() instead of distance_to()—it skips the sqrt and is faster for comparisons where you only need relative distance.

How do I remove items from an array safely while iterating?

Godot warns that erasing during iteration is unsupported. Three safe options: (1) iterate over enemies.duplicate(), (2) loop backward with for i in range(size - 1, -1, -1), or (3) use enemies.filter(func(e): return not e.is_dead).

What is distance_squared_to and when should I use it?

distance_squared_to() returns the squared distance without computing the square root. Use it when comparing distances (closest enemy, range checks) since sqrt is expensive. Only use distance_to() when you need the actual distance value.

How do I sort an array of enemies by distance in GDScript?

Use sort_custom with distance_squared_to: enemies.sort_custom(func(a, b): return global_position.distance_squared_to(a.global_position) < global_position.distance_squared_to(b.global_position)).

What is the difference between Array and Dictionary in GDScript?

Array is ordered and integer-indexed (items[0]). Dictionary uses key-value pairs (stats["hp"]). Dictionaries preserve insertion order but aren't sorted. Use Array for sequences; Dictionary for named lookups.

Does GDScript have filter and map like JavaScript?

Yes! Godot 4 has filter(), map(), and reduce(). Example: enemies.filter(func(e): return e.is_alive) returns a new array with only living enemies. Note: these allocate new arrays, so avoid in hot paths.

Array[T] vs PackedArray—when should I use which?

Use Array[T] for gameplay objects (enemies, items)—you get type safety and convenience methods. Use PackedVector2Array/PackedFloat32Array for large numeric datasets (navigation paths, geometry) where memory and iteration speed matter.

GDScript Arrays & Loops Syntax Quick Reference

Closest enemy (one pass, O(n))
func get_closest_enemy() -> Node2D:
	var enemies := get_tree().get_nodes_in_group(&"enemy")
	var closest: Node2D = null
	var min_dist_sq := INF
	for node in enemies:
		var enemy := node as Node2D
		if enemy == null:
			continue
		var dist_sq := global_position.distance_squared_to(enemy.global_position)
		if dist_sq < min_dist_sq:
			min_dist_sq = dist_sq
			closest = enemy
	return closest
Safe removal (backward loop)
func remove_dead_enemies(enemies: Array[Node2D]) -> void:
	for i in range(enemies.size() - 1, -1, -1):
		if enemies[i].is_dead:
			enemies.remove_at(i)
Safe removal (filter)
# Rebuild array with only living enemies
enemies = enemies.filter(func(e): return not e.is_dead)
Enemies in range (squared distance)
func get_enemies_in_range(radius: float) -> Array[Node2D]:
	var radius_sq := radius * radius
	var result: Array[Node2D] = []
	for node in get_tree().get_nodes_in_group(&"enemy"):
		var enemy := node as Node2D
		if enemy and global_position.distance_squared_to(enemy.global_position) <= radius_sq:
			result.append(enemy)
	return result

GDScript Arrays & Loops Sample Exercises

Example 1Difficulty: 2/5

Write a for loop using range from 1 to 10 (inclusive of 1, exclusive of 11) to spawn waves, with loop variable wave.

for wave in range(1, 11):
Example 2Difficulty: 2/5

Write a for loop using range from 0 to 10, stepping by 2 (0, 2, 4, 6, 8), with loop variable x.

for x in range(0, 10, 2):
Example 3Difficulty: 2/5

Get all nodes in the 'enemies' group from the scene tree, storing the result in a variable called enemies.

var enemies = get_tree().get_nodes_in_group("enemies")

+ 32 more exercises

Quick Reference
GDScript Arrays & Loops Cheat Sheet →

Copy-ready syntax examples for quick lookup

Practice in Build a Game

Roguelike: Part 3: The Dungeon BreathesBuild a GameRoguelike: Part 4: Mutations in the DustBuild a GameRoguelike: Drunkard's WalkBuild a GameRoguelike: Cellular AutomataBuild a GameRoguelike: BSP DungeonsBuild a GameRoguelike: Noise TerrainBuild a Game

Further Reading

  • GDScript Dictionary map() and map_in_place12 min read
  • Facade Pattern in Godot 4 GDScript: Taming "End Turn" Spaghetti12 min read

Start practicing GDScript Arrays & Loops

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

← Back to GDScript Syntax Practice
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.