Upload files to "/"
This commit is contained in:
parent
ec3ec011fc
commit
b0a527843b
30
index.php
Normal file
30
index.php
Normal file
@ -0,0 +1,30 @@
|
||||
<!---------------------------------- index.php ---------------------------------->
|
||||
<?php
|
||||
session_start();
|
||||
$conn = new mysqli("localhost","root","","breakout_db");
|
||||
if($conn->connect_error){ die("DB Error"); }
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Breakout Game</h1>
|
||||
<div class="menu">
|
||||
<a href="login.php">Login / Register</a>
|
||||
<a href="leaderboard.php">Leaderboard</a>
|
||||
</div>
|
||||
<canvas id="game" width="480" height="320"></canvas>
|
||||
<p>Score: <span id="score">0</span></p>
|
||||
<p>
|
||||
<select id="diff">
|
||||
<option value="easy">Easy</option>
|
||||
<option value="medium">Medium</option>
|
||||
<option value="hard">Hard</option>
|
||||
</select>
|
||||
<button onclick="startGame()">Start</button>
|
||||
</p>
|
||||
<script src="game.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
19
leaderboard.php
Normal file
19
leaderboard.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
session_start();
|
||||
$conn = new mysqli("localhost","root","","breakout_db");
|
||||
$lb = $conn->query("SELECT username, highscore FROM users ORDER BY highscore DESC LIMIT 10");
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<h2>Leaderboard</h2>
|
||||
<table>
|
||||
<?php while($r = $lb->fetch_assoc()){ ?>
|
||||
<tr><td><?= $r['username'] ?></td><td><?= $r['highscore'] ?></td></tr>
|
||||
<?php } ?>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
49
login.php
Normal file
49
login.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
session_start();
|
||||
$conn = new mysqli("localhost","root","","breakout_db");
|
||||
if($conn->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;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="login-box">
|
||||
<h2>Login</h2>
|
||||
<form method="POST">
|
||||
<input name="user" placeholder="Username" required>
|
||||
<input name="pass" type="password" placeholder="Password" required>
|
||||
<button name="login">Login</button>
|
||||
</form>
|
||||
|
||||
<h2>Register</h2>
|
||||
<form method="POST">
|
||||
<input name="user" placeholder="Username" required>
|
||||
<input name="pass" type="password" placeholder="Password" required>
|
||||
<button name="register">Register</button>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
7
save.php
Normal file
7
save.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
session_start();
|
||||
$conn = new mysqli("localhost","root","","breakout_db");
|
||||
$u = $_SESSION['user'];
|
||||
$s = intval($_GET['score']);
|
||||
$conn->query("UPDATE users SET highscore = GREATEST(highscore, $s) WHERE username='$u'");
|
||||
?>
|
||||
273
script.js
273
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();
|
||||
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<rows;r++){
|
||||
for(let c=0;c<cols;c++){
|
||||
bricks.push({ x: c*50+30, y: r*20+30, w:40, h:15, hit:false });
|
||||
}
|
||||
}
|
||||
requestAnimationFrame(loop);
|
||||
}
|
||||
|
||||
function loop(){
|
||||
if(!running) return;
|
||||
ctx.clearRect(0,0,480,320);
|
||||
|
||||
ctx.fillStyle = "white";
|
||||
ctx.fillRect(paddle.x, 300, paddle.w, paddle.h);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(ball.x, ball.y, ball.r, 0, Math.PI*2);
|
||||
ctx.fill();
|
||||
|
||||
ball.x += ball.dx;
|
||||
ball.y += ball.dy;
|
||||
|
||||
if(ball.x < ball.r || ball.x > 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);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user