diff --git a/login.php b/login.php index 2d4b347..4ffafeb 100644 --- a/login.php +++ b/login.php @@ -7,7 +7,7 @@ if(isset($_POST['register'])){ $u = $_POST['user']; $p = password_hash($_POST['pass'], PASSWORD_DEFAULT); $u_safe = $conn->real_escape_string($u); - $conn->query("INSERT INTO users(username,password,highscore) VALUES('$u_safe','$p',0)"); + $conn->query("INSERT INTO users(username,password,highscore_easy, highscore_medium, highscore_hard) VALUES('$u_safe','$p',0,0,0)"); if($conn->affected_rows > 0) { $_SESSION['user'] = $u; header("Location: index.php"); diff --git a/save.php b/save.php index 859492d..3b7a82f 100644 --- a/save.php +++ b/save.php @@ -1,7 +1,25 @@ query("UPDATE users SET highscore = GREATEST(highscore, $s) WHERE username='$u'"); +$diff = $_GET['diff']; + +$column = ""; +if($diff === 'easy') { + $column = "highscore_easy"; +} elseif ($diff === 'medium') { + $column = "highscore_medium"; +} elseif ($diff === 'hard') { + $column = "highscore_hard"; +} + +if($column != "") { + $conn->query("UPDATE users SET $column = GREATEST($column, $s) WHERE username='$u'"); +} ?> \ No newline at end of file diff --git a/script.js b/script.js index 26a7ce3..7fe9c9f 100644 --- a/script.js +++ b/script.js @@ -3,6 +3,8 @@ let ctx = canvas.getContext("2d"); let score = 0; let running = false; let ball, paddle, bricks, rows, cols, speed; +let currentDiff = "easy"; + const brickColors = ["#FF5733", "#33FF57", "#3357FF", "#FF33F5", "#33FFF5", "#F5FF33"]; let hitSound = new Audio("hit.wav"); @@ -10,14 +12,12 @@ let loseSound = new Audio("lose.wav"); let wallSound = new Audio("wall.wav"); let winSound = new Audio("win.wav"); -// Ambil elemen modal baru 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"); -// Event Listener untuk tombol Play Again di modal if (playAgainBtn) { playAgainBtn.addEventListener('click', () => { gameModal.style.display = 'none'; @@ -25,7 +25,6 @@ if (playAgainBtn) { }); } -// Event Listener untuk tombol Save Score di modal (jika user login) if (saveScoreBtn) { saveScoreBtn.addEventListener('click', () => { saveScore(true); @@ -47,26 +46,20 @@ function startGame(){ document.getElementById("score").textContent = score; running = true; - let diff = document.getElementById("diff").value; + // Simpan kesulitan yang dipilih ke variabel global currentDiff + let diffInput = document.getElementById("diff").value; + currentDiff = diffInput; + let initialHealth = 1; - if(diff === "easy"){ - rows = 3; - cols = 5; - speed = 2; - initialHealth = 1; + if(currentDiff === "easy"){ + rows = 3; cols = 5; speed = 2; initialHealth = 1; } - if(diff === "medium"){ - rows = 4; - cols = 7; - speed = 4; - initialHealth = 3; + if(currentDiff === "medium"){ + rows = 4; cols = 7; speed = 4; initialHealth = 3; } - if(diff === "hard"){ - rows = 6; - cols = 9; - speed = 5; - initialHealth = 5; + if(currentDiff === "hard"){ + rows = 6; cols = 9; speed = 5; initialHealth = 5; } paddle = { x:200, w:80, h:10 }; @@ -118,59 +111,41 @@ function update(){ ctx.fill(); ctx.closePath(); - // Pantulan Dinding if(ball.x + ball.r > canvas.width || ball.x - ball.r < 0){ - ball.dx *= -1; - lockSpeed(); - wallSound.currentTime = 0; - wallSound.play(); + ball.dx *= -1; lockSpeed(); + wallSound.currentTime = 0; wallSound.play(); } if(ball.y - ball.r < 0){ - ball.dy *= -1; - lockSpeed(); - wallSound.currentTime = 0; - wallSound.play(); + ball.dy *= -1; lockSpeed(); + wallSound.currentTime = 0; wallSound.play(); } - // Tabrakan Paddle if(ball.y + ball.r > canvas.height - paddle.h && ball.x > paddle.x && ball.x < paddle.x + paddle.w){ let deltaX = ball.x - (paddle.x + paddle.w/2); - let dy_abs = Math.abs(speed) * -1; - ball.dx = deltaX * 0.15; ball.dy = dy_abs; - lockSpeed(); - - wallSound.currentTime = 0; - wallSound.play(); + wallSound.currentTime = 0; wallSound.play(); } - // Tabrakan Brick bricks.forEach(b =>{ if(!b.hit && ball.x > b.x && ball.x < b.x+b.w && ball.y > b.y && ball.y < b.y+b.h){ - b.health--; ball.dy *= -1; - lockSpeed(); if (b.health <= 0) { b.hit = true; score += 10; - winSound.currentTime = 0; - winSound.play(); + winSound.currentTime = 0; winSound.play(); } else { - hitSound.currentTime = 0; - hitSound.play(); - // Perubahan warna berdasarkan sisa health + hitSound.currentTime = 0; hitSound.play(); if (b.health === 4) b.color = '#B22222'; if (b.health === 3) b.color = '#CD853F'; if (b.health === 2) b.color = '#FFA07A'; if (b.health === 1) b.color = '#F08080'; } - document.getElementById("score").textContent = score; } }); @@ -184,43 +159,33 @@ function update(){ } }); - // Cek Kemenangan - Menampilkan Modal if(bricks.every(b => b.hit)){ - winSound.currentTime = 0; - winSound.play(); + winSound.currentTime = 0; winSound.play(); running = false; showModal("YOU WIN!", score); } - // Cek Game Over - Menampilkan Modal if(ball.y > canvas.height){ - loseSound.currentTime = 0; - loseSound.play(); + loseSound.currentTime = 0; loseSound.play(); running = false; showModal("GAME OVER!", score); } } -// Pengendalian Paddle 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; }); -// Fungsi untuk menampilkan modal function showModal(title, finalScore) { modalTitle.textContent = title; - modalScore.innerHTML = `Final Score: ${finalScore}`; + modalScore.innerHTML = `Final Score: ${finalScore}
(${currentDiff.toUpperCase()})`; gameModal.style.display = 'flex'; - // Reset tombol save score if (saveScoreBtn) { saveScoreBtn.disabled = false; saveScoreBtn.textContent = 'Save Score'; @@ -234,24 +199,22 @@ function saveScore(fromModal = false){ if (isUserLoggedIn) { if (fromModal) { - if (saveScoreBtn) { saveScoreBtn.disabled = true; saveScoreBtn.textContent = 'Saving...'; saveScoreBtn.style.opacity = '0.7'; } - fetch(`save.php?score=${score}`) + // Perubahan: Menambahkan &diff=... ke URL + fetch(`save.php?score=${score}&diff=${currentDiff}`) .then(response => { if (response.ok) { - console.log("Score saved successfully!"); if (saveScoreBtn) { saveScoreBtn.textContent = 'Saved! ✅'; saveScoreBtn.style.background = 'gray'; saveScoreBtn.style.opacity = '1'; } } else { - console.error("Failed to save score."); if (saveScoreBtn) { saveScoreBtn.textContent = 'Failed ❌'; saveScoreBtn.disabled = false; @@ -267,10 +230,6 @@ function saveScore(fromModal = false){ saveScoreBtn.style.opacity = '1'; } }); - } else { - console.log("Score ready to be saved via modal."); } - } else { - console.log("Score not saved. User is not logged in."); } } \ No newline at end of file diff --git a/style.css b/style.css index 9fc0bad..08b0a34 100644 --- a/style.css +++ b/style.css @@ -17,11 +17,18 @@ h1 { letter-spacing: 1px; } +h2 { + font-size: 2.5rem; + margin-top: 20px; + text-shadow: 3px 3px 10px rgba(0,0,0,0.4); +} + .menu { margin-top: 10px; display: flex; gap: 15px; flex-wrap: wrap; + justify-content: center; } .menu a { @@ -47,6 +54,8 @@ h1 { font-size: 1.1rem; margin-bottom: 5px; text-align: center; + width: 100%; + display: block; } .game-container { @@ -108,11 +117,6 @@ button:hover { box-shadow: 0px 7px 18px rgba(255,76,76,0.55); } -@media (max-width: 600px) { - h1 { font-size: 2.2rem; } - canvas { width: 100%; height: auto; } -} - .leaderboard-body { padding: 20px; text-align: center; @@ -120,24 +124,40 @@ button:hover { display: block; } -h2 { - font-size: 2.5rem; - margin-top: 20px; - text-shadow: 3px 3px 10px rgba(0,0,0,0.4); -} - -.board-container { +.leaderboard-wrapper { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 20px; margin: 25px auto; width: 95%; - max-width: 650px; - background: rgba(255,255,255,0.10); - padding: 25px; + max-width: 1200px; +} + +.lb-column { + flex: 1; + min-width: 300px; + background: rgba(255,255,255,0.1); + padding: 20px; border-radius: 18px; backdrop-filter: blur(12px); border: 1px solid rgba(255,255,255,0.25); box-shadow: 0px 10px 25px rgba(0,0,0,0.25); } +.lb-column h3 { + margin-top: 0; + text-transform: uppercase; + font-size: 1.5rem; + letter-spacing: 2px; + margin-bottom: 15px; + text-shadow: 2px 2px 8px rgba(0,0,0,0.3); +} + +.easy-title { color: #33FF57; border-bottom: 2px solid #33FF57; display: inline-block; padding-bottom: 5px; } +.medium-title { color: #3357FF; border-bottom: 2px solid #3357FF; display: inline-block; padding-bottom: 5px; } +.hard-title { color: #FF33F5; border-bottom: 2px solid #FF33F5; display: inline-block; padding-bottom: 5px; } + table { width: 100%; border-collapse: collapse; @@ -170,7 +190,7 @@ tr:hover td { .back-button { display: inline-block; - margin-top: 25px; + margin: 25px auto; padding: 10px 22px; background: linear-gradient(45deg, #28a745, #21c064); border-radius: 25px; @@ -207,14 +227,8 @@ tr:hover td { } @keyframes popup { - from { - opacity: 0; - transform: scale(0.85); - } - to { - opacity: 1; - transform: scale(1); - } + from { opacity: 0; transform: scale(0.85); } + to { opacity: 1; transform: scale(1); } } .login-box input, .login-box button { @@ -245,6 +259,7 @@ tr:hover td { width: 90%; margin-left: 5%; } + .game-modal { display: none; position: fixed; @@ -316,4 +331,11 @@ tr:hover td { .leaderboard-link:hover, .back-link:hover { background: rgba(255, 255, 255, 0.15); +} + +@media (max-width: 600px) { + h1 { font-size: 2.2rem; } + canvas { width: 100%; height: auto; } + .leaderboard-wrapper { flex-direction: column; } + .lb-column { width: 100%; min-width: auto; } } \ No newline at end of file