Last Revisi

This commit is contained in:
Benedictus Rendra Andhika Putra Prasetya 2025-12-16 11:51:52 +07:00
parent 8e49077466
commit 61f14cea00

227
game.php
View File

@ -4,15 +4,12 @@ if (!isset($_SESSION['user'])) {
header("Location: index.php"); header("Location: index.php");
exit; exit;
} }
$username = $_SESSION['user']; $username = $_SESSION['user'];
// koneksi db // koneksi db
$conn = new mysqli("localhost", "root", "", "dodge_game"); $conn = new mysqli("localhost", "root", "", "dodge_game");
// Ambil skin user dari database // Ambil skin user dari database
$q = $conn->query("SELECT skin FROM users WHERE username='$username'"); $q = $conn->query("SELECT skin FROM users WHERE username='$username'");
$skinColor = $q->fetch_assoc()["skin"]; $skinColor = $q->fetch_assoc()["skin"];
// Daftar warna skin // Daftar warna skin
$skinList = [ $skinList = [
"cyan" => "#00ffff", "cyan" => "#00ffff",
@ -21,16 +18,13 @@ $skinList = [
"purple" => "#ff55ff", "purple" => "#ff55ff",
"green" => "#33ff55" "green" => "#33ff55"
]; ];
// Warna player yang dipakai // Warna player yang dipakai
$playerColor = $skinList[$skinColor]; $playerColor = $skinList[$skinColor];
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>Hindari Block</title> <title>Hindari Block Multi</title>
<style> <style>
body { body {
font-family: Arial; font-family: Arial;
@ -40,13 +34,11 @@ $playerColor = $skinList[$skinColor];
margin: 0; margin: 0;
display: flex; display: flex;
} }
#gameWrapper { #gameWrapper {
width: 75%; width: 75%;
padding: 20px; padding: 20px;
text-align: center; text-align: center;
} }
#gameArea { #gameArea {
width: 400px; width: 400px;
height: 500px; height: 500px;
@ -57,28 +49,22 @@ $playerColor = $skinList[$skinColor];
border-radius: 10px; border-radius: 10px;
box-shadow: 0 0 10px #000; box-shadow: 0 0 10px #000;
} }
#player { #player {
width: 40px; width: 40px;
height: 40px; height: 40px;
background: <?= $playerColor ?>; background: <?= $playerColor ?>;
position: absolute; position: absolute;
bottom: 10px; bottom: 10px;
left: 180px; left: 180px;
border-radius: 8px; border-radius: 8px;
} }
.block {
#block {
width: 40px; width: 40px;
height: 40px; height: 40px;
background: red; background: red;
position: absolute; position: absolute;
top: -40px;
left: 180px;
border-radius: 8px; border-radius: 8px;
} }
#leaderboard { #leaderboard {
width: 25%; width: 25%;
padding: 20px; padding: 20px;
@ -86,17 +72,14 @@ $playerColor = $skinList[$skinColor];
border-left: 2px solid #333; border-left: 2px solid #333;
height: 100vh; height: 100vh;
} }
table { table {
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
} }
th, td { th, td {
padding: 8px; padding: 8px;
border-bottom: 1px solid #333; border-bottom: 1px solid #333;
} }
/* ===== POPUP GAME OVER ===== */ /* ===== POPUP GAME OVER ===== */
#gameOverPopup { #gameOverPopup {
display: none; display: none;
@ -109,7 +92,6 @@ $playerColor = $skinList[$skinColor];
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.popup-box { .popup-box {
background: #222; background: #222;
padding: 25px; padding: 25px;
@ -118,7 +100,6 @@ $playerColor = $skinList[$skinColor];
width: 300px; width: 300px;
box-shadow: 0 0 10px #000; box-shadow: 0 0 10px #000;
} }
.popup-box button { .popup-box button {
margin-top: 15px; margin-top: 15px;
padding: 10px; padding: 10px;
@ -127,32 +108,20 @@ $playerColor = $skinList[$skinColor];
cursor: pointer; cursor: pointer;
font-size: 16px; font-size: 16px;
border-radius: 6px; border-radius: 6px;
}
#btnRestart {
background: #00d37e;
}
#btnLmenu {
background: #00d37e; background: #00d37e;
} }
</style> </style>
</head> </head>
<body> <body>
<div id="gameWrapper"> <div id="gameWrapper">
<h1>Hindari Block</h1> <h1>Hindari Block Multi</h1>
<p>Player: <b><?= $username ?></b></p> <p>Player: <b><?= $username ?></b></p>
<div class="score-box">Score: <span id="score">0</span></div> <div class="score-box">Score: <span id="score">0</span></div>
<div id="gameArea"> <div id="gameArea">
<div id="player"></div> <div id="player"></div>
<div id="block"></div>
</div> </div>
<p>Credits: Haekal Adi Rendra & Gerrad</p> <p>Credits: Haekal Adi Rendra & Gerrad</p>
</div> </div>
<div id="leaderboard"> <div id="leaderboard">
<h2>Leaderboard</h2> <h2>Leaderboard</h2>
<table> <table>
@ -160,7 +129,6 @@ $playerColor = $skinList[$skinColor];
<th>User</th> <th>User</th>
<th>Score</th> <th>Score</th>
</tr> </tr>
<?php <?php
$result = $conn->query("SELECT username, score FROM leaderboard ORDER BY score DESC LIMIT 20"); $result = $conn->query("SELECT username, score FROM leaderboard ORDER BY score DESC LIMIT 20");
while ($row = $result->fetch_assoc()) { while ($row = $result->fetch_assoc()) {
@ -175,121 +143,174 @@ $playerColor = $skinList[$skinColor];
<div class="popup-box"> <div class="popup-box">
<h2>Game Over</h2> <h2>Game Over</h2>
<p>Score Kamu: <span id="finalScore"></span></p> <p>Score Kamu: <span id="finalScore"></span></p>
<button id="btnRestart">New Game</button> <button id="btnRestart">New Game</button>
<button id="btnmenu">Menu</button> <button id="btnmenu">Menu</button>
</div> </div>
</div> </div>
<audio id="soundMove" src="assets/sound/move.wav"></audio> <audio id="soundMove" src="assets/sound/move.wav"></audio>
<audio id="soundScore" src="assets/sound/score.wav"></audio> <audio id="soundScore" src="assets/sound/score.wav"></audio>
<audio id="soundGameOver" src="assets/sound/gameover.wav"></audio> <audio id="soundGameOver" src="assets/sound/gameover.wav"></audio>
<script> <script>
let currentUser = "<?= $username ?>"; let currentUser = "<?= $username ?>";
</script>
<script> // ========= AUDIO =========
// ========= GAME SCRIPT ========== const soundMove = document.getElementById("soundMove");
const soundScore = document.getElementById("soundScore");
const soundGameOver = document.getElementById("soundGameOver");
// ========= GAME VARIABLES =========
const player = document.getElementById("player"); const player = document.getElementById("player");
const block = document.getElementById("block"); const gameArea = document.getElementById("gameArea");
let score = 0; let score = 0;
let gameRunning = true; let gameRunning = true;
let blockSpeed = 2;
const maxBlockSpeed = 14;
let blocks = [];
document.addEventListener("keydown", e => { // ========= CREATE MULTIPLE BLOCKS AT ONCE =========
function spawnBlocks() {
if (!gameRunning) return; if (!gameRunning) return;
let left = parseInt(window.getComputedStyle(player).getPropertyValue("left")); // Tentukan jumlah block yang akan muncul (13)
let blockCount = 1;
if (score >= 300) blockCount = Math.floor(Math.random() * 2) + 2; // 23
else if (score >= 150) blockCount = Math.floor(Math.random() * 2) + 1; // 12
else if (score >= 50) blockCount = Math.random() < 0.3 ? 2 : 1; // 30% chance 2 block
// score < 50 → selalu 1
const usedPositions = []; // agar tidak tumpang tindih
for (let i = 0; i < blockCount; i++) {
let leftPos;
let attempts = 0;
do {
leftPos = Math.floor(Math.random() * 10) * 40; // grid: 0,40,80,...,360
attempts++;
} while (usedPositions.includes(leftPos) && attempts < 20);
if (attempts >= 20) continue; // skip jika terlalu sulit cari posisi
usedPositions.push(leftPos);
let newBlock = document.createElement("div");
newBlock.classList.add("block");
newBlock.style.top = "-60px";
newBlock.style.left = leftPos + "px";
gameArea.appendChild(newBlock);
blocks.push(newBlock);
}
}
// ========= PLAYER MOVEMENT (grid 40px) =========
document.addEventListener("keydown", e => {
if (!gameRunning) return;
let left = parseInt(player.style.left) || 180;
if (e.key === "ArrowLeft" && left > 0) { if (e.key === "ArrowLeft" && left > 0) {
player.style.left = (left - 20) + "px"; player.style.left = (left - 40) + "px";
soundMove.currentTime = 0; soundMove.currentTime = 0;
soundMove.play(); soundMove.play();
} }
if (e.key === "ArrowRight" && left < 360) { if (e.key === "ArrowRight" && left < 360) {
player.style.left = (left + 20) + "px"; player.style.left = (left + 40) + "px";
soundMove.currentTime = 0; soundMove.currentTime = 0;
soundMove.play(); soundMove.play();
} }
}); });
// ========= UPDATE SPEED =========
function updateBlockSpeed() {
blockSpeed = 2 + Math.floor(score / 18);
if (blockSpeed > maxBlockSpeed) blockSpeed = maxBlockSpeed;
}
let blockSpeed = 5; // kecepatan awal block // ========= SPAWN INTERVAL (dinamis) =========
let spawnDelay = 1400;
function startSpawner() {
spawnBlocks(); // spawn pertama
setInterval(() => {
if (gameRunning) {
spawnBlocks();
// Percepat spawn sesuai score
if (score >= 400) spawnDelay = 400;
else if (score >= 300) spawnDelay = 500;
else if (score >= 200) spawnDelay = 600;
else if (score >= 100) spawnDelay = 800;
else if (score >= 50) spawnDelay = 1000;
}
}, spawnDelay);
}
startSpawner();
// Spawn tambahan di awal agar langsung ramai
setTimeout(() => spawnBlocks(), 800);
setTimeout(() => spawnBlocks(), 1600);
// ========= GAME LOOP =========
function fall() { function fall() {
if (!gameRunning) return; if (!gameRunning) return;
let blockTop = parseInt(window.getComputedStyle(block).getPropertyValue("top")); const playerLeft = parseInt(player.style.left) || 180;
let blockLeft = parseInt(window.getComputedStyle(block).getPropertyValue("left"));
let playerLeft = parseInt(window.getComputedStyle(player).getPropertyValue("left"));
// TABRAKAN blocks = blocks.filter(block => {
if (blockTop > 450 && Math.abs(blockLeft - playerLeft) < 40) { let top = parseInt(block.style.top || -60);
gameRunning = false; let left = parseInt(block.style.left);
soundGameOver.play();
saveScore(score);
showGameOver(score);
return;
}
// Jika block sudah jatuh ke bawah top += blockSpeed;
if (blockTop > 500) { block.style.top = top + "px";
block.style.top = "-40px";
block.style.left = Math.floor(Math.random() * 360) + "px";
score++;
document.getElementById("score").innerText = score;
// ======== TINGKATKAN KECEPATAN BLOCK BERDASARKAN SCORE ======== // Collision
if (score === 15) blockSpeed = 7; if (top >= 450 && top <= 490 && Math.abs(left - playerLeft) < 40) {
if (score === 25) blockSpeed = 8; gameRunning = false;
if (score === 35) blockSpeed = 10; soundGameOver.play();
if (score === 45) blockSpeed = 12; saveScore(score);
if (score === 60) blockSpeed = 14; showGameOver(score);
if (score === 80) blockSpeed = 16; return false;
if (score === 100) blockSpeed = 18; }
soundScore.currentTime = 0; // Lolos bawah
soundScore.play(); if (top > 550) {
} else { score += 10;
block.style.top = (blockTop + blockSpeed) + "px"; document.getElementById("score").innerText = score;
} updateBlockSpeed();
soundScore.currentTime = 0;
soundScore.play();
block.remove();
return false;
}
return true;
});
requestAnimationFrame(fall); requestAnimationFrame(fall);
} }
fall(); fall();
// ========= SAVE SCORE =========
// ================== SIMPAN SKOR KE SERVER ==================
function saveScore(finalScore) { function saveScore(finalScore) {
fetch("save_score.php", { fetch("save_score.php", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" }, headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: "username=" + currentUser + "&score=" + finalScore body: "username=" + encodeURIComponent(currentUser) + "&score=" + finalScore
}); });
} }
// ========= GAME OVER POPUP =========
// ================== POPUP GAME OVER ==================
const popup = document.getElementById("gameOverPopup"); const popup = document.getElementById("gameOverPopup");
const finalScoreText = document.getElementById("finalScore"); const finalScoreText = document.getElementById("finalScore");
const btnRestart = document.getElementById("btnRestart");
const btnmenu = document.getElementById("btnmenu"); document.getElementById("btnRestart").onclick = () => location.reload();
document.getElementById("btnmenu").onclick = () => location.href = "menu.php";
function showGameOver(finalScore) { function showGameOver(finalScore) {
finalScoreText.textContent = finalScore; finalScoreText.textContent = finalScore;
popup.style.display = "flex"; popup.style.display = "flex";
} }
btnRestart.onclick = () => {
window.location.reload();
};
btnmenu.onclick = () => {
window.location.href = "menu.php";
};
</script> </script>
</body> </body>
</html> </html>