From 76f09674560250409b86f1a6e50c0a7b2fa15a69 Mon Sep 17 00:00:00 2001 From: Evelyn Sucitro Date: Mon, 1 Dec 2025 14:13:46 +0700 Subject: [PATCH] Leaderboard --- Animation_Leaderboard.js | 57 ++++++++++++++ Leaderboard.html | 164 +-------------------------------------- Leaderboard.js | 107 +++++++++++++------------ Score.php | 57 ++++++-------- 4 files changed, 142 insertions(+), 243 deletions(-) create mode 100644 Animation_Leaderboard.js diff --git a/Animation_Leaderboard.js b/Animation_Leaderboard.js new file mode 100644 index 0000000..437af15 --- /dev/null +++ b/Animation_Leaderboard.js @@ -0,0 +1,57 @@ +// Particles Animation +const particlesContainer = document.getElementById('particles'); + +function createParticle() { + const particle = document.createElement('div'); + particle.className = 'particle'; + + particle.style.left = Math.random() * 100 + '%'; + particle.style.top = Math.random() * 100 + '%'; + + const size = 3 + Math.random() * 4; + particle.style.width = size + 'px'; + particle.style.height = size + 'px'; + + const duration = 3 + Math.random() * 5; + const delay = Math.random() * 2; + const moveX = (Math.random() - 0.5) * 200; + + const animationName = `float-${Date.now()}-${Math.random()}`; + const keyframes = ` + @keyframes ${animationName} { + 0% { + transform: translateY(0) translateX(0); + opacity: 0; + } + 10% { + opacity: 1; + } + 90% { + opacity: 1; + } + 100% { + transform: translateY(-100vh) translateX(${moveX}px); + opacity: 0; + } + } + `; + + const style = document.createElement('style'); + style.innerHTML = keyframes; + document.head.appendChild(style); + + particle.style.animation = `${animationName} ${duration}s ${delay}s ease-in-out forwards`; + + particlesContainer.appendChild(particle); + + setTimeout(() => { + particle.remove(); + style.remove(); + }, (duration + delay) * 1000); +} + +setInterval(createParticle, 300); + +for (let i = 0; i < 25; i++) { + setTimeout(createParticle, i * 100); +} \ No newline at end of file diff --git a/Leaderboard.html b/Leaderboard.html index da23a3a..a88f02f 100644 --- a/Leaderboard.html +++ b/Leaderboard.html @@ -19,167 +19,11 @@

Leaderboard

-
-
-
Players
-
10
-
-
-
Your Rank
-
5
-
-
-
High Score
-
9,850
-
-
- - - -
-
-
- 5 -
-
-
- You -
-
-
-
4,890
-
Points
-
-
-
+ +
+ - + \ No newline at end of file diff --git a/Leaderboard.js b/Leaderboard.js index 437af15..8329105 100644 --- a/Leaderboard.js +++ b/Leaderboard.js @@ -1,57 +1,62 @@ -// Particles Animation -const particlesContainer = document.getElementById('particles'); +document.addEventListener("DOMContentLoaded", () => { + loadLeaderboard(); +}); -function createParticle() { - const particle = document.createElement('div'); - particle.className = 'particle'; - - particle.style.left = Math.random() * 100 + '%'; - particle.style.top = Math.random() * 100 + '%'; - - const size = 3 + Math.random() * 4; - particle.style.width = size + 'px'; - particle.style.height = size + 'px'; - - const duration = 3 + Math.random() * 5; - const delay = Math.random() * 2; - const moveX = (Math.random() - 0.5) * 200; - - const animationName = `float-${Date.now()}-${Math.random()}`; - const keyframes = ` - @keyframes ${animationName} { - 0% { - transform: translateY(0) translateX(0); - opacity: 0; +function loadLeaderboard() { + fetch('Leaderboard.php') + .then(response => response.json()) + .then(data => { + if (data.status === "success") { + renderLeaderboard(data.leaderboard); } - 10% { - opacity: 1; - } - 90% { - opacity: 1; - } - 100% { - transform: translateY(-100vh) translateX(${moveX}px); - opacity: 0; - } - } - `; - - const style = document.createElement('style'); - style.innerHTML = keyframes; - document.head.appendChild(style); - - particle.style.animation = `${animationName} ${duration}s ${delay}s ease-in-out forwards`; - - particlesContainer.appendChild(particle); - - setTimeout(() => { - particle.remove(); - style.remove(); - }, (duration + delay) * 1000); + }) + .catch(error => console.error("Error loading leaderboard:", error)); } -setInterval(createParticle, 300); +function renderLeaderboard(players) { + const listContainer = document.getElementById('leaderboardList'); + if (!listContainer) return; // Safety check -for (let i = 0; i < 25; i++) { - setTimeout(createParticle, i * 100); + listContainer.innerHTML = ""; // Hapus data dummy statis + + players.forEach((player, index) => { + const rank = index + 1; + let rankClass = 'rank-other'; + + // Tentukan styling berdasarkan ranking + if (rank === 1) rankClass = 'rank-1'; + else if (rank === 2) rankClass = 'rank-2'; + else if (rank === 3) rankClass = 'rank-3'; + + // Format angka skor dengan koma (contoh: 1,000) + // Fallback jika score tidak valid + const scoreVal = parseInt(player.score) || 0; + const formattedScore = new Intl.NumberFormat().format(scoreVal); + + const itemHtml = ` +
  • +
    ${rank}
    +
    +
    ${escapeHtml(player.username)}
    +
    +
    +
    ${formattedScore}
    +
    Points
    +
    +
  • + `; + + listContainer.insertAdjacentHTML('beforeend', itemHtml); + }); +} + +// Mencegah XSS attack (keamanan tambahan) +function escapeHtml(text) { + if (!text) return text; + return text + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); } \ No newline at end of file diff --git a/Score.php b/Score.php index d880aeb..4cc4984 100644 --- a/Score.php +++ b/Score.php @@ -1,15 +1,16 @@ "error", "message" => "Belum login"]); +// 1. Pastikan user login & user_id tersedia +if (!isset($_SESSION['username']) || !isset($_SESSION['user_id'])) { + echo json_encode(["status" => "error", "message" => "Belum login atau sesi tidak valid"]); exit; } $username = $_SESSION['username']; +$user_id = $_SESSION['user_id']; // AMBIL ID DARI SESSION $score = intval($_POST['score'] ?? 0); // Validasi score @@ -18,62 +19,54 @@ if ($score <= 0) { exit; } -// Validasi score maksimal (opsional, sesuaikan dengan game Anda) -if ($score > 999999) { - echo json_encode(["status" => "error", "message" => "Skor terlalu tinggi"]); - exit; -} - -// Cek apakah user sudah punya record -$checkStmt = $conn->prepare("SELECT score FROM leaderboard WHERE username = ?"); -$checkStmt->bind_param("s", $username); +// Cek apakah user sudah punya record di leaderboard +$checkStmt = $conn->prepare("SELECT score FROM leaderboard WHERE user_id = ?"); +$checkStmt->bind_param("i", $user_id); // Cek berdasarkan ID, lebih akurat daripada username $checkStmt->execute(); $result = $checkStmt->get_result(); if ($result->num_rows > 0) { - // User sudah ada, cek apakah score baru lebih tinggi + // --- UPDATE --- $row = $result->fetch_assoc(); $oldScore = $row['score']; if ($score > $oldScore) { - // Update dengan score yang lebih tinggi - $updateStmt = $conn->prepare("UPDATE leaderboard SET score = ? WHERE username = ?"); - $updateStmt->bind_param("is", $score, $username); + // Update score berdasarkan user_id + $updateStmt = $conn->prepare("UPDATE leaderboard SET score = ?, username = ? WHERE user_id = ?"); + // Kita update username juga untuk jaga-jaga kalau user ganti nama + $updateStmt->bind_param("isi", $score, $username, $user_id); if ($updateStmt->execute()) { echo json_encode([ "status" => "success", - "message" => "Skor berhasil diperbarui!", - "newHighScore" => true, - "score" => $score + "message" => "High Score baru tercatat!", + "newHighScore" => true ]); } else { - echo json_encode(["status" => "error", "message" => "Gagal memperbarui skor"]); + echo json_encode(["status" => "error", "message" => "Gagal update database"]); } $updateStmt->close(); } else { - // Score baru lebih rendah, tidak perlu update echo json_encode([ "status" => "success", - "message" => "Skor tidak diperbarui (skor lama lebih tinggi)", - "newHighScore" => false, - "currentHighScore" => $oldScore + "message" => "Skor lebih rendah dari rekor sebelumnya.", + "newHighScore" => false ]); } } else { - // User belum ada, insert baru - $insertStmt = $conn->prepare("INSERT INTO leaderboard (username, score) VALUES (?, ?)"); - $insertStmt->bind_param("si", $username, $score); + // --- INSERT BARU --- + // Masukkan user_id, username, dan score + $insertStmt = $conn->prepare("INSERT INTO leaderboard (user_id, username, score) VALUES (?, ?, ?)"); + $insertStmt->bind_param("isi", $user_id, $username, $score); if ($insertStmt->execute()) { echo json_encode([ "status" => "success", - "message" => "Skor berhasil disimpan!", - "newHighScore" => true, - "score" => $score + "message" => "Skor pertama berhasil disimpan!", + "newHighScore" => true ]); } else { - echo json_encode(["status" => "error", "message" => "Gagal menyimpan skor"]); + echo json_encode(["status" => "error", "message" => "Gagal insert database"]); } $insertStmt->close(); }