Source file unity-csharp/arcade-classics/breakout/BrickGrid.cs from the GDnD code examples. Download raw file
// GDnD wiki example
// Demonstrates: building a grid of objects from a loop, tracking them in a list, and detecting level clearance
// Related pages: [[overview-arcade-classics-as-learning-projects]], [[csharp-collections]], [[unity-prefabs-scripting]]
using System;
using System.Collections.Generic;
using UnityEngine;
// Spawns the brick wall and owns the "how many bricks are left?" question. The
// double loop and the List<Brick> are the step-2 learning targets: arrays/lists
// and level reset. See [[csharp-collections]] and [[unity-prefabs-scripting]].
public class BrickGrid : MonoBehaviour
{
[Header("Prefab")]
[SerializeField] private Brick brickPrefab;
[Header("Layout")]
[SerializeField] private int columns = 10;
[SerializeField] private int rows = 5;
[SerializeField] private Vector2 brickSize = new Vector2(1.4f, 0.5f);
[SerializeField] private Vector2 spacing = new Vector2(0.1f, 0.1f);
[SerializeField] private float topMargin = 1f;
// Forwarded brick score, and a one-shot signal when the last brick is cleared.
public event Action<int> BrickDestroyed;
public event Action LevelCleared;
private readonly List<Brick> activeBricks = new List<Brick>();
public void BuildLevel()
{
ClearExistingBricks();
Camera cam = Camera.main;
float cellWidth = brickSize.x + spacing.x;
float cellHeight = brickSize.y + spacing.y;
// Centre the wall horizontally and hang it from just below the top edge.
float startX = -((columns - 1) * cellWidth) / 2f;
float startY = cam.orthographicSize - topMargin;
for (int row = 0; row < rows; row++)
{
for (int column = 0; column < columns; column++)
{
Vector3 position = new Vector3(
startX + column * cellWidth,
startY - row * cellHeight,
0f
);
Brick brick = Instantiate(brickPrefab, position, Quaternion.identity, transform);
brick.transform.localScale = new Vector3(brickSize.x, brickSize.y, 1f);
brick.Destroyed += OnBrickDestroyed;
activeBricks.Add(brick);
}
}
}
private void OnBrickDestroyed(int score)
{
BrickDestroyed?.Invoke(score);
// Tidy the list, then check for a cleared level.
activeBricks.RemoveAll(brick => brick == null);
if (activeBricks.Count == 0)
{
LevelCleared?.Invoke();
}
}
private void ClearExistingBricks()
{
foreach (Brick brick in activeBricks)
{
if (brick != null)
{
brick.Destroyed -= OnBrickDestroyed;
Destroy(brick.gameObject);
}
}
activeBricks.Clear();
}
}