Breakout the GameMaker way: spawn a brick wall with two loops, use collision events for bouncing, add particle explosions with the built-in particle system, and screen shake, juice is a first-class citizen here.
Need the game setup? Each episode builds a new game on the same GameMaker setup: a room, objects, and their Create / Step / Draw events. New here or need a refresher? Episode 1 setup → · GML Cheatsheet →
1
🏓
Mouse Paddle & Ball
mouse_x control plus a served ball
Active
🎯
Goal for this step
Set up the paddle on mouse control and a serving ball.
1New project: spr/obj for paddle (110×14) and ball (14×14), room 700×520, dark background.
2Paddle Step: x = clamp(mouse_x, 55, room_width - 55);, one line, mouse control done (origin centred!).
var colors = [c_red, c_orange, c_yellow, c_lime, c_aqua];
for (var r = 0; r < 5; r++) {
for (var c = 0; c < 10; c++) {
var b = instance_create_layer(
c * 68 + 44, r * 26 + 60, "Instances", obj_brick);
b.image_blend = colors[r];
b.points = (5 - r) * 10;
}
}var colors = [c_red, c_orange, c_yellow, c_lime, c_aqua];
for (var r = 0; r < 5; r++) {
for (var c = 0; c < 10; c++) {
var b = instance_create_layer(
c * 68 + 44, r * 26 + 60, "Instances", obj_brick);
b.image_blend = colors[r];
b.points = (5 - r) * 10;
}
}
⌨️
Code Challenge
+20 XP
Spawn and tint one brick:
obj_game · Create
var b = var b = (c * 68 + 44, r * 26 + 60, "Instances", obj_brick);
b.(c * 68 + 44, r * 26 + 60, "Instances", obj_brick);
b. = colors[r]; = colors[r];
💡 Hint: The modern spawn function takes x, y, layer name and object; tinting uses the blend colour variable.
🧠
Knowledge Check
+15 XP
image_blend lets 5 brick colours come from…
A5 different sprites
BONE white sprite tinted at spawn time, less art, instant palette changes
CThe room background
3
💥
Brick Breaking & Paddle Spin
Two collision events do all the physics
Locked
🎯
Goal for this step
Wire both collision events: bricks die, paddle steers.
1obj_ball + obj_brick collision: vspeed = -vspeed; add other.points to the score; with (other) instance_destroy();
2with runs code AS another instance, the cleanest way to affect what you hit.
3obj_ball + obj_paddle collision: bounce up and steer by hit position (the eternal spin formula).
4Guard the paddle bounce with vspeed > 0 so edge clips cannot double-bounce.
obj_ball · Collision with obj_brick
vspeed = -vspeed;
global.score += other.points;
with (other) instance_destroy();
/// Collision with obj_paddle:
if (vspeed > 0) {
vspeed = -vspeed;
hspeed = (x - other.x) / 12;
if (hspeed == 0) hspeed = 1;
}vspeed = -vspeed;
global.score += other.points;
with (other) instance_destroy();
/// Collision with obj_paddle:
if (vspeed > 0) {
vspeed = -vspeed;
hspeed = (x - other.x) / 12;
if (hspeed == 0) hspeed = 1;
}
✏️
Fill in the Blanks
+15 XP
The statement runs code as another instance, here destroying the brick the ball touched. The paddle bounce is guarded by vspeed > .
🧠
Knowledge Check
+15 XP
with (other) instance_destroy(); destroys…
AThe ball
BThe brick that was hit, with switches "who is running this code"
CAll bricks
4
✨
Native Particles
GameMaker’s built-in particle system
Locked
🎯
Goal for this step
Make bricks explode into sparks using the particle engine.
1GameMaker has particles BUILT IN, no manual arrays like the JS version.
2obj_game Create: make a particle system and define a "spark" type: tiny squares, random directions, shrink over life, brief lifespan.
3On brick death: part_particles_create at the brick’s position, 12 sparks.
4Tint the burst to match the brick with part_type_color1(..., image_blend) inside the collision.
5One-time setup, one call per burst. Native beats manual.
obj_game · Create (particles)
global.ps = part_system_create();
global.pt_spark = part_type_create();
part_type_shape(global.pt_spark, pt_shape_square);
part_type_size(global.pt_spark, 0.08, 0.14, -0.005, 0);
part_type_speed(global.pt_spark, 2, 5, -0.1, 0);
part_type_direction(global.pt_spark, 0, 359, 0, 0);
part_type_life(global.pt_spark, 20, 35);
// on brick death (in the collision event):
part_particles_create(global.ps, other.x, other.y,
global.pt_spark, 12);global.ps = part_system_create();
global.pt_spark = part_type_create();
part_type_shape(global.pt_spark, pt_shape_square);
part_type_size(global.pt_spark, 0.08, 0.14, -0.005, 0);
part_type_speed(global.pt_spark, 2, 5, -0.1, 0);
part_type_direction(global.pt_spark, 0, 359, 0, 0);
part_type_life(global.pt_spark, 20, 35);
// on brick death (in the collision event):
part_particles_create(global.ps, other.x, other.y,
global.pt_spark, 12);
✏️
Fill in the Blanks
+15 XP
GameMaker particles need a particle plus particle types. Spawning a burst is one call: with a count of 12.
🧠
Knowledge Check
+15 XP
The advantage of a defined particle TYPE reused for every burst is…
ABigger particles
BConfigure once, emit thousands cheaply, the engine batches and animates them for you
CIt works without a room
5
📳
Screen Shake & Lives
Camera wobble plus the lose-a-ball flow
Locked
🎯
Goal for this step
Add impact shake and the three-lives system.
1Room editor → Viewports: enable Viewport 0 (same as Episode 2's Platformer). Without this, camera_set_view_pos does nothing visible at all.
2Shake: obj_game holds shake = 0; brick deaths set it to 4; each Step it decays and offsets the camera by random(-shake..shake) around its resting position.
3Lives: ball past the bottom → lives--, reset ball to centre with a fresh serve; 0 → rm_gameover.
4Draw hearts in Draw GUI with a small heart sprite in a loop.
if (shake > 0) {
shake -= 0.3;
var cam = view_camera[0];
// static vars capture the camera's resting position once, so the
// wobble always offsets FROM there instead of overwriting it
static base_x = camera_get_view_x(cam);
static base_y = camera_get_view_y(cam);
camera_set_view_pos(cam,
base_x + random_range(-shake, shake),
base_y + random_range(-shake, shake));
}if (shake > 0) {
shake -= 0.3;
var cam = view_camera[0];
// static vars capture the camera's resting position once, so the
// wobble always offsets FROM there instead of overwriting it
static base_x = camera_get_view_x(cam);
static base_y = camera_get_view_y(cam);
camera_set_view_pos(cam,
base_x + random_range(-shake, shake),
base_y + random_range(-shake, shake));
}
💡 Hint: Ease the value down a little each frame; the ranged random function picks the wobble offset.
🧠
Knowledge Check
+15 XP
Shake decaying by 0.3/frame (not instantly stopping) makes the effect…
ALonger and floatier
BSnap hard then settle smoothly, a punch followed by recovery, like real impacts
CRandom forever
6
🏆
Win Condition & Polish Pass
instance_number and the finishing checklist
Locked
🎯
Goal for this step
Detect the cleared wall and complete the game loop.
1Win check, one line in obj_game Step: if (instance_number(obj_brick) == 0) room_goto(rm_win);
2rm_win / rm_gameover rooms with score display and R-to-restart (reset globals!).
3Polish checklist: ball speed cap (±7), serve delay (a 60-frame alarm before the ball moves, meet Alarm events!), sound effects (audio_play_sound on hits, the built-in bounce sounds work).
4Three engines, three Breakouts, you now FEEL what engines automate. Episode 4 continues in the Space Shooter trainer!