TECH DETAILS

Shoot Them Up - Day 5

Advanced Level

Table of Contents

01 / Wave Spawning System

Enemies spawn in waves with increasing difficulty. Each wave completes when all enemies are destroyed.

let wave = 1; let enemies = []; function spawnWave() { // More rows and columns as waves progress const rows = Math.min(3 + Math.floor(wave / 3), 5); const cols = Math.min(4 + Math.floor(wave / 2), 8); const spacing = 55; const startX = (canvas.width - cols * spacing) / 2; for (let row = 0; row < rows; row++) { for (let col = 0; col < cols; col++) { // Enemy type based on row (top = strongest) const type = row === 0 ? 2 : (row === 1 ? 1 : 0); enemies.push({ x: startX + col * spacing, y: -50 - row * 50, // Start above screen targetY: 60 + row * 50, // Move down to this Y type: type, health: type + 1, // HP based on type moveDir: 1, canShoot: type >= 1 // Only strong enemies shoot }); } } } // Check if wave is complete if (enemies.length === 0) { wave++; setTimeout(spawnWave, 1000); // Brief pause between waves }

02 / Particle Explosions

When enemies die, spawn particles that fly outward and fade. Creates satisfying destruction feedback.

let particles = []; function createExplosion(x, y, size) { for (let i = 0; i < 12; i++) { particles.push({ x: x, y: y, // Random velocity in all directions vx: (Math.random() - 0.5) * 8, vy: (Math.random() - 0.5) * 8, size: Math.random() * size + 2, life: 30, // Frames until death color: Math.random() > 0.5 ? '#ff6633' : '#ffcc00' }); } } function updateParticles() { for (let i = particles.length - 1; i >= 0; i--) { const p = particles[i]; // Apply velocity p.x += p.vx; p.y += p.vy; // Decay p.life--; p.size *= 0.95; // Shrink over time if (p.life <= 0) { particles.splice(i, 1); } } } function drawParticles() { for (const p of particles) { ctx.globalAlpha = p.life / 30; // Fade out ctx.fillStyle = p.color; ctx.beginPath(); ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2); ctx.fill(); } ctx.globalAlpha = 1; }

03 / Power-Up System

Enemies have a chance to drop power-ups. Effects are temporary using setTimeout.

const powerUpTypes = ['life', 'rapid', 'shield']; // Spawn power-up when enemy dies (10% chance) if (Math.random() < 0.1) { powerUps.push({ x: enemy.x, y: enemy.y, type: powerUpTypes[Math.floor(Math.random() * powerUpTypes.length)] }); } // Apply power-up effect function collectPowerUp(powerUp) { switch (powerUp.type) { case 'life': lives++; break; case 'rapid': // Faster fire rate for 5 seconds player.fireRate = 80; // Normal is 150 setTimeout(() => { player.fireRate = 150; }, 5000); break; case 'shield': player.shielded = true; setTimeout(() => { player.shielded = false; }, 3000); break; } }
Visual Feedback

Always show when a power-up is active (glow, icon, etc.) so players know their temporary ability.

04 / Enemy Types & AI

Different enemy types have different behaviors, health, and point values.

function updateEnemy(enemy) { // Move down to target Y position if (enemy.y < enemy.targetY) { enemy.y += 2; } else { // Side-to-side movement (faster in later waves) enemy.x += enemy.moveDir * (0.5 + wave * 0.1); // Reverse at screen edges if (enemy.x <= 10 || enemy.x >= canvas.width - 45) { enemy.moveDir *= -1; } // Shooting (stronger enemies only) if (enemy.canShoot) { enemy.shootTimer--; if (enemy.shootTimer <= 0) { enemyShoot(enemy); // Faster shooting in later waves enemy.shootTimer = 150 - wave * 5 + Math.random() * 100; } } } } // Point values by type const pointValues = [100, 200, 300]; // type 0, 1, 2 score += pointValues[enemy.type];

05 / Bullet Management

Efficiently manage bullets with pooling-like behavior and off-screen cleanup.

let playerBullets = []; let enemyBullets = []; let lastFire = 0; function fireBullet() { const now = Date.now(); if (now - lastFire < player.fireRate) return; lastFire = now; playerBullets.push({ x: player.x + player.width / 2 - 3, y: player.y, width: 6, height: 15, speed: 10 }); } function updateBullets() { // Update and remove off-screen bullets for (let i = playerBullets.length - 1; i >= 0; i--) { playerBullets[i].y -= playerBullets[i].speed; if (playerBullets[i].y < -20) { playerBullets.splice(i, 1); } } // Same for enemy bullets (moving down) for (let i = enemyBullets.length - 1; i >= 0; i--) { enemyBullets[i].y += enemyBullets[i].speed; if (enemyBullets[i].y > canvas.height + 20) { enemyBullets.splice(i, 1); } } }

06 / Parallax Starfield

Stars at different speeds create depth illusion. Faster stars appear closer.

const stars = []; // Initialize stars with varying speeds for (let i = 0; i < 100; i++) { stars.push({ x: Math.random() * canvas.width, y: Math.random() * canvas.height, size: Math.random() * 2 + 0.5, speed: Math.random() * 2 + 1 // Varying speeds }); } function updateStars() { for (const star of stars) { star.y += star.speed; // Wrap around when off screen if (star.y > canvas.height) { star.y = 0; star.x = Math.random() * canvas.width; } } } function drawStars() { for (const star of stars) { // Brighter stars are "closer" (larger, faster) ctx.fillStyle = `rgba(255, 255, 255, ${0.5 + star.size / 4})`; ctx.beginPath(); ctx.arc(star.x, star.y, star.size, 0, Math.PI * 2); ctx.fill(); } }