You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自制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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 21:55:01