本文详解如何构建一个符合逻辑的 html 赛车游戏,重点解决速度递增(每5秒+1,起始为5)和精准计分(仅当玩家车尾完全越过敌车尾时+10分)两大核心需求,并修复常见重启异常、误计分与速度失控问题。
在原始代码中,player.sco
re++ 被错误地置于 runGame() 的每一帧循环内,导致分数随帧率狂涨(如60fps下每秒+60),完全违背“仅过车时计分”的设计要求;同时,速度未做时间基准控制,player.speed++ 缺乏定时器封装,造成重启后累积加速、多次重启后指数级失控。此外,“车尾对齐”判定缺失,当前碰撞检测 isCollide() 仅用于防撞,无法支撑过车逻辑。
使用 performance.now() 记录上一次加速时间,确保严格每5000ms增加1点速度,且每次游戏初始化重置计时器:
let lastSpeedIncreaseTime = 0;
function updateSpeed(timestamp) {
if (timestamp - lastSpeedIncreaseTime >= 5000) {
player.speed++;
lastSpeedIncreaseTime = timestamp;
}
}⚠️ 注意:必须在 runGame() 的动画帧回调中传入 timestamp(requestAnimationFrame(runGame) 自动提供),不可用 setInterval——后者与渲染帧不同步,易导致卡顿或跳帧。
根据题设:“黄车(玩家)尾部 > 绿车(敌人)尾部”才计分。需获取两车 getBoundingClientRect() 的 bottom 值(即元素最下方Y坐标),并确保:
为此,为每个敌车元素添加自定义属性标记状态:
立即学习“前端免费学习笔记(深入)”;
// 初始化敌车时添加标记
enemyCar.dataset.passed = 'false';
// 在 moveEnemy() 中检查过车
function checkPassing(myCar, enemyCar) {
const myRect = myCar.getBoundingClientRect();
const enemyRect = enemyCar.getBoundingClientRect();
// 黄车尾部(bottom) > 绿车尾部(bottom) → 已完成超越
if (myRect.bottom > enemyRect.bottom && enemyCar.dataset.passed === 'false') {
player.score += 10;
enemyCar.dataset.passed = 'true'; // 标记已计分,防止重复
}
}调用位置:在 moveEnemy() 循环内、更新 enemyCar.y 之后立即执行 checkPassing(car, enemyCar)。
initializeGame() 必须完全重置所有状态变量:
function initializeGame() {
startScreen.classList.add('hide');
gameArea.innerHTML = "";
// 关键:重置全部状态
player = { speed: 5, score: 0, start: true, x: 0, y: 0 };
lastSpeedIncreaseTime = performance.now(); // 重置计时起点
keys = { ArrowUp: false, ArrowDown: false, ArrowLeft: false, ArrowRight: false };
// ... 后续创建元素逻辑(保持不变)
}? 为什么原代码重启后速度异常?因 player 对象未被重建,speed 继承上次结束值;而 lastSpeedIncreaseTime 未重置,导致差值极小,瞬间触发加速。
function runGame(timestamp) {
if (!player.start) return;
// 1. 更新速度(基于时间戳)
updateSpeed(timestamp);
// 2. 移动道路线
moveLines();
// 3. 获取玩家车元素并移动
const car = document.querySelector('.myCar');
const road = gameArea.getBoundingClientRect();
if (keys.ArrowUp && player.y > (road.top + 150)) player.y -= player.speed;
if (keys.ArrowDown && player.y < (road.bottom - 85)) player.y += player.speed;
if (keys.ArrowLeft && player.x > 0) player.x -= player.speed;
if (keys.ArrowRight && player.x < (road.width - 50)) player.x += player.speed;
car.style.top = player.y + "px";
car.style.left = player.x + "px";
// 4. 移动并检测敌车(含过车判定)
moveEnemy(car);
// 5. 更新UI
score.innerText = `Score: ${player.score}\nSpeed: ${player.speed}`;
// 6. 持续动画
window.requestAnimationFrame(runGame);
}通过以上改造,游戏将严格遵循:
✅ 起始速度恒为 5
✅ 每整 5 秒精确 +1 速度(不受重启影响)
✅ 仅当黄车尾部越过绿车尾部时 +10 分(无漏计、无重计、无误计)
✅ 多次重启后状态完全隔离,运行稳定
现在,你已掌握构建可扩展、可维护的 HTML 游戏核心状态管理范式。