Breakout is Unity’s perfect prefab lesson: build one brick, stamp out fifty from code, wire up physics bounces, particle bursts and a proper game-state manager with restart.
Set up the arena and a paddle that tracks the mouse.
1New 2D project Breakout. Walls: three thin sprites with BoxCollider2D (left, right, top).
2Paddle: square sprite scaled (1.6, 0.25), collider, and the script below.
3Camera.main.ScreenToWorldPoint converts pixel mouse coordinates into world space, the conversion every engine needs (remember getBoundingClientRect in JS?).
4Clamp x to the court and lock y. Play, silky mouse control.
PaddleMouse.cs
using UnityEngine;
public class PaddleMouse : MonoBehaviour
{
void Update()
{
Vector3 world = Camera.main.ScreenToWorldPoint(Input.mousePosition);
transform.position = new Vector3(
Mathf.Clamp(world.x, -7f, 7f),
-4.2f,
0f);
}
}
✏️
Fill in the Blanks
+15 XP
Pixel coordinates become world coordinates via Camera.main.. The paddle’s y is locked at while x follows the mouse.
🧠
Knowledge Check
+15 XP
Why must mouse input be converted before use?
AMice are analog
BInput.mousePosition is in SCREEN pixels; the game lives in world units, two different coordinate spaces
CC# requires Vector3
2
📦
The Brick Prefab
Build one brick, save it as a reusable asset
Locked
🎯
Goal for this step
Create a brick GameObject and turn it into a prefab.
1Build ONE brick: sprite (scale 1.2×0.45), BoxCollider2D, and a Brick.cs script holding a points value and a colour setter.
2Now the Unity superpower: drag the brick from the Hierarchy into the Project panel, it becomes a Prefab (blue icon), a saved template.
3Delete the scene copy. The template lives on as an asset.
4Edit the prefab → every future copy updates. One source of truth for every brick in every level.
Brick.cs
using UnityEngine;
public class Brick : MonoBehaviour
{
public int points = 10;
public void SetRow(int row, Color color)
{
points = (5 - row) * 10;
GetComponent<SpriteRenderer>().color = color;
}
}
✏️
Fill in the Blanks
+15 XP
A saved GameObject template is a , created by dragging from the Hierarchy into the panel. Editing the prefab updates copy.
🧠
Knowledge Check
+15 XP
Prefabs are Unity’s answer to which pattern from your earlier series?
AThe game loop
BThe object blueprint (GameMaker objects, C++ classes), define once, instantiate many
CScreen shake
3
🌀
Instantiate the Wall
Spawn 50 bricks from a loop at runtime
Locked
🎯
Goal for this step
Generate the whole wall from code using the prefab.
1A WallBuilder script on an empty GameObject: nested loops calling Instantiate(brickPrefab, position, rotation).
2Drag the prefab asset into the script’s public field, code meets assets.
3Colour by row from a public Color array (editable in the Inspector, your palette is designer-tweakable).
4Position maths: x from column, y from row, exactly like every wall you have built.
WallBuilder.cs
using UnityEngine;
public class WallBuilder : MonoBehaviour
{
public Brick brickPrefab;
public Color[] rowColors = new Color[5];
void Start()
{
for (int row = 0; row < 5; row++)
{
for (int col = 0; col < 10; col++)
{
Vector3 pos = new Vector3(-6.75f + col * 1.5f,
4f - row * 0.6f, 0f);
Brick b = Instantiate(brickPrefab, pos, Quaternion.identity);
b.SetRow(row, rowColors[row]);
b.transform.parent = transform; // tidy hierarchy
}
}
}
}
⌨️
Code Challenge
+20 XP
Spawn one configured brick:
WallBuilder.cs
Brick b = (brickPrefab, pos, Quaternion.identity);
b.(row, rowColors[row]);
💡 Hint: Unity’s spawn function clones the prefab at a position; then the brick configures itself from its row.
🧠
Knowledge Check
+15 XP
b.transform.parent = transform; exists purely to…
AMake bricks bounce
BNest spawned bricks under the builder in the Hierarchy, organisation, not behaviour
CDouble the points
4
💥
Ball, Bounce & Brick Death
Physics ball plus OnCollisionEnter2D destruction
Locked
🎯
Goal for this step
Wire the ball’s physics and destroy bricks on contact.
1Ball setup from Episode 1: Rigidbody2D (gravity 0, continuous), bouncy material, launched downward at start.
2Ball script’s OnCollisionEnter2D: if we hit a Brick component, add its points and Destroy(brick.gameObject).
3Paddle steering: on paddle contact, override the x velocity based on hit offset (the eternal spin), keeping overall speed constant with normalized * speed.
4A speed clamp in FixedUpdate keeps physics honest (min 5, max 9).
Ball.cs
using UnityEngine;
public class Ball : MonoBehaviour
{
public float speed = 6f;
Rigidbody2D rb;
void OnCollisionEnter2D(Collision2D hit)
{
Brick brick = hit.gameObject.GetComponent<Brick>();
if (brick != null)
{
GameManager.Instance.AddScore(brick.points);
Destroy(brick.gameObject);
}
if (hit.gameObject.CompareTag("Paddle"))
{
float offset = transform.position.x - hit.transform.position.x;
Vector2 dir = new Vector2(offset * 1.2f, 1f).normalized;
rb.linearVelocity = dir * speed;
}
}
}
✏️
Fill in the Blanks
+15 XP
Checking WHAT was hit uses <Brick>() and a null test. Removing the brick from the world is (brick.gameObject).
🧠
Knowledge Check
+15 XP
GetComponent<Brick>() returning null means…
AA bug
BThe thing we hit has no Brick component, it was a wall or paddle. Null IS the answer "not a brick"
CThe brick is empty
5
✨
Particles & Juice
A ParticleSystem prefab bursts on every brick
Locked
🎯
Goal for this step
Add Unity’s particle system for brick-break explosions.
1GameObject → Effects → Particle System. Configure a burst: Duration 0.3, Looping OFF, Start Speed 4, Start Size 0.12, Emission → Bursts → one burst of 15, Shape → Sphere.
2Stop Action: Destroy, the effect cleans itself up. No manual lifetime code!
3Prefab it, then Instantiate at the brick’s position on death (one line in the ball script).
4Tint via the main module’s Start Color, pass the brick’s colour through.
5Compare: JS particles = 40 lines of manual physics; Unity = a component you configure. Both worth knowing.
Ball.cs (addition)
public ParticleSystem burstPrefab;
// inside the brick-hit branch:
ParticleSystem burst = Instantiate(
burstPrefab,
brick.transform.position,
Quaternion.identity);
var main = burst.main;
main.startColor = brick.GetComponent<SpriteRenderer>().color;
✏️
Fill in the Blanks
+15 XP
The particle system cleans itself up via Stop Action: . A one-off explosion uses a in the Emission module rather than continuous emission.
🧠
Knowledge Check
+15 XP
Configuring particles in the Inspector vs coding them by hand (your JS version) trades…
AQuality for speed
BFine control for speed and power, engines give you a Ferrari, hand-coding taught you how engines work
CNothing, they are identical
6
🔁
Game Manager & Scene Reload
Singleton scoring, lives, and one-line restart
Locked
🎯
Goal for this step
Finish with lives, win/lose states and a restart that just works.
1GameManager with the singleton pattern (Instance) so any script reaches it without wiring, used sparingly, it is the community-standard manager pattern.
2A bottom trigger zone costs a life and respawns the ball; zero lives → game over UI.
3Win when no Brick components remain: FindObjectsByType<Brick>().Length == 0 (checked when bricks die).
4Restart is gloriously lazy in Unity: SceneManager.LoadScene(SceneManager.GetActiveScene().name), the entire scene rebuilds itself, wall included (Start() runs again!).
GameManager.cs
using UnityEngine;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour
{
public static GameManager Instance;
void Awake() { Instance = this; }
public void Restart()
{
Time.timeScale = 1f;
SceneManager.LoadScene(
SceneManager.GetActiveScene().name);
}
}
⌨️
Code Challenge
+20 XP
Reload the current scene to restart everything:
GameManager.cs
SceneManager.(
SceneManager.().name);
💡 Hint: One function loads a scene by name; the other asks which scene is currently running.
🧠
Knowledge Check
+15 XP
Reloading the scene restarts the game perfectly because…
AUnity saves your progress
BEverything respawns fresh and every Start() re-runs, including the wall builder. State reset for free
CIt clears the disk
🎉🏆🎮✨🎉
Workshop Complete!
Prefabs, Instantiate, particles and scene management, the core Unity production loop. Onwards to Episode 4: the top-down shooter!