Leaderboard

This commit is contained in:
Evelyn Sucitro 2025-12-01 14:13:46 +07:00
parent b7db68222c
commit 76f0967456
4 changed files with 142 additions and 243 deletions

57
Animation_Leaderboard.js Normal file
View File

@ -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);
}

View File

@ -19,167 +19,11 @@
<div class="container"> <div class="container">
<h1>Leaderboard</h1> <h1>Leaderboard</h1>
<div class="stats-container"> <ul class="leaderboard-list" id="leaderboardList"></ul>
<div class="stat-box">
<div class="stat-label">Players</div>
<div class="stat-value" id="totalPlayers">10</div>
</div>
<div class="stat-box">
<div class="stat-label">Your Rank</div>
<div class="stat-value" id="yourRank">5</div>
</div>
<div class="stat-box">
<div class="stat-label">High Score</div>
<div class="stat-value" id="highScore">9,850</div>
</div>
</div>
<ul class="leaderboard-list" id="leaderboardList">
<li class="leaderboard-item rank-1">
<div class="rank-badge">1</div>
<div class="player-info">
<div class="player-name">CyberKing</div>
</div>
<div class="player-score">
<div class="score-value">9,850</div>
<div class="score-label">Points</div>
</div>
</li>
<li class="leaderboard-item rank-2">
<div class="rank-badge">2</div>
<div class="player-info">
<div class="player-name">NeonMaster</div>
</div>
<div class="player-score">
<div class="score-value">8,200</div>
<div class="score-label">Points</div>
</div>
</li>
<li class="leaderboard-item rank-3">
<div class="rank-badge">3</div>
<div class="player-info">
<div class="player-name">PixelHunter</div>
</div>
<div class="player-score">
<div class="score-value">6,950</div>
<div class="score-label">Points</div>
</div>
</li>
<li class="leaderboard-item rank-other">
<div class="rank-badge">4</div>
<div class="player-info">
<div class="player-name">StarGazer</div>
</div>
<div class="player-score">
<div class="score-value">5,420</div>
<div class="score-label">Points</div>
</div>
</li>
<li class="leaderboard-item rank-other">
<div class="rank-badge">5</div>
<div class="player-info">
<div class="player-name">You</div>
</div>
<div class="player-score">
<div class="score-value">4,890</div>
<div class="score-label">Points</div>
</div>
</li>
<li class="leaderboard-item rank-other">
<div class="rank-badge">6</div>
<div class="player-info">
<div class="player-name">ByteWarrior</div>
</div>
<div class="player-score">
<div class="score-value">4,320</div>
<div class="score-label">Points</div>
</div>
</li>
<li class="leaderboard-item rank-other">
<div class="rank-badge">7</div>
<div class="player-info">
<div class="player-name">DataDragon</div>
</div>
<div class="player-score">
<div class="score-value">3,850</div>
<div class="score-label">Points</div>
</div>
</li>
<li class="leaderboard-item rank-other">
<div class="rank-badge">8</div>
<div class="player-info">
<div class="player-name">SyntaxSage</div>
</div>
<div class="player-score">
<div class="score-value">3,120</div>
<div class="score-label">Points</div>
</div>
</li>
<li class="leaderboard-item rank-other">
<div class="rank-badge">9</div>
<div class="player-info">
<div class="player-name">LogicLord</div>
</div>
<div class="player-score">
<div class="score-value">2,780</div>
<div class="score-label">Points</div>
</div>
</li>
<li class="leaderboard-item rank-other">
<div class="rank-badge">10</div>
<div class="player-info">
<div class="player-name">BugSlayer</div>
</div>
<div class="player-score">
<div class="score-value">2,340</div>
<div class="score-label">Points</div>
</div>
</li>
</ul>
<div class="your-rank-container">
<div class="your-rank-item">
<div
class="rank-badge"
style="
background: linear-gradient(135deg, #00ff88, #00eaff);
color: #0c001a;
box-shadow: 0 0 20px rgba(0, 255, 136, 0.8);
"
>
5
</div>
<div class="player-info">
<div
class="player-name"
style="
color: #00ff88;
filter: drop-shadow(0 0 8px rgba(0, 255, 136, 0.6));
"
>
You
</div>
</div>
<div
class="player-score"
style="color: #00ff88; text-shadow: 0 0 15px rgba(0, 255, 136, 0.8)"
>
<div class="score-value" style="font-size: 24px">4,890</div>
<div class="score-label">Points</div>
</div>
</div>
</div>
</div> </div>
<script src="Leaderboard.js"></script> <script src="Leaderboard.js"></script>
<script src="Animation_Leaderboard.js"></script>
</body> </body>
</html> </html>

View File

@ -1,57 +1,62 @@
// Particles Animation document.addEventListener("DOMContentLoaded", () => {
const particlesContainer = document.getElementById('particles'); loadLeaderboard();
});
function createParticle() { function loadLeaderboard() {
const particle = document.createElement('div'); fetch('Leaderboard.php')
particle.className = 'particle'; .then(response => response.json())
.then(data => {
if (data.status === "success") {
renderLeaderboard(data.leaderboard);
}
})
.catch(error => console.error("Error loading leaderboard:", error));
}
particle.style.left = Math.random() * 100 + '%'; function renderLeaderboard(players) {
particle.style.top = Math.random() * 100 + '%'; const listContainer = document.getElementById('leaderboardList');
if (!listContainer) return; // Safety check
const size = 3 + Math.random() * 4; listContainer.innerHTML = ""; // Hapus data dummy statis
particle.style.width = size + 'px';
particle.style.height = size + 'px';
const duration = 3 + Math.random() * 5; players.forEach((player, index) => {
const delay = Math.random() * 2; const rank = index + 1;
const moveX = (Math.random() - 0.5) * 200; let rankClass = 'rank-other';
const animationName = `float-${Date.now()}-${Math.random()}`; // Tentukan styling berdasarkan ranking
const keyframes = ` if (rank === 1) rankClass = 'rank-1';
@keyframes ${animationName} { else if (rank === 2) rankClass = 'rank-2';
0% { else if (rank === 3) rankClass = 'rank-3';
transform: translateY(0) translateX(0);
opacity: 0; // Format angka skor dengan koma (contoh: 1,000)
} // Fallback jika score tidak valid
10% { const scoreVal = parseInt(player.score) || 0;
opacity: 1; const formattedScore = new Intl.NumberFormat().format(scoreVal);
}
90% { const itemHtml = `
opacity: 1; <li class="leaderboard-item ${rankClass}">
} <div class="rank-badge">${rank}</div>
100% { <div class="player-info">
transform: translateY(-100vh) translateX(${moveX}px); <div class="player-name">${escapeHtml(player.username)}</div>
opacity: 0; </div>
} <div class="player-score">
} <div class="score-value">${formattedScore}</div>
<div class="score-label">Points</div>
</div>
</li>
`; `;
const style = document.createElement('style'); listContainer.insertAdjacentHTML('beforeend', itemHtml);
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); // Mencegah XSS attack (keamanan tambahan)
function escapeHtml(text) {
for (let i = 0; i < 25; i++) { if (!text) return text;
setTimeout(createParticle, i * 100); return text
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
} }

View File

@ -1,15 +1,16 @@
<?php <?php
session_start(); session_start();
header('Content-Type: application/json'); header('Content-Type: application/json');
include 'Connection.php'; require 'Connection.php'; // Gunakan require agar stop jika file tidak ada
// Pastikan user sudah login // 1. Pastikan user login & user_id tersedia
if (!isset($_SESSION['username'])) { if (!isset($_SESSION['username']) || !isset($_SESSION['user_id'])) {
echo json_encode(["status" => "error", "message" => "Belum login"]); echo json_encode(["status" => "error", "message" => "Belum login atau sesi tidak valid"]);
exit; exit;
} }
$username = $_SESSION['username']; $username = $_SESSION['username'];
$user_id = $_SESSION['user_id']; // AMBIL ID DARI SESSION
$score = intval($_POST['score'] ?? 0); $score = intval($_POST['score'] ?? 0);
// Validasi score // Validasi score
@ -18,62 +19,54 @@ if ($score <= 0) {
exit; exit;
} }
// Validasi score maksimal (opsional, sesuaikan dengan game Anda) // Cek apakah user sudah punya record di leaderboard
if ($score > 999999) { $checkStmt = $conn->prepare("SELECT score FROM leaderboard WHERE user_id = ?");
echo json_encode(["status" => "error", "message" => "Skor terlalu tinggi"]); $checkStmt->bind_param("i", $user_id); // Cek berdasarkan ID, lebih akurat daripada username
exit;
}
// Cek apakah user sudah punya record
$checkStmt = $conn->prepare("SELECT score FROM leaderboard WHERE username = ?");
$checkStmt->bind_param("s", $username);
$checkStmt->execute(); $checkStmt->execute();
$result = $checkStmt->get_result(); $result = $checkStmt->get_result();
if ($result->num_rows > 0) { if ($result->num_rows > 0) {
// User sudah ada, cek apakah score baru lebih tinggi // --- UPDATE ---
$row = $result->fetch_assoc(); $row = $result->fetch_assoc();
$oldScore = $row['score']; $oldScore = $row['score'];
if ($score > $oldScore) { if ($score > $oldScore) {
// Update dengan score yang lebih tinggi // Update score berdasarkan user_id
$updateStmt = $conn->prepare("UPDATE leaderboard SET score = ? WHERE username = ?"); $updateStmt = $conn->prepare("UPDATE leaderboard SET score = ?, username = ? WHERE user_id = ?");
$updateStmt->bind_param("is", $score, $username); // Kita update username juga untuk jaga-jaga kalau user ganti nama
$updateStmt->bind_param("isi", $score, $username, $user_id);
if ($updateStmt->execute()) { if ($updateStmt->execute()) {
echo json_encode([ echo json_encode([
"status" => "success", "status" => "success",
"message" => "Skor berhasil diperbarui!", "message" => "High Score baru tercatat!",
"newHighScore" => true, "newHighScore" => true
"score" => $score
]); ]);
} else { } else {
echo json_encode(["status" => "error", "message" => "Gagal memperbarui skor"]); echo json_encode(["status" => "error", "message" => "Gagal update database"]);
} }
$updateStmt->close(); $updateStmt->close();
} else { } else {
// Score baru lebih rendah, tidak perlu update
echo json_encode([ echo json_encode([
"status" => "success", "status" => "success",
"message" => "Skor tidak diperbarui (skor lama lebih tinggi)", "message" => "Skor lebih rendah dari rekor sebelumnya.",
"newHighScore" => false, "newHighScore" => false
"currentHighScore" => $oldScore
]); ]);
} }
} else { } else {
// User belum ada, insert baru // --- INSERT BARU ---
$insertStmt = $conn->prepare("INSERT INTO leaderboard (username, score) VALUES (?, ?)"); // Masukkan user_id, username, dan score
$insertStmt->bind_param("si", $username, $score); $insertStmt = $conn->prepare("INSERT INTO leaderboard (user_id, username, score) VALUES (?, ?, ?)");
$insertStmt->bind_param("isi", $user_id, $username, $score);
if ($insertStmt->execute()) { if ($insertStmt->execute()) {
echo json_encode([ echo json_encode([
"status" => "success", "status" => "success",
"message" => "Skor berhasil disimpan!", "message" => "Skor pertama berhasil disimpan!",
"newHighScore" => true, "newHighScore" => true
"score" => $score
]); ]);
} else { } else {
echo json_encode(["status" => "error", "message" => "Gagal menyimpan skor"]); echo json_encode(["status" => "error", "message" => "Gagal insert database"]);
} }
$insertStmt->close(); $insertStmt->close();
} }