为什么我的 javascript 对象变得越来越快?

Why does my javascript object get faster and faster?

所以,我正在尝试编写一个游戏,其中有一个球会追逐玩家,目前我正在编写玩家物理特性的代码。出于某种原因,随着玩家来回走动,它变得越来越快,但我不明白为什么。我认为这可能与我将 physicsX 变量乘以 .85 有关,但我不知道这会如何影响它。这是我的代码-

var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var baseX = 100;
var baseY = 50;
var physicsY = 0;
var physicsX = 0;

function coronavirus() {
  ctx.beginPath();
  ctx.fillStyle = "blue";
  ctx.arc(50, 50, 5, 0, 2 * Math.PI, false);
  ctx.fill();
}

function ground() {
  ctx.beginPath();
  ctx.fillStyle = "green";
  ctx.rect(0, 140, screen.width, 10);
  ctx.fill();
}

function person() {
  ctx.beginPath();
  ctx.strokeStyle = "black";
  ctx.arc(baseX, baseY, 5, 0, 2 * Math.PI, false); //head
  ctx.stroke();
  ctx.moveTo(baseX, baseY + 5); //body
  ctx.lineTo(baseX, baseY + 20);
  ctx.stroke();
  ctx.moveTo(baseX, baseY + 20); //left leg
  ctx.lineTo(baseX - 3, baseY + 27);
  ctx.stroke();
  ctx.moveTo(baseX, baseY + 20); //right leg
  ctx.lineTo(baseX + 3, baseY + 27);
  ctx.stroke();
  ctx.moveTo(baseX - 5, baseY + 10); //arms
  ctx.lineTo(baseX + 5, baseY + 10);
  ctx.stroke();
}

function personHitbox() {
  ctx.beginPath();
  ctx.strokeStyle = "black"
  ctx.rect(baseX - 5, baseY - 5, 10, 32);
  ctx.stroke();
}

function personTouchingGround() {
  var personHitbox = {y: baseY - 5, height: 32}
  var ground = {y: 140} 
    if (personHitbox.y + personHitbox.height < ground.y) {
    touchingGround = false;
} else {
  touchingGround = true;
}
}

function personMoving() {
  if (touchingGround == false) {
    physicsY++;
    baseY = baseY + physicsY;
  }
  physicsX = 0;
  window.addEventListener('keydown', (e) => {
  if (e.key == "ArrowRight") {
    physicsX = physicsX + 0.001;
  }
  if (e.key == "ArrowLeft") {
    physicsX = physicsX - 0.001;
  }
  physicsX = physicsX * 0.85  
  baseX = baseX + physicsX;
});


}
function gameloop() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  new coronavirus();
  new person();
  new personHitbox();
  new personTouchingGround();
  new personMoving();
  new ground();
  requestAnimationFrame(gameloop);
}
gameloop();
canvas {
  width: 100%;
  height: 100%;
  margin: 0%;
}
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>repl.it</title>
    <link href="style.css" rel="stylesheet" type="text/css" />
  </head>
  <body>
    <canvas id="canvas"></canvas>
    <script src="script.js"></script>
  </body>
</html>

两个问题:

  1. 你不断地添加到 physicsX,所以它移动的距离量不断增加。只需保持 physicsX 不变即可移动相同的量。 (实际上不是,因为你设置的每个动画帧 PhysicsX = 0,但逻辑是错误的。当你修复真正的错误时,这会导致单位不能正确移动。)

  2. 将 'keydown' 事件绑定移到 personMoving() 之外,使其只执行一次。每次调用 personMoving() 时都会执行您的事件侦听器绑定,因此它会一遍又一遍地绑定 'key' 事件,然后随着时间的推移,您会越来越多地触发 'key' 事件。
    因此在 100 个动画帧之后,每个按键都会触发 baseX 和 PhysicsX 添加代码 100 次。
    您应该只绑定一次按键事件。

我还使用 Math.abs 和 *-1 进行左右移动。

var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var baseX = 100;
var baseY = 50;
var physicsY = 0;
var physicsX = 0;

function coronavirus() {
  ctx.beginPath();
  ctx.fillStyle = "blue";
  ctx.arc(50, 50, 5, 0, 2 * Math.PI, false);
  ctx.fill();
}

function ground() {
  ctx.beginPath();
  ctx.fillStyle = "green";
  ctx.rect(0, 140, screen.width, 10);
  ctx.fill();
}

function person() {
  ctx.beginPath();
  ctx.strokeStyle = "black";
  ctx.arc(baseX, baseY, 5, 0, 2 * Math.PI, false); //head
  ctx.stroke();
  ctx.moveTo(baseX, baseY + 5); //body
  ctx.lineTo(baseX, baseY + 20);
  ctx.stroke();
  ctx.moveTo(baseX, baseY + 20); //left leg
  ctx.lineTo(baseX - 3, baseY + 27);
  ctx.stroke();
  ctx.moveTo(baseX, baseY + 20); //right leg
  ctx.lineTo(baseX + 3, baseY + 27);
  ctx.stroke();
  ctx.moveTo(baseX - 5, baseY + 10); //arms
  ctx.lineTo(baseX + 5, baseY + 10);
  ctx.stroke();
}

function personHitbox() {
  ctx.beginPath();
  ctx.strokeStyle = "black"
  ctx.rect(baseX - 5, baseY - 5, 10, 32);
  ctx.stroke();
}

function personTouchingGround() {
  var personHitbox = {
    y: baseY - 5,
    height: 32
  }
  var ground = {
    y: 140
  }
  if (personHitbox.y + personHitbox.height < ground.y) {
    touchingGround = false;
  } else {
    touchingGround = true;
  }
}

function personMoving() {
  if (touchingGround == false) {
    physicsY++;
    baseY = baseY + physicsY;
  }


}


  physicsX = 10;
  window.addEventListener('keydown', (e) => {
    if (e.key == "ArrowRight") {
      physicsX = Math.abs(physicsX);
    }
    if (e.key == "ArrowLeft") {
      physicsX = Math.abs(physicsX)*-1;
    }
//    physicsX = physicsX * 0.85
    baseX = baseX + physicsX;
//    put this console.log in your original code to see what I mean
//    console.log(baseX)
  });

function gameloop() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  new coronavirus();
  new person();
  new personHitbox();
  new personTouchingGround();
  new personMoving();
  new ground();
  requestAnimationFrame(gameloop);
}
gameloop();
<canvas id="canvas"></canvas>

每按一个键,playerX 变量只减少 15% (0.15)。要解决此问题,只需将该行移到按键事件侦听器之外的游戏循环中(就在循环的每次迭代中它将成为 运行 的某个地方)。

编辑:如@user120242 所述,事件侦听器也应移出循环。但是,我稍作修改的解决方案保留了(我相信是有意的)水平速度。唯一的问题是两种解决方案的按键都有延迟,您可以参考How to fix delay in javascript keydown

var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var baseX = 100;
var baseY = 50;
var physicsY = 0;
var physicsX = 0;
//move this outside
window.addEventListener('keydown', (e) => {
  if (e.key == "ArrowRight") {
      physicsX += 5;
  }
  if (e.key == "ArrowLeft") {
      physicsX -= 5;
  }
});

function coronavirus() {
  ctx.beginPath();
  ctx.fillStyle = "blue";
  ctx.arc(50, 50, 5, 0, 2 * Math.PI, false);
  ctx.fill();
}

function ground() {
  ctx.beginPath();
  ctx.fillStyle = "green";
  ctx.rect(0, 140, screen.width, 10);
  ctx.fill();
}

function person() {
  ctx.beginPath();
  ctx.strokeStyle = "black";
  ctx.arc(baseX, baseY, 5, 0, 2 * Math.PI, false); //head
  ctx.stroke();
  ctx.moveTo(baseX, baseY + 5); //body
  ctx.lineTo(baseX, baseY + 20);
  ctx.stroke();
  ctx.moveTo(baseX, baseY + 20); //left leg
  ctx.lineTo(baseX - 3, baseY + 27);
  ctx.stroke();
  ctx.moveTo(baseX, baseY + 20); //right leg
  ctx.lineTo(baseX + 3, baseY + 27);
  ctx.stroke();
  ctx.moveTo(baseX - 5, baseY + 10); //arms
  ctx.lineTo(baseX + 5, baseY + 10);
  ctx.stroke();
}

function personHitbox() {
  ctx.beginPath();
  ctx.strokeStyle = "black"
  ctx.rect(baseX - 5, baseY - 5, 10, 32);
  ctx.stroke();
}

function personTouchingGround() {
  var personHitbox = {
    y: baseY - 5,
    height: 32
  }
  var ground = {
    y: 140
  }
  if (personHitbox.y + personHitbox.height < ground.y) {
    touchingGround = false;
  } else {
    touchingGround = true;
  }
}

function personMoving() {
  if (touchingGround == false) {
    physicsY++;
    baseY += physicsY;
  }
  //physicsX = 0; remove this line of code
  //moving the line here will guarantee physicsX decreases on each
  //iteration of the loop.
  physicsX *= 0.85;
  baseX += physicsX;
}

function gameloop() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  new coronavirus();
  new person();
  new personHitbox();
  new personTouchingGround();
  new personMoving();
  new ground();
  requestAnimationFrame(gameloop);
}
gameloop();
<canvas id="canvas"></canvas>

此外,使用 += 可以简化您的代码。例如: playerX = playerX + 15; 等同于 playerX += 15;