【Unity】C# Arrays and Lists for Unity Developers - Handling Multiple Pieces of Data at Once

Created: 2026-07-05Last updated: 2026-07-13

Still creating enemy1, enemy2, enemy3... as separate variables? Learn how arrays and Lists let you manage multiple pieces of data together, with practical Unity examples like spawn point management and enemy tracking. Beginner-friendly guide.

You want three enemies, so you create three variables: enemy1, enemy2, enemy3. It works—but once you need ten enemies, you're stuck with ten variables and ten copy-pasted blocks of code. This "lots of the same kind of data" problem is exactly what C# collections solve, and the two you'll use most are arrays and Lists.

In this article, we'll cover the basics of arrays and Lists, the key difference between them and when to use which, plus practical Unity examples: managing spawn points in the Inspector and tracking active enemies with a List.

Conceptual image of an array: blocks lined up in order on numbered shelves

What You'll Learn

  • How to declare, access, and loop over "arrays"—numbered variables bundled together
  • How to use the resizable "List" (Add / Remove / Count)
  • How to decide between arrays and Lists
  • Practical Unity patterns like Inspector integration and enemy list management

Sponsored

Arrays: A Row of Numbered Boxes

An array reserves a set of variables of the same type as a single "numbered shelf." Let's start with the mental picture.

Array concept diagram: int boxes numbered 0 through 4 connected in a row like a shelf, with each box accessed by its index number

Each slot on the shelf is a variable, and each one has a number called an index. The crucial detail: indices start at 0. An array with 5 elements uses indices 0 through 4.

using UnityEngine;

public class ArrayExample : MonoBehaviour
{
    void Start()
    {
        // Create an int array with 5 elements (all initialized to 0)
        int[] scores = new int[5];

        // Read and write by index (zero-based!)
        scores[0] = 100;
        scores[1] = 85;

        // You can also create an array with its contents up front
        string[] stageNames = { "Forest", "Cave", "Castle" };

        // Length gives you the number of elements
        Debug.Log($"Stage count: {stageNames.Length}"); // 3

        // foreach processes every element in order
        foreach (string name in stageNames)
        {
            Debug.Log($"Stage: {name}");
        }
    }
}

Warning: Accessing an index that doesn't exist throws an IndexOutOfRangeException. Writing scores[5] on a 5-element array is the classic mistake (the last element is scores[4]).

An array's size is fixed at the moment you create it. There's no "let me add one more later." That's where List comes in.

List: A Shelf That Grows and Shrinks

A List is a "stretchable shelf" that lets you freely add and remove elements after creation. To use it, you need using System.Collections.Generic; at the top of your file.

Comparison diagram of array vs. List: an array is a shelf with a fixed number of slots that can't grow after creation, while a List's shelf automatically extends when you add elements

You write the type you want to store inside the <>, like List<int> (this is the same generics mechanism we saw in the GetComponent article).

using System.Collections.Generic; // Required for List!
using UnityEngine;

public class ListExample : MonoBehaviour
{
    void Start()
    {
        // Create an empty List
        List<string> inventory = new List<string>();

        // Add: appends to the end (the shelf grows automatically)
        inventory.Add("Health Potion");
        inventory.Add("Iron Sword");
        inventory.Add("Shield");

        // Count gives the current number of elements (like an array's Length)
        Debug.Log($"Item count: {inventory.Count}"); // 3

        // Index access works just like arrays
        Debug.Log($"First item: {inventory[0]}"); // Health Potion

        // Remove: deletes the specified element (the shelf shrinks)
        // Note: even if duplicates exist, only the FIRST match is removed
        inventory.Remove("Health Potion");

        // Contains: check whether an item is present
        if (inventory.Contains("Iron Sword"))
        {
            Debug.Log("You can equip the sword");
        }
    }
}
Sponsored

Array vs. List: Which to Use

FeatureArray (int[])List (List<int>)
SizeFixed at creationGrows and shrinks freely
Element count.Length.Count
Add / RemoveNot possibleAdd / Remove
Best forData with a fixed countData that changes during gameplay

The decision rule is simple.

  • The count is known up front (stage lists, spawn points, equipment slots) → array
  • Items come and go during gameplay (active enemies, inventory, unlocked achievements) → List

If in doubt, starting with a List is fine. Arrays shine when the "fixed count" constraint communicates design intent, or when you're squeezing out performance.

Practical Examples in Unity

Example 1: Managing Spawn Points in the Inspector

A public array shows up as a list in the Inspector, and you can assign elements via drag and drop. This is where collections first prove their worth in Unity.

Diagram of setting up an array in the Inspector: three spawn point objects from the scene being dragged into the Spawn Points array slots
using UnityEngine;

public class EnemySpawner : MonoBehaviour
{
    public GameObject enemyPrefab;

    // Appears in the Inspector as "Spawn Points"
    public Transform[] spawnPoints;

    void Start()
    {
        // Spawn one enemy at every spawn point
        foreach (Transform point in spawnPoints)
        {
            Instantiate(enemyPrefab, point.position, point.rotation);
        }
    }
}

Just place three empty GameObjects in the scene and drag them into Spawn Points in the Inspector. Want more spawn points later? Add elements in the Inspector—no code changes needed.

Example 2: Tracking Active Enemies with a List

"Enemies currently in the scene" shrink when defeated and grow when spawned—exactly the kind of data a List is made for.

Practical diagram of enemy List management: spawned enemies are added to the activeEnemies list with Add, defeated enemies leave via Remove, and when Count hits 0 the wave is cleared
using System.Collections.Generic;
using UnityEngine;

public class EnemyManager : MonoBehaviour
{
    // List tracking the enemies currently active
    private List<GameObject> activeEnemies = new List<GameObject>();

    public void RegisterEnemy(GameObject enemy)
    {
        activeEnemies.Add(enemy); // Add on spawn
    }

    public void UnregisterEnemy(GameObject enemy)
    {
        activeEnemies.Remove(enemy); // Remove on defeat

        // Checking for a full wipe is just a Count check
        if (activeEnemies.Count == 0)
        {
            Debug.Log("Wave cleared!");
        }
    }
}

Warning: Calling Remove on a List while iterating it with foreach throws an InvalidOperationException. If you need to remove elements mid-loop, the standard workaround is a for loop that runs from the end backwards (for (int i = list.Count - 1; i >= 0; i--)).

Sponsored

Bonus: Good to Know for Later

Once you're comfortable with arrays and Lists, these topics are the natural next steps.

  • Looking things up "by name"? Use Dictionary: With Dictionary<string, int>, you can look up values by key instead of by number, like items["Health Potion"]. It's a workhorse for things like mapping item IDs to their data.
  • A perfect match for prefab spawning at scale: The next step after managing spawned enemies and items in a List is object pooling—reusing them efficiently instead of creating and destroying. It appears as "a reuse mechanism built on Lists" in the object pooling article.
  • Watch out for GC with heavy churn: Adding elements to a List can trigger internal array reallocation, and doing it in bulk repeatedly puts pressure on GC (garbage collection). When that starts to matter, the GC article is a good reference.
  • There's a design that doesn't expose the List as public: a public List<...> can be Added to or Removed from by any other script at will. As you get comfortable, make the List private and expose only "gateway methods" for adding and removing (the earlier RegisterEnemy/UnregisterEnemy are exactly this)—it closes off a whole class of bugs.

Summary

Collections—handling multiple pieces of data together—are the foundation of game logic.

  • An array is a "fixed shelf with numbered slots." Its size is set at declaration, and you work with .Length and indices (starting at 0).
  • A List is a "shelf that grows and shrinks." Use Add / Remove / .Count to resize freely. Don't forget using System.Collections.Generic;.
  • The rule of thumb: fixed count → array, changing count → List. If in doubt, a List is fine.
  • public arrays and Lists appear as lists in the Inspector, assignable via drag and drop.
  • Remove inside a foreach throws an exception. To delete while looping, use for from the end backwards.

Say goodbye to enemy1, enemy2, enemy3. Whether it's 10 enemies or 100, collections handle them with the same few lines of code.