Update script.js

This commit is contained in:
5803025031 2025-11-30 22:01:30 -05:00
parent 4c353781b1
commit aa2166af12

225
script.js
View File

@ -1,72 +1,189 @@
const game = document.getElementById("game"); const canvas = document.getElementById('gameCanvas');
const movesText = document.getElementById("moves"); const ctx = canvas.getContext('2d');
const scoreText = document.getElementById("score"); 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 moves = 0;
let score = 0; let score = 0;
let firstCard = null; let gameRunning = true;
let lock = false; let speed = 2;
let blockHeight = 35;
let initialWidth = 200;
let blocks = [];
let currentBlock = {};
let direction = 1;
let hue = 0;
let icons = ["🍎", "🍌", "🍇", "🍓", "🍒", "🍑", "🍍", "🥝"]; // 8 pairs function initGame() {
let cards = [...icons, ...icons]; score = 0;
cards.sort(() => Math.random() - 0.5); blocks = [];
speed = 3;
hue = Math.random() * 360;
cards.forEach(icon => { inGameScore.innerText = score;
const div = document.createElement("div");
div.className = "card"; // Base block
div.dataset.icon = icon; blocks.push({
div.textContent = "?"; x: (canvas.width - initialWidth) / 2,
game.appendChild(div); y: canvas.height - 100,
width: initialWidth,
color: `hsl(${hue}, 100%, 50%)`
}); });
game.querySelectorAll(".card").forEach(card => { spawnBlock();
card.addEventListener("click", () => {
if(lock || card.classList.contains("open") || card.classList.contains("matched")) return;
card.classList.add("open"); // Perubahan: Jangan panggil draw() di sini jika ini reset,
card.textContent = card.dataset.icon; // biarkan resetGame yang mengontrol loop
if(gameRunning) draw();
}
if(!firstCard){ function spawnBlock() {
firstCard = card; 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; return;
} }
moves++; if (currentBlock.x < prevBlock.x) {
movesText.textContent = moves; currentBlock.width = overlap;
lock = true; currentBlock.x = prevBlock.x;
if(firstCard.dataset.icon === card.dataset.icon){
score += 100;
scoreText.textContent = score;
firstCard.classList.add("matched");
card.classList.add("matched");
firstCard = null;
lock = false;
saveScore(score);
} else { } else {
score -= 20; currentBlock.width = overlap;
scoreText.textContent = score; }
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(() => { setTimeout(() => {
firstCard.classList.remove("open"); gameRunning = true;
firstCard.textContent = "?"; draw(); // Mulai loop animasi
card.classList.remove("open"); }, 300);
card.textContent = "?";
firstCard = null;
lock = false;
}, 700);
} }
});
});
function saveScore(score){ // Input Handler yang lebih aman
fetch("save_score.php", { document.body.onkeydown = (e) => {
method: "POST", if (e.code === 'Space') {
headers: { "Content-Type": "application/x-www-form-urlencoded" }, if (gameRunning) {
body: "score=" + score 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();