自制HTML跳跃游戏频繁冻结问题排查求助
问题:HTML跳跃小游戏频繁冻结排查
我正在开发一款用于编程练习的HTML跳跃小游戏,目前游戏虽基础但进度稳定,近期出现频繁冻结的问题。多次排查代码后仍未找到问题根源,确定问题出在移动相关函数中,但无法定位具体模块。
我已尝试以下调试操作:
- 注释
checkCollision()函数,游戏在玩家与敌人接近时仍会冻结; - 注释
moveEnemy()函数后游戏恢复正常,但敌人失去移动功能; - 分段注释代码调试,问题依旧存在。
以下是游戏代码:
<!DOCTYPE html> <html> <head> <title>Jump Test</title> <style> #player { position: absolute; left: 0px; top: 0px; width: 50px; height: 50px; background-color: rgb(153, 0, 255); box-shadow: 0 0 5px rgb(23, 6, 255); } #ground { position: absolute; bottom: 0; left: 0; width: 100%; height: 50px; background-color: black; } #scoreboard { position: absolute; top: 10px; right: 10px; font-size: 24px; color: white; font-family: Arial, sans-serif; background-color: black; padding: 10px; border-radius: 10px; } #distance-scoreboard { position: absolute; top: 60px; right: 10px; font-size: 24px; color: white; font-family: Arial, sans-serif; background-color: black; padding: 10px; border-radius: 10px; } #enemy { position: absolute; left: 0px; top: 850px; width: 40px; height: 40px; background-color: rgb(255, 0, 0); box-shadow: 0 0 5px rgb(255, 0, 0); } </style> </head> <body> <div id="player"></div> <div id="ground"></div> <div id="enemy"></div> <div id="scoreboard">Jumps: 0</div> <div id="distance-scoreboard">Distance Traveled: 0 cm</div> <script> // Define variables // Get the elements from the HTML DOM and assign them to variables let player = document.querySelector('#player'); let ground = document.querySelector('#ground'); let enemy = document.querySelector("#enemy"); let scoreboard = document.querySelector('#scoreboard'); let distanceScoreboard = document.querySelector('#distance-scoreboard'); // Declare and initialize game variables let jumpsCount = 0; let velocity = 0; let gravity = 0.2; let movingLeft = false; let movingRight = false; let jumpKeyDown = false; let Jumps = 0; let distanceTraveled = 0; let horizontalDistance = 0; let verticalDistance = 0; let enemyPosition = 1500; let enemyVelocity = 0; let enemySpeed = 7; // Define functions // Function to make the player jump function jump() { // If the player hasn't jumped yet and is on the ground, set their velocity to a negative value to make them jump if (jumpsCount < 1 && player.offsetTop + player.offsetHeight >= ground.offsetTop) { velocity = -8; jumpsCount++; Jumps++; // Update the scoreboard to display the number of jumps scoreboard.textContent = 'Jumps: ' + Jumps; } } // Function to make the enemy jump if the player is above it function enemyJump() { if (player.offsetTop + player.offsetHeight < enemy.offsetTop && enemyVelocity === 0) { enemyVelocity = -7; } } // Function to check if the player is within range of the enemy and if so, make the enemy jump function checkPlayerInRange(player) { const playerBox = player.getBoundingClientRect(); const enemyBox = enemy.getBoundingClientRect(); if (playerBox.bottom >= enemyBox.top && playerBox.top <= enemyBox.bottom && playerBox.right >= enemyBox.left && playerBox.left <= enemyBox.right && enemyVelocity >= 0) { enemyVelocity = -7; } } // Function to calculate the distance traveled by the player function calculateDistanceTraveled() { let currentHorizontalDistance = player.offsetLeft; let currentVerticalDistance = player.offsetTop; let currentDistanceInCm = Math.sqrt(Math.pow(currentHorizontalDistance - horizontalDistance, 2) + Math.pow(currentVerticalDistance - verticalDistance, 2)) / 10; // divide by 10 to convert to cm // If the current distance is 0, exit the function if (currentDistanceInCm === 0) { return; } // Add the current distance traveled to the total distance traveled distanceTraveled += currentDistanceInCm; // Update the distance scoreboard with the current distance traveled if (distanceTraveled >= 100000) { let distanceInKilometers = distanceTraveled / 100000; distanceScoreboard.textContent = "Distance Traveled: " + distanceInKilometers.toFixed(2) + " km"; } else if (distanceTraveled >= 100) { let distanceInMeters = distanceTraveled / 100; distanceScoreboard.textContent = "Distance Traveled: " + distanceInMeters.toFixed(2) + " m"; } else { distanceScoreboard.textContent = "Distance Traveled: " + distanceTraveled.toFixed(2) + " cm"; } // Update the horizontal and vertical distances for the next calculation horizontalDistance = currentHorizontalDistance; verticalDistance = currentVerticalDistance; } // This function is responsible for animating the game by calling itself recursively with requestAnimationFrame function animate() { requestAnimationFrame(animate); // Call functions to move enemy, check if player is in range, and check for collisions moveEnemy(); checkPlayerInRange(player); checkCollision(); // If jump key is pressed, call jump function if (jumpKeyDown) { jump(); } // Add gravity to the player's velocity velocity += gravity; // Calculate new top position for the player let newTop = player.offsetTop + velocity; // Check if player has hit the ground and reset jumpsCount if they have if (newTop + player.offsetHeight >= ground.offsetTop) { newTop = ground.offsetTop - player.offsetHeight; jumpsCount = 0; } // Check if player has gone above the top of the screen and set their top position to 0 if they have if (newTop < 0) { newTop = 0; } // Set the player's top position to the new top position player.style.top = newTop + 'px'; // Calculate new left position for the player let newLeft = player.offsetLeft; // If movingLeft is true, move the player to the left if (movingLeft) { newLeft = player.offsetLeft - 5; } // If movingRight is true, move the player to the right if (movingRight) { newLeft = player.offsetLeft + 5; } // Check if player has gone beyond the left side of the screen and set their left position to 0 if they have if (newLeft < 0) { newLeft = 0; } // Check if player has gone beyond the right side of the screen and set their left position to the maximum possible if they have if (newLeft + player.offsetWidth > window.innerWidth) { newLeft = window.innerWidth - player.offsetWidth; } // Set the player's left position to the new left position player.style.left = newLeft + 'px'; // Call function to calculate the distance the player has traveled calculateDistanceTraveled(); } function moveEnemy() { // Calculate distance between player and enemy let distanceToPlayer = Math.sqrt(Math.pow(player.offsetLeft - enemyPosition, 2)); // Follow the player when the player is within 750 pixels of the enemy if (distanceToPlayer <= 750) { // Update enemySpeed to follow the player if (player.offsetLeft < enemyPosition) { enemySpeed = -7; } else { enemySpeed = 7; } // Jump if player is above enemy and within 100 pixels on both sides let playerAbove = player.offsetTop + player.offsetHeight < enemy.offsetTop; let playerInRange = distanceToPlayer <= 100; if (playerAbove && playerInRange) { jumpEnemy(); } } else { // Perform searching behavior // Move enemy towards nearest wall if (enemyPosition < window.innerWidth / 2) { enemySpeed = 7; } else { enemySpeed = -7; } // Turn around when enemy reaches wall if (enemyPosition <= 0 || enemyPosition + enemy.offsetWidth >= window.innerWidth) { enemySpeed = -enemySpeed; } } // Update enemy position enemyPosition += enemySpeed; // Ensure enemy stays within the screen boundaries if (enemyPosition < 0) { enemyPosition = 0; } else if (enemyPosition + enemy.offsetWidth > window.innerWidth) { enemyPosition = window.innerWidth - enemy.offsetWidth; } // Update enemy position and velocity enemy.style.left = enemyPosition + 'px'; enemyVelocity += gravity; let newTop = enemy.offsetTop + enemyVelocity; // Stop enemy from falling below ground if (newTop + enemy.offsetHeight >= ground.offsetTop) { newTop = ground.offsetTop - enemy.offsetHeight; enemyVelocity = 0; } // Stop enemy from moving above the screen if (newTop < 0) { newTop = 0; } // Update enemy vertical position enemy.style.top = newTop + 'px'; } function checkCollision() { if ( player.offsetLeft + player.offsetWidth >= enemy.offsetLeft && player.offsetLeft <= enemy.offsetLeft + enemy.offsetWidth && player.offsetTop + player.offsetHeight >= enemy.offsetTop && player.offsetTop <= enemy.offsetTop + enemy.offsetHeight ) { // player collides with enemy // alert('Game over!'); } else if ( enemy.offsetTop + enemy.offsetHeight >= player.offsetTop && enemy.offsetLeft + enemy.offsetWidth >= player.offsetLeft && enemy.offsetLeft <= player.offsetLeft + player.offsetWidth ) { // enemy collides with player enemyJump(); } else if ( player.offsetTop + player.offsetHeight >= enemy.offsetTop + enemy.offsetHeight && player.offsetLeft + player.offsetWidth >= enemy.offsetLeft && player.offsetLeft <= enemy.offsetLeft + enemy.offsetWidth ) { // player passes underneath enemy if (enemyVelocity > 0) { enemyJump(); // make the enemy jump if it's falling } } } // Add event listeners document.addEventListener('keydown', event => { if (event.code === 'Space' && jumpsCount < 1) { jump(); jumpKeyDown = true; } else if (event.code === 'KeyA') { movingLeft = true; } else if (event.code === 'KeyD') { movingRight = true; } }); document.addEventListener('keyup', event => { if (event.code === 'KeyA') { movingLeft = false; } else if (event.code === 'KeyD') { movingRight = false; } else if (event.code === 'Space') { jumpKeyDown = false; } }); // Call the animate function to start checkCollision(); animate(); </script> </body> </html>
问题排查与修复
核心问题:未定义的函数调用
在moveEnemy()函数中,当玩家满足跳跃触发条件时,代码调用了jumpEnemy()函数,但你实际定义的函数是enemyJump()——这是一个拼写错误。这个错误会导致JavaScript抛出未捕获的引用错误,直接中断游戏的动画循环,引发冻结。
修复步骤
修改moveEnemy()中的函数调用:
将:
jumpEnemy();
替换为:
enemyJump();
额外优化建议
- 合并重复逻辑:
checkPlayerInRange()和moveEnemy()中的玩家范围检测逻辑重复,可合并为一个函数减少冗余; - 统一变量命名:代码中同时存在
jumpsCount和Jumps两个类似变量,建议统一命名避免混淆; - 优化边界检测:在
moveEnemy()的搜索行为中,敌人到达边界时直接设置位置为边界值再反转速度,避免位置抖动。
修复后的完整moveEnemy()函数:
function moveEnemy() { // Calculate distance between player and enemy let distanceToPlayer = Math.sqrt(Math.pow(player.offsetLeft - enemyPosition, 2)); // Follow the player when the player is within 750 pixels of the enemy if (distanceToPlayer <= 750) { // Update enemySpeed to follow the player enemySpeed = player.offsetLeft < enemyPosition ? -7 : 7; // Jump if player is above enemy and within 100 pixels on both sides let playerAbove = player.offsetTop + player.offsetHeight < enemy.offsetTop; let playerInRange = distanceToPlayer <= 100; if (playerAbove && playerInRange) { enemyJump(); } } else { // Perform searching behavior // Move enemy towards nearest wall enemySpeed = enemyPosition < window.innerWidth / 2 ? 7 : -7; // Turn around when enemy reaches wall if (enemyPosition <= 0) { enemyPosition = 0; enemySpeed = 7; } else if (enemyPosition + enemy.offsetWidth >= window.innerWidth) { enemyPosition = window.innerWidth - enemy.offsetWidth; enemySpeed = -7; } } // Update enemy position enemyPosition += enemySpeed; // Ensure enemy stays within the screen boundaries if (enemyPosition < 0) { enemyPosition = 0; } else if (enemyPosition + enemy.offsetWidth > window.innerWidth) { enemyPosition = window.innerWidth - enemy.offsetWidth; } // Update enemy position and velocity enemy.style.left = enemyPosition + 'px'; enemyVelocity += gravity; let newTop = enemy.offsetTop + enemyVelocity; // Stop enemy from falling below ground if (newTop + enemy.offsetHeight >= ground.offsetTop) { newTop = ground.offsetTop - enemy.offsetHeight; enemyVelocity = 0; } // Stop enemy from moving above the screen if (newTop < 0) { newTop = 0; } // Update enemy vertical position enemy.style.top = newTop + 'px'; }
内容的提问来源于stack exchange,提问作者Rambo
相关产品推荐
相关产品推荐

