Brick Shot游戏无法存储用户分数至数据库,代码问题排查求助
Fixing Your Brick Shot Game's User Authentication & Score Saving Issues
Let's walk through the problems in your code and fix them to get your game working properly, with username input and score saving functionality.
Key Issues Identified
- Server-Client Timing Mismatch: PHP runs on the server before the page reaches the user's browser. The PHP code embedded inside your JavaScript (like the score inserts on game win/loss) will execute immediately when the page loads, not when the game actually ends.
- Broken Form Logic: You're using a JavaScript
promptto get the username but trying to pass it via a form POST, which doesn't sync up. The initial PHP insert forUsernameruns before the user even enters their name, leading to empty database entries. - Incorrect Database Insert: You're trying to insert
UsernameandScoreas separate records instead of a single row that links a user to their score. - Syntax Error: Your first PHP database block is missing a closing
}, which breaks the HTML structure and causes the page to fail loading.
Step-by-Step Fixes
1. Separate Frontend and Backend Logic
We'll split the score-saving functionality into a dedicated PHP script (save-score.php) that your game will call via AJAX when the game ends.
2. Proper Username Input Form
Replace the prompt with a visible form so users can enter their username before starting the game. Only load the game once the form is submitted.
3. AJAX for Score Submission
Use jQuery (which you already have included) to send the username and score to the backend script when the game ends, without reloading the page immediately.
Corrected Code
Game.php
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Gamedev Canvas Workshop</title> <style> * { padding: 0; margin: 0; } canvas { background: #eee; display: block; margin: 0 auto; display: none; } .username-form { text-align: center; margin: 20px 0; } </style> <script src="randomColor.js"></script> <script src="jquery-3.2.1.min.js"></script> <link href="css/bootstrap.min.css" rel="stylesheet" type="text/css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" type="text/css"> </head> <body> <!-- Username Input Form --> <div class="username-form"> <form id="usernameForm"> <label for="Username">Enter your username:</label> <input type="text" id="Username" name="Username" required> <button type="submit">Start Game</button> </form> </div> <canvas id="myCanvas" width="480" height="320"></canvas> <!-- Hidden inputs to store username and score --> <input type="hidden" id="hiddenUsername" name="hiddenUsername"> <input type="hidden" id="hiddenScore" name="hiddenScore"> <script> let username; let canvas = document.getElementById("myCanvas"); let ctx = canvas.getContext("2d"); let ballRadius = 10; let x = canvas.width/2; let y = canvas.height-30; let dx = 2; let dy = -2; let paddleHeight = 10; let paddleWidth = 75; let paddleX = (canvas.width-paddleWidth)/2; let rightPressed = false; let leftPressed = false; let brickRowCount = 5; let brickColumnCount = 3; let brickWidth = 75; let brickHeight = 20; let brickPadding = 10; let brickOffsetTop = 30; let brickOffsetLeft = 30; let score = 0; let lives = 3; let color = "#0095DD"; let bricks = []; // Initialize bricks for(c=0; c<brickColumnCount; c++) { bricks[c] = []; for(r=0; r<brickRowCount; r++) { bricks[c][r] = { x: 0, y: 0, status: 1 }; } } // Username form submission handler $("#usernameForm").submit(function(e) { e.preventDefault(); username = $("#Username").val(); $("#hiddenUsername").val(username); // Show canvas and start game $(".username-form").hide(); canvas.style.display = "block"; draw(); }); // Key handlers document.addEventListener("keydown", keyDownHandler, false); document.addEventListener("keyup", keyUpHandler, false); function random_color() { color = randomColor(); } function keyDownHandler(e) { if(e.keyCode == 39) { rightPressed = true; } else if(e.keyCode == 37) { leftPressed = true; } } function keyUpHandler(e) { if(e.keyCode == 39) { rightPressed = false; } else if(e.keyCode == 37) { leftPressed = false; } } function collisionDetection() { for(c=0; c<brickColumnCount; c++) { for(r=0; r<brickRowCount; r++) { let b = bricks[c][r]; if(b.status == 1) { if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) { dy = -dy; b.status = 0; random_color(); score++; $("#hiddenScore").val(score); if(score == brickRowCount*brickColumnCount) { alert("恭喜你获胜!"); saveScore(); setTimeout(() => document.location.reload(), 1000); } } } } } } // Save score via AJAX function saveScore() { $.ajax({ url: "save-score.php", type: "POST", data: { Username: $("#hiddenUsername").val(), Score: $("#hiddenScore").val() }, success: function(response) { console.log("Score saved successfully: " + response); }, error: function(xhr, status, error) { console.error("Error saving score: " + error); } }); } function drawBall() { ctx.beginPath(); ctx.arc(x, y, ballRadius, 0, Math.PI*2); ctx.fillStyle = color; ctx.fill(); ctx.closePath(); } function drawPaddle() { ctx.beginPath(); ctx.rect(paddleX, canvas.height-paddleHeight, paddleWidth, paddleHeight); ctx.fillStyle = "#0095DD"; ctx.fill(); ctx.closePath(); } function drawBricks() { for(c=0; c<brickColumnCount; c++) { for(r=0; r<brickRowCount; r++) { if(bricks[c][r].status == 1) { let brickX = (r*(brickWidth+brickPadding))+brickOffsetLeft; let brickY = (c*(brickHeight+brickPadding))+brickOffsetTop; bricks[c][r].x = brickX; bricks[c][r].y = brickY; ctx.beginPath(); ctx.rect(brickX, brickY, brickWidth, brickHeight); ctx.fillStyle = "#0095DD"; ctx.fill(); ctx.closePath(); } } } } function drawLives() { ctx.font = "16px Arial"; ctx.fillStyle = "#0095DD"; ctx.fillText("剩余生命: "+lives, canvas.width-65, 20); } function drawScore() { ctx.font = "16px Arial"; ctx.fillStyle = "#0095DD"; ctx.fillText("分数: "+score, 8, 20); } function draw() { ctx.clearRect(0, 0, canvas.width, canvas.height); drawBricks(); drawBall(); drawPaddle(); drawScore(); drawLives(); collisionDetection(); if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) { dx = -dx; } if(y + dy < ballRadius) { dy = -dy; } else if(y + dy > canvas.height-ballRadius) { if(x > paddleX && x < paddleX + paddleWidth) { dy = -dy; } else { lives--; if(!lives) { alert("游戏结束"); saveScore(); setTimeout(() => document.location.reload(), 1000); } else { x = canvas.width/2; y = canvas.height-30; dx = 2; dy = -2; paddleX = (canvas.width-paddleWidth)/2; } } } if(rightPressed && paddleX < canvas.width-paddleWidth) { paddleX += 7; } else if(leftPressed && paddleX > 0) { paddleX -= 7; } x += dx; y += dy; requestAnimationFrame(draw); } </script> </body> </html>
save-score.php
<?php require("Database.php"); if ($_SERVER['REQUEST_METHOD']=="POST"){ $username = mysqli_real_escape_string($conn, $_POST["Username"]); $score = mysqli_real_escape_string($conn, $_POST["Score"]); // Insert both username and score in one query $sql = "INSERT INTO `scoreboard` (`Username`, `Score`) VALUES ('$username', '$score')"; if (mysqli_query($conn, $sql)) { echo "Score saved successfully"; } else { echo "Error: " . mysqli_error($conn); } mysqli_close($conn); } ?>
Database.php (Keep as is)
<?php $servername = "localhost"; $username = "root"; $password = ""; $database = "game"; // 创建连接 $conn = mysqli_connect($servername, $username, $password, $database); // 检查连接 if (!$conn) { die("连接失败: " . mysqli_connect_error()); } //echo "连接成功"; ?>
Additional Notes
- SQL Injection Protection: We added
mysqli_real_escape_string()to sanitize user input and prevent SQL injection attacks. For better security, consider using prepared statements instead. - Game Flow: The game now only loads after the user submits their username, which aligns with your requirement.
- AJAX Submission: Score saving happens in the background when the game ends, so users get feedback before the page reloads.
内容的提问来源于stack exchange,提问作者Cenk Camkıran
相关产品推荐
相关产品推荐

