189 lines
4.8 KiB
JavaScript
189 lines
4.8 KiB
JavaScript
const canvas = document.getElementById('gameCanvas');
|
|
const ctx = canvas.getContext('2d');
|
|
const uiLayer = document.getElementById('ui-layer');
|
|
const finalScoreSpan = document.getElementById('final-score');
|
|
const inGameScore = document.getElementById('ingame-score');
|
|
const highScoreDisplay = document.getElementById('high-score-display');
|
|
|
|
// Setup UI Flexbox
|
|
uiLayer.style.display = 'none';
|
|
|
|
let score = 0;
|
|
let gameRunning = true;
|
|
let speed = 2;
|
|
let blockHeight = 35;
|
|
let initialWidth = 200;
|
|
let blocks = [];
|
|
let currentBlock = {};
|
|
let direction = 1;
|
|
let hue = 0;
|
|
|
|
function initGame() {
|
|
score = 0;
|
|
blocks = [];
|
|
speed = 3;
|
|
hue = Math.random() * 360;
|
|
|
|
inGameScore.innerText = score;
|
|
|
|
// Base block
|
|
blocks.push({
|
|
x: (canvas.width - initialWidth) / 2,
|
|
y: canvas.height - 100,
|
|
width: initialWidth,
|
|
color: `hsl(${hue}, 100%, 50%)`
|
|
});
|
|
|
|
spawnBlock();
|
|
|
|
// Perubahan: Jangan panggil draw() di sini jika ini reset,
|
|
// biarkan resetGame yang mengontrol loop
|
|
if(gameRunning) draw();
|
|
}
|
|
|
|
function spawnBlock() {
|
|
const prevBlock = blocks[blocks.length - 1];
|
|
hue += 10;
|
|
|
|
currentBlock = {
|
|
x: 0,
|
|
y: prevBlock.y - blockHeight,
|
|
width: prevBlock.width,
|
|
color: `hsl(${hue}, 100%, 50%)`
|
|
};
|
|
|
|
if (currentBlock.y < 150) {
|
|
blocks.forEach(b => b.y += blockHeight);
|
|
currentBlock.y += blockHeight;
|
|
}
|
|
}
|
|
|
|
function drawBackground() {
|
|
ctx.strokeStyle = 'rgba(255, 255, 255, 0.05)';
|
|
ctx.lineWidth = 1;
|
|
for (let i = 0; i < canvas.width; i += 40) {
|
|
ctx.beginPath(); ctx.moveTo(i, 0); ctx.lineTo(i, canvas.height); ctx.stroke();
|
|
}
|
|
for (let i = 0; i < canvas.height; i += 40) {
|
|
ctx.beginPath(); ctx.moveTo(0, i); ctx.lineTo(canvas.width, i); ctx.stroke();
|
|
}
|
|
}
|
|
|
|
function draw() {
|
|
if (!gameRunning) return;
|
|
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
drawBackground();
|
|
|
|
currentBlock.x += speed * direction;
|
|
if (currentBlock.x + currentBlock.width > canvas.width || currentBlock.x < 0) {
|
|
direction *= -1;
|
|
}
|
|
|
|
ctx.shadowBlur = 20;
|
|
blocks.forEach(b => {
|
|
ctx.fillStyle = b.color;
|
|
ctx.shadowColor = b.color;
|
|
ctx.fillRect(b.x, b.y, b.width, blockHeight);
|
|
ctx.fillStyle = 'rgba(255,255,255,0.2)';
|
|
ctx.fillRect(b.x, b.y, b.width, 5);
|
|
});
|
|
|
|
ctx.fillStyle = currentBlock.color;
|
|
ctx.shadowColor = currentBlock.color;
|
|
ctx.fillRect(currentBlock.x, currentBlock.y, currentBlock.width, blockHeight);
|
|
ctx.fillStyle = 'rgba(255,255,255,0.4)';
|
|
ctx.fillRect(currentBlock.x, currentBlock.y, currentBlock.width, 5);
|
|
ctx.shadowBlur = 0;
|
|
|
|
requestAnimationFrame(draw);
|
|
}
|
|
|
|
function placeBlock() {
|
|
if (!gameRunning) return;
|
|
|
|
const prevBlock = blocks[blocks.length - 1];
|
|
let overlap = currentBlock.width - Math.abs(currentBlock.x - prevBlock.x);
|
|
|
|
if (overlap <= 0) {
|
|
gameOver();
|
|
return;
|
|
}
|
|
|
|
if (currentBlock.x < prevBlock.x) {
|
|
currentBlock.width = overlap;
|
|
currentBlock.x = prevBlock.x;
|
|
} else {
|
|
currentBlock.width = overlap;
|
|
}
|
|
|
|
blocks.push(currentBlock);
|
|
score++;
|
|
inGameScore.innerText = score;
|
|
speed += 0.15;
|
|
spawnBlock();
|
|
}
|
|
|
|
function gameOver() {
|
|
gameRunning = false;
|
|
uiLayer.style.display = 'flex';
|
|
finalScoreSpan.innerText = score;
|
|
saveScore(score);
|
|
}
|
|
|
|
// --- PERBAIKAN UTAMA ADA DI SINI ---
|
|
function resetGame() {
|
|
uiLayer.style.display = 'none';
|
|
|
|
// Matikan gameRunning sementara agar klik tombol tidak terbaca sebagai 'placeBlock'
|
|
gameRunning = false;
|
|
|
|
initGame();
|
|
|
|
// Beri jeda 300ms. Setelah tombol dilepas, baru game aktif.
|
|
setTimeout(() => {
|
|
gameRunning = true;
|
|
draw(); // Mulai loop animasi
|
|
}, 300);
|
|
}
|
|
|
|
// Input Handler yang lebih aman
|
|
document.body.onkeydown = (e) => {
|
|
if (e.code === 'Space') {
|
|
if (gameRunning) {
|
|
placeBlock();
|
|
} else if (uiLayer.style.display === 'flex') {
|
|
// Cegah spasi merestart terlalu cepat
|
|
resetGame();
|
|
}
|
|
}
|
|
};
|
|
|
|
document.body.onclick = (e) => {
|
|
// PENTING: Jika yang diklik adalah tombol atau bagian dari UI Layer, JANGAN jalankan game
|
|
if (e.target.closest('#ui-layer') || e.target.closest('.btn')) return;
|
|
|
|
if (gameRunning) placeBlock();
|
|
};
|
|
|
|
function saveScore(newScore) {
|
|
const formData = new FormData();
|
|
formData.append('score', newScore);
|
|
fetch('save_score.php', { method: 'POST', body: formData })
|
|
.then(response => response.json())
|
|
.then(data => fetchHighScore());
|
|
}
|
|
|
|
function fetchHighScore() {
|
|
fetch('save_score.php?action=get')
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
highScoreDisplay.innerText = data.high_score || "0";
|
|
});
|
|
}
|
|
|
|
// Start pertama kali
|
|
initGame();
|
|
// Paksa draw pertama kali
|
|
gameRunning = true;
|
|
draw(); |