let canvas = document.getElementById("game"); let ctx = canvas.getContext("2d"); let score = 0; let running = false; let ball, paddle, bricks, rows, cols, speed; let currentDiff = "easy"; let balls = []; // Array untuk multiple balls let powerUps = []; // Array untuk power-ups const brickColors = ["#FF5733", "#33FF57", "#3357FF", "#FF33F5", "#33FFF5", "#F5FF33"]; let hitSound = new Audio("hit.wav"); let loseSound = new Audio("lose.wav"); let wallSound = new Audio("wall.wav"); let winSound = new Audio("win.wav"); const gameModal = document.getElementById("gameModal"); const modalTitle = document.getElementById("modalTitle"); const modalScore = document.getElementById("modalScore"); const saveScoreBtn = document.getElementById("saveScoreBtn"); const playAgainBtn = document.getElementById("playAgainBtn"); if (playAgainBtn) { playAgainBtn.addEventListener('click', () => { gameModal.style.display = 'none'; startGame(); }); } if (saveScoreBtn) { saveScoreBtn.addEventListener('click', () => { saveScore(true); }); } // Modifikasi: lockSpeed sekarang menerima objek bola function lockSpeed(b) { let currentSpeedSq = b.dx * b.dx + b.dy * b.dy; if (currentSpeedSq > 0.0001) { let currentSpeed = Math.sqrt(currentSpeedSq); let ratio = speed / currentSpeed; b.dx *= ratio; b.dy *= ratio; } } function startGame(){ score = 0; document.getElementById("score").textContent = score; running = true; // Simpan kesulitan yang dipilih ke variabel global currentDiff let diffInput = document.getElementById("diff").value; currentDiff = diffInput; let initialHealth = 1; if(currentDiff === "easy"){ rows = 3; cols = 5; speed = 2; initialHealth = 1; } if(currentDiff === "medium"){ rows = 4; cols = 7; speed = 4; initialHealth = 3; } if(currentDiff === "hard"){ rows = 6; cols = 9; speed = 5; initialHealth = 5; } paddle = { x:200, w:80, h:10 }; ball = { x:240, y:200, dx:speed, dy:-speed, r:6 }; balls = [ball]; // Reset ke satu bola bricks = []; powerUps = []; // Reset power-ups let brickW = (canvas.width - cols * 5) / cols; let brickH = 15; for(let r=0;r { b.x += b.dx; b.y += b.dy; // Gambar bola ctx.beginPath(); ctx.arc(b.x, b.y, b.r, 0, Math.PI*2); ctx.fillStyle = "#ffffff"; ctx.fill(); ctx.closePath(); // Collision dengan dinding if(b.x + b.r > canvas.width || b.x - b.r < 0){ b.dx *= -1; lockSpeed(b); // wallSound.currentTime = 0; wallSound.play(); } if(b.y - b.r < 0){ b.dy *= -1; lockSpeed(b); // wallSound.currentTime = 0; wallSound.play(); } // Collision dengan paddle if(b.y + b.r > canvas.height - paddle.h && b.x > paddle.x && b.x < paddle.x + paddle.w){ let deltaX = b.x - (paddle.x + paddle.w/2); let dy_abs = Math.abs(speed) * -1; b.dx = deltaX * 0.15; b.dy = dy_abs; lockSpeed(b); // wallSound.currentTime = 0; wallSound.play(); } // Jika bola jatuh, hapus if(b.y > canvas.height){ balls.splice(index, 1); } }); // Jika tidak ada bola lagi, game over if(balls.length === 0){ loseSound.currentTime = 0; loseSound.play(); running = false; showModal("GAME OVER!", score); return; } // Collision bola dengan bricks balls.forEach(b => { bricks.forEach(br => { if(!br.hit && b.x > br.x && b.x < br.x+br.w && b.y > br.y && b.y < br.y+br.h){ br.health--; b.dy *= -1; lockSpeed(b); if (br.health <= 0) { br.hit = true; score += 10; // winSound.currentTime = 0; winSound.play(); // Spawn power-up if (Math.random() < 0.3) { spawnPowerUp(br.x + br.w/2, br.y + br.h/2); } } else { // hitSound.currentTime = 0; hitSound.play(); if (br.health === 4) br.color = '#B22222'; if (br.health === 3) br.color = '#CD853F'; if (br.health === 2) br.color = '#FFA07A'; if (br.health === 1) br.color = '#F08080'; } document.getElementById("score").textContent = score; } }); }); // Gambar bricks bricks.forEach(b =>{ if(!b.hit){ ctx.fillStyle = b.color; ctx.fillRect(b.x,b.y,b.w,b.h); ctx.strokeStyle = "#000000"; ctx.strokeRect(b.x,b.y,b.w,b.h); } }); // Update power-ups powerUps.forEach((pu, index) => { pu.y += 2; ctx.fillStyle = pu.color; ctx.fillRect(pu.x - 5, pu.y - 5, 10, 10); if (pu.y + 5 > canvas.height - paddle.h && pu.x > paddle.x && pu.x < paddle.x + paddle.w) { activatePowerUp(pu.type); powerUps.splice(index, 1); } if (pu.y > canvas.height) { powerUps.splice(index, 1); } }); if(bricks.every(b => b.hit)){ winSound.currentTime = 0; winSound.play(); running = false; showModal("YOU WIN!", score); } } canvas.addEventListener("mousemove", e =>{ if (!paddle || !canvas) return; const canvasRect = canvas.getBoundingClientRect(); let newX = e.clientX - canvasRect.left - paddle.w/2; if(newX < 0) newX = 0; if(newX > canvas.width - paddle.w) newX = canvas.width - paddle.w; paddle.x = newX; }); function showModal(title, finalScore) { modalTitle.textContent = title; modalScore.innerHTML = `Final Score: ${finalScore}
(${currentDiff.toUpperCase()})`; gameModal.style.display = 'flex'; if (saveScoreBtn) { saveScoreBtn.disabled = false; saveScoreBtn.textContent = 'Save Score'; saveScoreBtn.style.background = 'linear-gradient(45deg, #28a745, #21c064)'; saveScoreBtn.style.opacity = '1'; } } function saveScore(fromModal = false){ let isUserLoggedIn = document.querySelector('.user-info'); if (isUserLoggedIn) { if (fromModal) { if (saveScoreBtn) { saveScoreBtn.disabled = true; saveScoreBtn.textContent = 'Saving...'; saveScoreBtn.style.opacity = '0.7'; } fetch(`save.php?score=${score}&diff=${currentDiff}`) .then(response => { if (response.ok) { if (saveScoreBtn) { saveScoreBtn.textContent = 'Saved! ✅'; saveScoreBtn.style.background = 'gray'; saveScoreBtn.style.opacity = '1'; } } else { if (saveScoreBtn) { saveScoreBtn.textContent = 'Failed ❌'; saveScoreBtn.disabled = false; saveScoreBtn.style.opacity = '1'; } } }) .catch(error => { console.error("Error saving score:", error); if (saveScoreBtn) { saveScoreBtn.textContent = 'Error ❌'; saveScoreBtn.disabled = false; saveScoreBtn.style.opacity = '1'; } }); } } } // Fungsi spawn power-up function spawnPowerUp(x, y) { const types = ['multiBall', 'largeBall', 'largePaddle', 'fastBall']; const type = types[Math.floor(Math.random() * types.length)]; let color; switch (type) { case 'multiBall': color = '#FF0000'; break; case 'largeBall': color = '#00FF00'; break; case 'largePaddle': color = '#0000FF'; break; case 'fastBall': color = '#FFFF00'; break; } powerUps.push({ x: x, y: y, type: type, color: color }); } // Fungsi activate power-up function activatePowerUp(type) { switch (type) { case 'multiBall': // Tambah bola baru dari posisi bola pertama if (balls.length > 0) { let newBall = { x: balls[0].x, y: balls[0].y, dx: -balls[0].dx, dy: balls[0].dy, r: balls[0].r }; balls.push(newBall); } break; case 'largeBall': balls.forEach(b => b.r += 2); break; case 'largePaddle': paddle.w += 20; break; case 'fastBall': speed += 1; balls.forEach(b => lockSpeed(b)); break; } }