JavaScript贪吃蛇游戏Shift加速异常求助:长按Shift蛇停止移动
修复长按Shift键导致贪吃蛇暂停的问题
我一眼就看出问题所在啦——当你长按Shift键时,浏览器会重复触发keydown事件,你的代码每次都会清除当前定时器然后重新创建,频繁的重复操作会让定时器逻辑混乱,最后导致蛇停止移动。
下面是具体的修复方案,核心是加一个状态变量跟踪Shift键的按下状态,避免重复执行定时器的清除和重建:
修复步骤
- 添加
isShiftPressed变量,用于标记Shift是否处于按下状态 - 在Shift的
keydown事件中,仅当Shift未被按下时才执行加速操作 - 在Shift的
keyup事件中恢复速度,并重置状态变量 - 游戏结束时也要重置Shift状态,避免后续状态混乱
修改后的完整代码
HTML部分
<!DOCTYPE html> <html> <head> <link rel="stylesheet" href="web_style.css"> <title>Snake Game</title> </head> <body> <h1>Snake</h1> <canvas id="gc" width="400" height="400"></canvas> <script type="text/javascript" src="snake_script.js"></script> </body> </html>
CSS部分(web_style.css)
body { background-color: lightblue; } h1 { color: white; text-align: center; } button { margin-top: 20px; line-height: 60px; font-weight: bold; padding: 0 40px; background: salmon; border: none; } button:hover { background: lightsalmon; } canvas { padding: 0; margin: auto; display: block; width: 400px; height: 400px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; }
JavaScript部分(snake_script.js)
var grid_size = 20; var grid_num = 20; var player_x = Math.floor(Math.random() * grid_num); var player_y = Math.floor(Math.random() * grid_num); var apple_x = Math.floor(Math.random() * grid_num); var apple_y = Math.floor(Math.random() * grid_num); var x_direction = 0; var y_direction = 0; var trail = []; var tail = 5; var normal_speed = 1000 / 10; var speed = 1000 / 10; var game_status = 0; var my_game; var isShiftPressed = false; // 新增状态变量跟踪Shift按键状态 // 创建游戏控制按钮 var button = document.createElement("button"); button.innerHTML = "Start/Resume Game"; var body = document.getElementsByTagName("body")[0]; body.appendChild(button); button.addEventListener("click", function() { clearInterval(my_game); my_game = setInterval(game, speed); }); window.onload = function() { canv = document.getElementById("gc"); context = canv.getContext("2d"); document.addEventListener("keydown", keyPush); document.addEventListener("keyup", keyRelease); } function game() { player_x += x_direction; player_y += y_direction; // 边界循环处理 if (player_x < 0) player_x = grid_num - 1; if (player_x > grid_num - 1) player_x = 0; if (player_y < 0) player_y = grid_num - 1; if (player_y > grid_num - 1) player_y = 0; // 绘制游戏背景 context.fillStyle = "black"; context.fillRect(0, 0, canv.width, canv.height); // 绘制蛇身 context.fillStyle = "lime"; for(var i = 0; i < trail.length; i++) { context.fillRect(trail[i].x * grid_size, trail[i].y * grid_size, grid_size - 2, grid_size - 2); // 游戏开始后才触发碰撞结束逻辑 if(trail[i].x == player_x && trail[i].y == player_y && game_status !== 0) { endGame(); return; } } trail.push({x:player_x, y:player_y}); while(trail.length > tail) trail.shift(); // 吃苹果逻辑 if (apple_x == player_x && apple_y == player_y) { tail++; apple_x = Math.floor(Math.random() * grid_num); apple_y = Math.floor(Math.random() * grid_num); } // 绘制苹果 context.fillStyle = "red"; context.fillRect(apple_x * grid_size, apple_y * grid_size, grid_size - 2, grid_size - 2); } function keyPush(keyEvent) { switch(keyEvent.keyCode) { // 左方向键/A键控制 case 37: case 65: if (x_direction == 1) break; game_status++; x_direction = -1; y_direction = 0; break; // 上方向键/W键控制 case 38: case 87: if (y_direction == 1) break; game_status++; x_direction = 0; y_direction = -1; break; // 右方向键/D键控制 case 39: case 68: if (x_direction == -1) break; game_status++; x_direction = 1; y_direction = 0; break; // 下方向键/S键控制 case 40: case 83: if (y_direction == -1) break; game_status++; x_direction = 0; y_direction = 1; break; // Shift键加速:仅当未按下时执行一次 case 16: if (!isShiftPressed) { clearInterval(my_game); speed = normal_speed * 0.5; my_game = setInterval(game, speed); isShiftPressed = true; } break; } } function keyRelease(keyEvent) { switch(keyEvent.keyCode) { case 16: isShiftPressed = false; clearInterval(my_game); speed = normal_speed; my_game = setInterval(game, speed); break; } } function endGame() { clearInterval(my_game); context.fillStyle = "yellow"; context.font="20px Georgia"; context.fillText("Game Over!", 10, 50); // 重置所有游戏状态(包括Shift按键状态) x_direction = 0; y_direction = 0; trail = []; tail = 5; normal_speed = 1000 / 10; speed = 1000 / 10; game_status = 0; isShiftPressed = false; }
另外我还顺手优化了几个小细节:
- 合并了方向键和WASD的重复代码,让逻辑更简洁
- 调整了按钮文字为更清晰的"Start/Resume Game"
- 优化了边界判断的写法,去掉冗余的大括号
- 明确了游戏开始状态(
game_status !==0)才触发碰撞结束,避免初始状态误判
这样修改后,长按Shift键就只会触发一次加速操作,松开时恢复正常速度,再也不会出现游戏暂停的问题啦!
内容的提问来源于stack exchange,提问作者SOS
相关产品推荐
相关产品推荐

