diff --git a/GameLogic.js b/GameLogic.js index 0d00267..4e0691c 100644 --- a/GameLogic.js +++ b/GameLogic.js @@ -1,4 +1,4 @@ -//bagian tempat main ama buat generate game 2d +// //bagian tempat main ama buat generate game 2d var canvas = document.getElementById("game"); var content = canvas.getContext("2d"); const Text = document.getElementById("text"); @@ -25,9 +25,9 @@ KepalaKeKanan.src = "image/KepalaHorizontalKanan.png"; var KepalaKeAtas = new Image(); KepalaKeAtas.src = "image/KepalaVertikalAtas.png"; var KepalaKeKiri = new Image(); -KepalaKeKiri.src = "image/KepalaVertikalBawah.png"; +KepalaKeKiri.src = "image/KepalaVertikalBawah.png"; // Asumsi ini adalah Kepala ke KIRI var KepalaKeBawah = new Image(); -KepalaKeBawah.src = "image/KepalaHorizontalKiri.png"; +KepalaKeBawah.src = "image/KepalaHorizontalKiri.png"; // Asumsi ini adalah Kepala ke BAWAH // ↑ kepala ular var BadanHori = new Image(); @@ -50,292 +50,325 @@ RandomizeApel(); //mastiin gambar external generate dulu sebelum game start KepalaKeKanan.onload = function () { - function gameLoop() {} + // Memastikan gambar termuat, meskipun fungsi ini tidak melakukan apa-apa selain deklarasi + function gameLoop() {} }; //ngatur biar game ga langsung jalan function StartingGame(menantang) { - ModeH = menantang; - persiapan.style.display = "none"; - if (ModeH) { - RandomSpawnWall(); - } else { - Tembok = []; - } - GameStart = true; + ModeH = menantang; + persiapan.style.display = "none"; + if (ModeH) { + RandomSpawnWall(); + } else { + Tembok = []; + } + GameStart = true; } //buat ngatur batu spwan apa ga nanti document.getElementById("mode-normal").addEventListener("click", function () { - StartingGame(false); + StartingGame(false); }); document.getElementById("mode-tambahan").addEventListener("click", function () { - StartingGame(true); + StartingGame(true); }); //play again pas gameover function resetGame() { - Ular.x = 528; - Ular.y = 240; - Ular.cells = []; - Ular.maxCells = 4; - Ular.dx = grid; - Ular.dy = 0; - Tembok = []; - RandomizeApel(); - UpdateScore(0); - ModeH = false; - GameStart = false; + Ular.x = 528; + Ular.y = 240; + Ular.cells = []; + Ular.maxCells = 4; + Ular.dx = grid; + Ular.dy = 0; + Tembok = []; + RandomizeApel(); + UpdateScore(0); + ModeH = false; + // Penting: Jangan set GameStart=false di sini jika ingin memulai ulang game loop + // Kita set GameStart=false saat game over, lalu di sini kita persiapkan UI } //ngatur tombol pas gameover kemana abis di klik PlayAgain.addEventListener("click", function () { - UpDead.style.display = "none"; - resetGame(); - persiapan.style.display = "flex"; + UpDead.style.display = "none"; + resetGame(); + persiapan.style.display = "flex"; }); Udahan.addEventListener("click", function () { - UpDead.style.display = "none"; - resetGame(); + UpDead.style.display = "none"; + resetGame(); + // Opsional: Redirect ke halaman lain + // window.location.href = 'leaderboard.php'; }); //gameover terus ngatur ular ke setting awal function gameLoop() { - if (!GameStart) { - requestAnimationFrame(gameLoop); - return; - } - ClearCanvas(); - Movement(); - IntiGame(); + if (!GameStart) { + requestAnimationFrame(gameLoop); + return; + } + ClearCanvas(); + Movement(); + IntiGame(); - requestAnimationFrame(gameLoop); + requestAnimationFrame(gameLoop); } //random spawn Apel function RandomizeApel() { - var pembataslebar = Math.floor(canvas.width / grid); - var pembatastinggi = Math.floor(canvas.height / grid); - Apel.x = Math.floor(Math.random() * pembataslebar) * grid; - Apel.y = Math.floor(Math.random() * pembatastinggi) * grid; + var pembataslebar = Math.floor(canvas.width / grid); + var pembatastinggi = Math.floor(canvas.height / grid); + + do { + Apel.x = Math.floor(Math.random() * pembataslebar) * grid; + Apel.y = Math.floor(Math.random() * pembatastinggi) * grid; + + // Pastikan Apel tidak spawn di atas ular + var isOverlapSnake = Ular.cells.some(cell => cell.x === Apel.x && cell.y === Apel.y); + + // Pastikan Apel tidak spawn di atas tembok + var isOverlapWall = Tembok.some(bata => bata.x === Apel.x && bata.y === Apel.y); + + } while (isOverlapSnake || isOverlapWall); } //random spawn tembok function RandomSpawnWall() { - var TembokX, TembokY; - var kosong; - var pembataslebar = Math.floor(canvas.width / grid); - var pembatastinggi = Math.floor(canvas.height / grid); + var TembokX, TembokY; + var kosong; + var pembataslebar = Math.floor(canvas.width / grid); + var pembatastinggi = Math.floor(canvas.height / grid); - //create tembok - do { - kosong = true; + //create tembok + do { + kosong = true; - TembokX = Math.floor(Math.random() * pembataslebar) * grid; - TembokY = Math.floor(Math.random() * pembatastinggi) * grid; + TembokX = Math.floor(Math.random() * pembataslebar) * grid; + TembokY = Math.floor(Math.random() * pembatastinggi) * grid; - //cek untuk posisi yang mau di kasih tembok ada/tidak ada ularnya - for (var i = 0; i < Ular.cells.length; i++) { - if (Ular.cells[i].x === TembokX && Ular.cells[i].y === TembokY) { - kosong = false; - break; - } - } + // cek untuk posisi yang mau di kasih tembok ada/tidak ada ularnya + for (var i = 0; i < Ular.cells.length; i++) { + // Hindari spawn di sekitar kepala ular (misal 5 kotak pertama) + if (Math.abs(Ular.cells[i].x - TembokX) <= grid * 5 && Math.abs(Ular.cells[i].y - TembokY) <= grid * 5) { + kosong = false; + break; + } + } - //tidak memperbolehkan tembok spawn sama dengan apel - if (TembokX === Apel.x && TembokY === Apel.y) { - kosong = false; - } + // tidak memperbolehkan tembok spawn sama dengan apel + if (TembokX === Apel.x && TembokY === Apel.y) { + kosong = false; + } - for (var i = 0; i < Tembok.length; i++) { - if (Tembok[i].x === TembokX && Tembok[i].y === TembokY) { - kosong = false; - break; - } - } - } while (kosong === false); - Tembok.push({ x: TembokX, y: TembokY }); + // Cek agar tembok tidak menumpuk + for (var i = 0; i < Tembok.length; i++) { + if (Tembok[i].x === TembokX && Tembok[i].y === TembokY) { + kosong = false; + break; + } + } + } while (kosong === false); + Tembok.push({ x: TembokX, y: TembokY }); } -//nambah tembok tiap score kelipatan ... berapa enaknya ya? 😁 +//nambah tembok tiap score kelipatan function PenambahanTembok() { - if (ModeH) { - if (Tembok.length < Math.floor(score / 2)) { - RandomSpawnWall(); + if (ModeH) { + // Tambah tembok setiap 2 skor, tapi jangan melebihi batas (misal 15 tembok) + if (score > 0 && score % 2 === 0 && Tembok.length < 15 && Tembok.length < score / 2) { + RandomSpawnWall(); + } } - } } //set dan update score function UpdateScore(amount) { - score = amount > 0 ? score + amount : 0; - highscore = score > highscore ? score : highscore; - Text.innerHTML = - "Score: " + score + "
Highscore: " + highscore + "
Speed: " + speed; + score = amount > 0 ? score + amount : 0; + // Highscore hanya di update jika skor > highscore yang TERCATAT LOKAL. + // Highscore dari database biasanya diambil saat inisialisasi. + highscore = score > highscore ? score : highscore; + + Text.innerHTML = + "Score: " + score + "
Highscore: " + highscore + "
Speed: " + speed; - PenambahanTembok(); + PenambahanTembok(); } //tampilin gameover function GameOver() { - GameStart = false; - ClearCanvas(); + GameStart = false; + ClearCanvas(); - const modePermainan = ModeH ? "Tambahan" : "Normal"; - if (score >= 0) { - kirimSkorKeServer(score, modePermainan); - } - - // TAMPILKAN POP-UP GAME OVER - ScoreMain.innerHTML = "Score: " + score; - UpDead.style.display = "flex"; + const modePermainan = ModeH ? "Tambahan" : "Normal"; + + // Kirim skor ke server hanya jika skor lebih besar dari 0 (atau sesuai kriteria) + if (score > 0) { + kirimSkorKeServer(score, modePermainan); + } + + // TAMPILKAN POP-UP GAME OVER + ScoreMain.innerHTML = "Score: " + score; + UpDead.style.display = "flex"; } //reset isi canvas doang function ClearCanvas() { - content.clearRect(0, 0, canvas.width, canvas.height); + content.clearRect(0, 0, canvas.width, canvas.height); } //bagian utama: //ular makan dan mati pas ketemu badannya function IntiGame() { - //buat gambarnya bisa keluar - content.drawImage(ApelImage, Apel.x, Apel.y, grid, grid); - Tembok.forEach(function (bata) { - content.drawImage(TembokImage, bata.x, bata.y, grid, grid); - }); + // buat gambarnya bisa keluar + content.drawImage(ApelImage, Apel.x, Apel.y, grid, grid); + + // Gambar Tembok + Tembok.forEach(function (bata) { + content.drawImage(TembokImage, bata.x, bata.y, grid, grid); + }); - Ular.cells.forEach(function (cell, index) { - if (index === 0) { - // Logika Pemilihan Gambar Kepala Ular - var posisiKepalaImage; - if (Ular.dx === grid) { - // KANAN - posisiKepalaImage = KepalaKeKanan; - } else if (Ular.dx === -grid) { - // KIRI - posisiKepalaImage = KepalaKeKiri; - } else if (Ular.dy === -grid) { - // ATAS - posisiKepalaImage = KepalaKeBawah; - } else if (Ular.dy === grid) { - // BAWAH - posisiKepalaImage = KepalaKeAtas; - } else { - // Default, misalnya saat game baru mulai (dx=grid, dy=0, atau default awal) - posisiKepalaImage = KepalaKeKanan; - } - - content.drawImage(posisiKepalaImage, cell.x, cell.y, grid, grid); - } else { - content.drawImage(BadanHori, cell.x, cell.y, grid, grid); - } - }); - - //bagian generate ular - Ular.cells.forEach(function (cell, index) { - if (index === 0) { - content.drawImage(KepalaKeKanan, cell.x, cell.y, grid, grid); - } else { - content.drawImage(BadanHori, cell.x, cell.y, grid, grid); - } - - //buat pas ular makan Apel - if (cell.x === Apel.x && cell.y === Apel.y) { - Ular.maxCells += 1; - UpdateScore(1); - RandomizeApel(); - } - - //tabrak tembok = mati - if (index === 0) { - Tembok.forEach(function (bata) { - if (cell.x === bata.x && cell.y === bata.y) { - GameOver(); + // Gambar Ular + Ular.cells.forEach(function (cell, index) { + if (index === 0) { + // Logika Pemilihan Gambar Kepala Ular + var posisiKepalaImage; + if (Ular.dx === grid) { // KANAN + posisiKepalaImage = KepalaKeKanan; + } else if (Ular.dx === -grid) { // KIRI + posisiKepalaImage = KepalaKeKiri; + } else if (Ular.dy === -grid) { // ATAS + posisiKepalaImage = KepalaKeAtas; // Perlu dicek, di atas Anda menamakannya KepalaKeBawah? + } else if (Ular.dy === grid) { // BAWAH + posisiKepalaImage = KepalaKeBawah; // Perlu dicek, di atas Anda menamakannya KepalaKeAtas? + } else { + posisiKepalaImage = KepalaKeKanan; + } + content.drawImage(posisiKepalaImage, cell.x, cell.y, grid, grid); + } else { + // Logika sederhana untuk badan: selalu horizontal + // Catatan: untuk badan vertikal/belokan, perlu logika tambahan, tapi kita ikuti kode asli Anda. + content.drawImage(BadanHori, cell.x, cell.y, grid, grid); } - }); - } - //buat pas ular mati kena badan sendiri - for (var i = index + 1; i < Ular.cells.length; i++) - if (cell.x === Ular.cells[i].x && cell.y === Ular.cells[i].y) GameOver(); - }); + // buat pas ular makan Apel (Deteksi tabrakan kepala vs Apel) + if (index === 0 && cell.x === Apel.x && cell.y === Apel.y) { + Ular.maxCells += 1; + UpdateScore(1); + RandomizeApel(); + } + + // tabrak tembok = mati (Hanya kepala yang dicek) + if (index === 0) { + Tembok.forEach(function (bata) { + if (cell.x === bata.x && cell.y === bata.y) { + GameOver(); + } + }); + } + + // buat pas ular mati kena badan sendiri (Hanya kepala vs sisa badan) + if (index === 0) { + for (var i = 1; i < Ular.cells.length; i++) { // Mulai dari index 1 (badan) + if (cell.x === Ular.cells[i].x && cell.y === Ular.cells[i].y) { + GameOver(); + } + } + } + }); } //update teks pada speed kalau score update function Movement() { - if (++count < speed) return; - if (ArahUlar > 0) ArahUlar--; - count = 0; - Ular.x += Ular.dx; - Ular.y += Ular.dy; - if ( - Ular.x < 0 || - Ular.x >= canvas.width || - Ular.y < 0 || - Ular.y >= canvas.height - ) - GameOver(); - Ular.cells.unshift({ x: Ular.x, y: Ular.y }); - if (Ular.cells.length > Ular.maxCells) Ular.cells.pop(); + if (++count < speed) return; + if (ArahUlar > 0) ArahUlar--; + count = 0; + + // Pindahkan kepala + Ular.x += Ular.dx; + Ular.y += Ular.dy; + + // Cek batas layar + if ( + Ular.x < 0 || + Ular.x >= canvas.width || + Ular.y < 0 || + Ular.y >= canvas.height + ) + GameOver(); + + // Tambahkan posisi baru ke sel pertama (Kepala) + Ular.cells.unshift({ x: Ular.x, y: Ular.y }); + + // Hapus sel terakhir (Ekor) + if (Ular.cells.length > Ular.maxCells) Ular.cells.pop(); } //input keyboard function InputKeyboard() { - document.addEventListener("keydown", function (e) { - if (!GameStart) return; + document.addEventListener("keydown", function (e) { + if (!GameStart) return; - //jalan buat ular - if ( - ArahUlar == 0 && - ((e.code == "KeyA" && Ular.dx === 0) || - (e.code == "KeyD" && Ular.dx === 0)) - ) { - ArahUlar = 1; - Ular.dx = e.code === "KeyA" ? -grid : grid; - Ular.dy = 0; - } else if ( - ArahUlar == 0 && - ((e.code === "KeyW" && Ular.dy === 0) || - (e.code == "KeyS" && Ular.dy === 0)) - ) { - ArahUlar = 1; - Ular.dy = e.code == "KeyW" ? -grid : grid; - Ular.dx = 0; - } else if ( - ArahUlar == 0 && - ((e.code === "ArrowUp" && Ular.dy === 0) || - (e.code == "ArrowDown" && Ular.dy === 0)) - ) { - ArahUlar = 1; - Ular.dy = e.code == "ArrowUp" ? -grid : grid; - Ular.dx = 0; - } else if ( - ArahUlar == 0 && - ((e.code === "ArrowLeft" && Ular.dx === 0) || - (e.code == "ArrowRight" && Ular.dx === 0)) - ) { - ArahUlar = 1; - Ular.dx = e.code == "ArrowLeft" ? -grid : grid; - Ular.dy = 0; - } + // Key A, D (Kiri/Kanan) + if ( + ArahUlar == 0 && + ((e.code == "KeyA" && Ular.dx === 0) || + (e.code == "KeyD" && Ular.dx === 0)) + ) { + ArahUlar = 1; + Ular.dx = e.code === "KeyA" ? -grid : grid; + Ular.dy = 0; + } + // Key W, S (Atas/Bawah) + else if ( + ArahUlar == 0 && + ((e.code === "KeyW" && Ular.dy === 0) || + (e.code == "KeyS" && Ular.dy === 0)) + ) { + ArahUlar = 1; + Ular.dy = e.code == "KeyW" ? -grid : grid; + Ular.dx = 0; + } + // Arrow Up, Down + else if ( + ArahUlar == 0 && + ((e.code === "ArrowUp" && Ular.dy === 0) || + (e.code == "ArrowDown" && Ular.dy === 0)) + ) { + ArahUlar = 1; + Ular.dy = e.code == "ArrowUp" ? -grid : grid; + Ular.dx = 0; + } + // Arrow Left, Right + else if ( + ArahUlar == 0 && + ((e.code === "ArrowLeft" && Ular.dx === 0) || + (e.code == "ArrowRight" && Ular.dx === 0)) + ) { + ArahUlar = 1; + Ular.dx = e.code == "ArrowLeft" ? -grid : grid; + Ular.dy = 0; + } - if (e.code === "KeyE" || e.code == "KeyQ") - speed = - e.code == "KeyE" && speed > 2 - ? speed - 1 - : e.code == "KeyQ" && speed < 30 - ? speed + 1 - : speed; - }); + // Key E (Cepat/Kurangi speed), Key Q (Lambat/Tambah speed) + if (e.code === "KeyE" || e.code == "KeyQ") + speed = + e.code == "KeyE" && speed > 2 + ? speed - 1 + : e.code == "KeyQ" && speed < 30 + ? speed + 1 + : speed; + }); } function kirimSkorKeServer(skor, modePermainan) { console.log(`Mengirim skor ${skor} (Mode: ${modePermainan}) ke server...`); - fetch('score.php', { + // Ganti 'score.php' sesuai dengan path di server Anda + fetch('score.php', { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -347,20 +380,28 @@ function kirimSkorKeServer(skor, modePermainan) { }) .then(response => { if (!response.ok) { - return response.json().then(error => { throw new Error(error.message || 'Gagal menyimpan skor'); }); + return response.json().then(error => { throw new Error(error.message || 'Gagal menyimpan skor'); }); } return response.json(); }) .then(data => { if (data.status === 'success') { console.log('✅ Berhasil:', data.message); + // Opsional: Perbarui highscore lokal dengan skor yang baru jika ini highscore + if (data.message.includes('Highscore baru')) { + highscore = skor; + UpdateScore(0); // Update tampilan score/highscore + } } else { console.error('❌ Error Server:', data.message); } }) .catch((error) => { console.error('⚠️ Error Jaringan atau Proses:', error.message); + // Tampilkan pesan error ke user jika perlu + // alert("Gagal terhubung ke server skor. Pastikan Anda sudah login."); }); } + InputKeyboard(); -gameLoop(); +gameLoop(); \ No newline at end of file diff --git a/leaderboard.php b/leaderboard.php index 0262f84..5b41166 100644 --- a/leaderboard.php +++ b/leaderboard.php @@ -1,6 +1,6 @@ - Leaderboard - - +

🥇 Leaderboard Top 10 🥈

+ +

Skor Tertinggi Anda (): PTS

+ +

Silakan login untuk melihat skor Anda.

+ @@ -64,9 +97,7 @@ if($result) { - - '; } - ?> diff --git a/score.php b/score.php index 043c825..1200b27 100644 --- a/score.php +++ b/score.php @@ -1,4 +1,5 @@ 'error', 'message' => 'Anda harus login untuk menyimpan skor.']); exit; @@ -17,9 +18,7 @@ if (!isset($_SESSION['id_user'])) { $input = json_decode(file_get_contents('php://input'), true); -$user_id = $_SESSION['id_user']; $final_score = (int)($input['score'] ?? 0); -$game_mode = $input['mode'] ?? 'Normal'; if ($final_score <= 0) { http_response_code(400); @@ -27,24 +26,56 @@ if ($final_score <= 0) { exit; } -try { - $sql = "INSERT INTO scores (id_user, score_value, mode) VALUES (:id_user, :score_value, :mode)"; - $stmt = $pdo->prepare($sql); +$user_id = null; +if (isset($_SESSION['id_user'])) { + $user_id = $_SESSION['id_user']; +} elseif (isset($_SESSION['username'])) { - $stmt->execute([ - ':id_user' => $user_id, - ':score_value' => $final_score, - ':mode' => $game_mode - ]); + $username = $_SESSION['username']; - echo json_encode([ - 'status' => 'success', - 'message' => 'Skor berhasil disimpan.', - 'skor_terkirim' => $final_score - ]); + $getID_sql = "SELECT id_user FROM users WHERE username = '$username'"; + $result_id = mysqli_query($koneksi, $getID_sql); + + if ($result_id && mysqli_num_rows($result_id) > 0) { + $row = mysqli_fetch_assoc($result_id); + $user_id = $row['id_user']; + } +} -} catch (\PDOException $e) { +if (!$user_id) { + http_response_code(401); + echo json_encode(['status' => 'error', 'message' => 'ID pengguna tidak ditemukan.']); + exit; +} + +$sql = "UPDATE users SET score = ? WHERE id_user = ? AND score < ?"; + +if ($stmt = mysqli_prepare($koneksi, $sql)) { + mysqli_stmt_bind_param($stmt, "iii", $final_score, $user_id, $final_score); + $exec = mysqli_stmt_execute($stmt); + + if ($exec) { + $rows_affected = mysqli_stmt_affected_rows($stmt); + + if ($rows_affected > 0) { + $message = 'Skor berhasil diperbarui. Ini adalah Highscore baru!'; + } else { + $message = 'Skor berhasil dikirim, tetapi skor tidak lebih tinggi dari Highscore sebelumnya.'; + } + + echo json_encode([ + 'status' => 'success', + 'message' => $message, + 'skor_terkirim' => $final_score + ]); + } else { + http_response_code(500); + echo json_encode(['status' => 'error', 'message' => 'Gagal menjalankan kueri update: ' . mysqli_stmt_error($stmt)]); + } + mysqli_stmt_close($stmt); + +} else { http_response_code(500); - echo json_encode(['status' => 'error', 'message' => 'Terjadi kesalahan server saat menyimpan data.']); + echo json_encode(['status' => 'error', 'message' => 'Gagal mempersiapkan statement: ' . mysqli_error($koneksi)]); } ?> \ No newline at end of file
PTS
Belum ada Pemain