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 @@
-
Skor Tertinggi Anda (): PTS
+ +Silakan login untuk melihat skor Anda.
+| - | PTS | -Belum ada Pemain | '; } - ?> 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