Skip to content
Game 14 Unit 19 of 32 1 hr learning time

Bomb Collision

Falling bombs hit the player — a bullet pool for enemy projectiles with a dual threat.

59% of Blockstorm

Bombs fall from bombers, but so far they pass through the player harmlessly. This unit adds bomb-to-player collision: when a falling bomb reaches the player position, the player loses a life. Up to three bombs can be active simultaneously, tracked in a small array pool. The player must now dodge while shooting.

The Program

5 REM === BOMB COLLISION ===
10 BORDER 0: PAPER 0: INK 7: CLS
15 GO SUB 800
20 LET sc = 0: LET hi = 0: LET li = 3
22 LET wv = 1: LET ne = 10: LET sp = 4
24 LET nr = 2
25 DIM e(10): DIM r(10): DIM t(10): DIM h(10)
27 DIM b(1): DIM c(1): DIM d(1)
28 DIM m(3): DIM n(3): DIM o(3)
29 FOR i = 1 TO 3: LET o(i) = 0: NEXT i
30 REM row 1: 5 drones
32 FOR i = 1 TO 5
34 LET e(i) = (i - 1) * 2: LET r(i) = 0: LET t(i) = 1: LET h(i) = 1
36 NEXT i
38 REM row 2: mixed types
40 LET e(6) = 0: LET r(6) = 1: LET t(6) = 2: LET h(6) = 1
42 LET e(7) = 2: LET r(7) = 1: LET t(7) = 1: LET h(7) = 1
44 LET e(8) = 4: LET r(8) = 1: LET t(8) = 3: LET h(8) = 2
46 LET e(9) = 6: LET r(9) = 1: LET t(9) = 4: LET h(9) = 1
48 LET e(10) = 8: LET r(10) = 1: LET t(10) = 4: LET h(10) = 1
50 LET fx = 10: LET fy = 2: LET fd = 1: LET tk = 0
52 LET px = 15: LET py = 20
54 LET d(1) = 0
60 CLS
62 GO SUB 600
65 GO SUB 500
80 REM === game loop ===
85 LET k$ = INKEY$
90 IF k$ = "o" OR k$ = "O" THEN GO SUB 300
95 IF k$ = "p" OR k$ = "P" THEN GO SUB 310
100 IF k$ = " " THEN GO SUB 320
105 GO SUB 350
110 LET tk = tk + 1
115 IF tk >= sp THEN GO SUB 400: LET tk = 0
120 GO SUB 450
125 IF fy + nr > 19 THEN GO TO 700
130 GO SUB 600
135 GO SUB 650
140 GO TO 80
300 REM === move left ===
302 IF px <= 1 THEN RETURN
304 PRINT AT py, px; " "
306 LET px = px - 1
308 PRINT AT py, px; INK 7; CHR$ 152
309 RETURN
310 REM === move right ===
312 IF px >= 30 THEN RETURN
314 PRINT AT py, px; " "
316 LET px = px + 1
318 PRINT AT py, px; INK 7; CHR$ 152
319 RETURN
320 REM === fire ===
322 IF d(1) = 1 THEN RETURN
324 LET b(1) = px: LET c(1) = py - 1: LET d(1) = 1
326 PRINT AT c(1), b(1); INK 7; CHR$ 148
328 BEEP 0.01, 20
329 RETURN
350 REM === move bullets ===
352 IF d(1) = 0 THEN RETURN
354 PRINT AT c(1), b(1); " "
356 LET c(1) = c(1) - 1
358 IF c(1) < 1 THEN LET d(1) = 0: RETURN
360 LET ht = 0
364 FOR j = 1 TO ne
366 IF h(j) <= 0 THEN GO TO 380
368 LET sx = fx + e(j): LET sy = fy + r(j)
370 IF b(1) = sx AND c(1) = sy THEN LET ht = j: GO TO 382
380 NEXT j
382 IF ht = 0 THEN PRINT AT c(1), b(1); INK 7; CHR$ 148: RETURN
384 LET d(1) = 0
386 LET h(ht) = h(ht) - 1
388 IF h(ht) <= 0 THEN GO SUB 510: RETURN
390 PRINT AT fy + r(ht), fx + e(ht); INK 7; CHR$ (143 + t(ht)): BEEP 0.01, 10
394 PAUSE 2: PRINT AT fy + r(ht), fx + e(ht); INK 6; CHR$ (143 + t(ht))
396 RETURN
400 REM === move formation ===
402 FOR i = 1 TO ne
404 IF h(i) <= 0 THEN GO TO 420
406 LET sx = fx + e(i): LET sy = fy + r(i)
408 IF sx >= 1 AND sx <= 30 AND sy >= 1 AND sy <= 21 THEN PRINT AT sy, sx; " "
420 NEXT i
422 LET fx = fx + fd
424 IF fx + 10 > 30 OR fx < 1 THEN LET fd = -fd: LET fy = fy + 1
428 FOR i = 1 TO ne
430 IF h(i) <= 0 THEN GO TO 445
432 LET sx = fx + e(i): LET sy = fy + r(i)
434 IF sx < 1 OR sx > 30 OR sy < 1 OR sy > 21 THEN GO TO 445
436 LET ci = 4
438 IF t(i) = 2 THEN LET ci = 5
439 IF t(i) = 3 THEN LET ci = 6
440 IF t(i) = 4 THEN LET ci = 3
442 PRINT AT sy, sx; INK ci; CHR$ (143 + t(i))
445 NEXT i
447 RETURN
450 REM === move bombs ===
452 FOR i = 1 TO 3
454 IF o(i) = 0 THEN GO TO 480
456 PRINT AT n(i), m(i); " "
458 LET n(i) = n(i) + 1
460 IF n(i) > 21 THEN LET o(i) = 0: GO TO 480
462 IF m(i) = px AND n(i) = py THEN GO SUB 530: LET o(i) = 0: GO TO 480
464 PRINT AT n(i), m(i); INK 2; CHR$ 153
480 NEXT i
482 REM drop new bomb from bombers
484 FOR i = 1 TO ne
486 IF h(i) <= 0 OR t(i) <> 4 THEN GO TO 496
488 IF INT (RND * 30) <> 0 THEN GO TO 496
490 FOR j = 1 TO 3
492 IF o(j) = 0 THEN LET m(j) = fx + e(i): LET n(j) = fy + r(i) + 1: LET o(j) = 1: LET j = 3
494 NEXT j
496 NEXT i
498 RETURN
500 REM === draw player ===
505 PRINT AT py, px; INK 7; CHR$ 152
508 RETURN
510 REM === enemy destroyed ===
512 LET sx = fy + r(ht): LET sy = fx + e(ht)
514 PRINT AT sx, sy; INK 2; CHR$ 149
516 BEEP 0.02, -5: BEEP 0.02, -10
518 LET pt = 10
519 IF t(ht) = 2 THEN LET pt = 25
520 IF t(ht) = 3 THEN LET pt = 50
521 IF t(ht) = 4 THEN LET pt = 30
522 LET sc = sc + pt
524 IF sc > hi THEN LET hi = sc
528 RETURN
530 REM === player hit ===
534 LET li = li - 1
536 PRINT AT py, px; INK 2; CHR$ 149
538 BEEP 0.1, -10: BEEP 0.1, -15
540 PAUSE 25
542 PRINT AT py, px; " "
544 IF li <= 0 THEN GO TO 700
546 LET px = 15
548 GO SUB 500
549 RETURN
600 REM === draw HUD ===
605 PRINT AT 0, 0; INK 7; BRIGHT 1; "SC:"; sc; "  HI:"; hi; "  LV:"; li; " W"; wv; "  "
610 RETURN
650 REM === check wave clear ===
652 LET w = 0
654 FOR i = 1 TO ne
656 IF h(i) > 0 THEN LET w = 1
658 NEXT i
660 IF w = 1 THEN RETURN
662 PRINT AT 10, 9; INK 7; BRIGHT 1; "WAVE CLEAR!"
664 BEEP 0.1, 12: BEEP 0.1, 16: BEEP 0.2, 19
670 PAUSE 50
685 RETURN
700 REM === game over ===
705 CLS
710 PRINT AT 8, 10; INK 2; BRIGHT 1; "GAME OVER"
715 PRINT AT 10, 7; INK 7; "Score: "; sc
720 PRINT AT 12, 7; INK 7; "High: "; hi
730 PRINT AT 18, 6; INK 7; "Press any key"
735 PAUSE 0
740 LET li = 3: LET sc = 0
745 GO TO 20
800 REM === define UDGs ===
805 FOR i = 0 TO 13
810 FOR j = 0 TO 7
815 READ a
820 POKE USR CHR$ (65 + i) + j, a
825 NEXT j
830 NEXT i
835 RETURN
840 REM UDG A: drone
842 DATA 36, 126, 219, 255, 255, 102, 66, 0
844 REM UDG B: scout
846 DATA 24, 60, 126, 255, 219, 24, 36, 0
848 REM UDG C: tank
850 DATA 126, 255, 255, 255, 255, 255, 126, 0
852 REM UDG D: bomber
854 DATA 66, 231, 255, 126, 60, 90, 36, 0
856 REM UDG E: bullet
858 DATA 16, 56, 16, 16, 0, 0, 0, 0
860 REM UDG F: explosion
862 DATA 36, 153, 66, 129, 66, 153, 36, 0
864 REM UDG G: double shot
866 DATA 84, 170, 84, 170, 84, 170, 84, 0
868 REM UDG H: shield
870 DATA 60, 126, 255, 255, 255, 126, 60, 0
872 REM UDG I: player ship
874 DATA 16, 56, 56, 124, 254, 254, 130, 0
876 REM UDG J: enemy bomb
878 DATA 16, 16, 56, 16, 0, 0, 0, 0
880 REM UDG K: explosion 2
882 DATA 129, 66, 36, 0, 36, 66, 129, 0
884 REM UDG L: shield icon
886 DATA 60, 126, 126, 126, 60, 24, 0, 0
888 REM UDG M: drone frame 2
890 DATA 66, 102, 255, 255, 219, 126, 36, 0
892 REM UDG N: scout frame 2
894 DATA 36, 24, 219, 255, 126, 60, 24, 0

How It Works

Lines 28 dimension the bomb arrays: DIM m(3): DIM n(3): DIM o(3). Array m() holds bomb columns, n() holds bomb rows, and o() holds active flags. Three slots means at most three bombs can be on screen at once.

Lines 450-498 manage bombs each frame. For each active bomb: erase at current position, move down one row, check if it has left the screen (clear it), check if it has reached the player position (trigger death). If the bomb is still active and on screen, draw it as UDG J (CHR$ 153) in red.

Lines 484-496 handle new bomb drops. For each living bomber in the formation, RND generates a 1-in-30 chance of dropping a bomb. If the random check passes and a free slot exists in the bomb pool (any o(j) that equals 0), a new bomb is created at one row below the bomber.

Line 462 checks bomb-player collision: IF m(i) = px AND n(i) = py THEN GO SUB 530. Same position-based comparison as bullet-enemy collision, but reversed — the projectile comes from above rather than below.

The Bullet Pool Pattern

The bomb pool works identically to the player bullet system, scaled to three slots. Each slot has a position (column, row) and an active flag. Creating a bomb means finding an empty slot and filling it. Destroying a bomb means clearing its active flag.

This pattern scales. Three bombs. Five bombs. Ten bombs. The only change is the DIM size and the loop limit. The code that moves, draws and collision-checks bombs is the same regardless of how many exist. You have already seen this pattern with enemy arrays — the bullet pool is the same idea applied to projectiles.

Three-Bomb Limit

Why limit bombs to three? Performance. Each active bomb requires a PRINT AT to erase, a PRINT AT to draw, and position comparisons to check. Three bombs add six PRINT AT calls and three comparisons per frame. Ten bombs would add twenty PRINT AT calls — a noticeable slowdown in BASIC. The three-bomb limit keeps the game responsive while still creating dodging pressure.

Try This

Increase the pool. Change DIM to 5 and the loop limit to 5. With five bombs falling simultaneously, is the game more exciting or just chaotic?

Bomb speed. Move bombs downward every other frame instead of every frame. Slower bombs give the player more time to dodge but stay on screen longer, occupying pool slots. How does this trade-off affect gameplay?