Source file unity-csharp/arcade-classics/breakout/BreakoutGame.cs from the GDnD code examples. Download raw file
// GDnD wiki example
// Demonstrates: the game loop owning score and lives, level reset on clear, and game over on no lives
// Related pages: [[overview-arcade-classics-as-learning-projects]], [[unity-gamemanager-pattern]], [[observer-pattern]], [[ui-design]]
using UnityEngine;
// Central controller: owns score and lives, builds each level, serves the ball,
// and responds to the two events that drive Breakout — a brick destroyed and a
// level cleared. This is the step-2 version of [[unity-gamemanager-pattern]].
public class BreakoutGame : MonoBehaviour
{
[SerializeField] private Ball2D ball;
[SerializeField] private BrickGrid grid;
[SerializeField] private int startingLives = 3;
[Tooltip("Optional on-screen HUD. If empty, messages print to the Console.")]
[SerializeField] private ArcadeHud hud;
public int Score { get; private set; }
public int Lives { get; private set; }
private void OnEnable()
{
ball.Missed += OnBallMissed;
grid.BrickDestroyed += OnBrickDestroyed;
grid.LevelCleared += OnLevelCleared;
}
private void OnDisable()
{
ball.Missed -= OnBallMissed;
grid.BrickDestroyed -= OnBrickDestroyed;
grid.LevelCleared -= OnLevelCleared;
}
private void Start()
{
StartGame();
}
private void StartGame()
{
Score = 0;
Lives = startingLives;
RefreshHud();
grid.BuildLevel();
ball.Serve();
}
private void OnBrickDestroyed(int value)
{
Score += value;
RefreshHud();
}
private void OnBallMissed()
{
Lives--;
RefreshHud();
ShowMessage($"Ball lost. Lives remaining: {Lives}");
if (Lives > 0)
{
ball.Serve();
}
else
{
ShowMessage($"Game over. Final score: {Score}");
StartGame();
}
}
private void OnLevelCleared()
{
ShowMessage("Level cleared!");
grid.BuildLevel();
ball.Serve();
}
// HUD helpers. The game owns the numbers; ArcadeHud only displays them.
// With no HUD assigned, messages fall back to the Console instead of throwing.
private void RefreshHud()
{
if (hud != null)
{
hud.SetStatus($"Score {Score} Lives {Lives}");
}
}
private void ShowMessage(string message)
{
if (hud != null)
{
hud.ShowMessage(message);
}
else
{
Debug.Log(message);
}
}
}