diff --git a/index.php b/index.php
new file mode 100644
index 0000000..071d93f
--- /dev/null
+++ b/index.php
@@ -0,0 +1,30 @@
+
+connect_error){ die("DB Error"); }
+?>
+
+
+
+
+
+
+Breakout Game
+
+
+Score: 0
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/leaderboard.php b/leaderboard.php
new file mode 100644
index 0000000..8726d99
--- /dev/null
+++ b/leaderboard.php
@@ -0,0 +1,19 @@
+query("SELECT username, highscore FROM users ORDER BY highscore DESC LIMIT 10");
+?>
+
+
+
+
+
+
+Leaderboard
+
+fetch_assoc()){ ?>
+| = $r['username'] ?> | = $r['highscore'] ?> |
+
+
+
+
\ No newline at end of file
diff --git a/login.php b/login.php
new file mode 100644
index 0000000..f01c226
--- /dev/null
+++ b/login.php
@@ -0,0 +1,49 @@
+connect_error){ die("DB Error"); }
+
+// Register
+if(isset($_POST['register'])){
+ $u = $_POST['user'];
+ $p = password_hash($_POST['pass'], PASSWORD_DEFAULT);
+ $conn->query("INSERT INTO users(username,password,highscore) VALUES('$u','$p',0)");
+}
+
+// Login
+if(isset($_POST['login'])){
+ $u = $_POST['user'];
+ $p = $_POST['pass'];
+ $res = $conn->query("SELECT * FROM users WHERE username='$u'");
+ if($row = $res->fetch_assoc()){
+ if(password_verify($p, $row['password'])){
+ $_SESSION['user'] = $u;
+ header("Location: index.php");
+ exit;
+ }
+ }
+}
+?>
+
+
+
+
+
+
+
+
Login
+
+
+Register
+
+
+
+
\ No newline at end of file
diff --git a/save.php b/save.php
new file mode 100644
index 0000000..859492d
--- /dev/null
+++ b/save.php
@@ -0,0 +1,7 @@
+query("UPDATE users SET highscore = GREATEST(highscore, $s) WHERE username='$u'");
+?>
\ No newline at end of file
diff --git a/script.js b/script.js
index f8a7d56..510ad6a 100644
--- a/script.js
+++ b/script.js
@@ -1,189 +1,84 @@
-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();
\ No newline at end of file
+let canvas = document.getElementById("game");
+let ctx = canvas.getContext("2d");
+let score = 0;
+let running = false;
+let ball, paddle, bricks, rows, cols, speed;
+let hitSound = new Audio("hit.wav");
+let loseSound = new Audio("lose.wav");
+
+function startGame(){
+ score = 0;
+ document.getElementById("score").textContent = score;
+ running = true;
+
+ let diff = document.getElementById("diff").value;
+ if(diff === "easy"){ rows = 3; cols = 5; speed = 3; }
+ if(diff === "medium"){ rows = 4; cols = 7; speed = 4; }
+ if(diff === "hard"){ rows = 6; cols = 9; speed = 5; }
+
+ paddle = { x:200, w:80, h:10 };
+ ball = { x:240, y:200, dx:speed, dy:-speed, r:6 };
+ bricks = [];
+
+ for(let r=0;r 480-ball.r) ball.dx *= -1;
+ if(ball.y < ball.r) ball.dy *= -1;
+
+ if(ball.y > 294 && ball.x > paddle.x && ball.x < paddle.x+paddle.w){
+ ball.dy *= -1;
+ hitSound.play();
+ }
+
+ bricks.forEach(b =>{
+ if(!b.hit && ball.x > b.x && ball.x < b.x+b.w && ball.y > b.y && ball.y < b.y+b.h){
+ b.hit = true;
+ ball.dy *= -1;
+ score += 10;
+ document.getElementById("score").textContent = score;
+ hitSound.play();
+ }
+ });
+
+ bricks.forEach(b =>{
+ if(!b.hit){ ctx.fillRect(b.x,b.y,b.w,b.h); }
+ });
+
+ if(ball.y > 330){
+ loseSound.play();
+ running = false;
+ saveScore();
+ alert("Game Over");
+ return;
+ }
+
+ requestAnimationFrame(loop);
+}
+
+window.addEventListener("mousemove", e =>{
+ paddle.x = e.clientX - canvas.offsetLeft - paddle.w/2;
+});
+
+function saveScore(){
+ fetch("save.php?score="+score);
+}
\ No newline at end of file