为什么我的 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>
两个问题:
你不断地添加到 physicsX,所以它移动的距离量不断增加。只需保持 physicsX 不变即可移动相同的量。 (实际上不是,因为你设置的每个动画帧 PhysicsX = 0,但逻辑是错误的。当你修复真正的错误时,这会导致单位不能正确移动。)
将 '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;
所以,我正在尝试编写一个游戏,其中有一个球会追逐玩家,目前我正在编写玩家物理特性的代码。出于某种原因,随着玩家来回走动,它变得越来越快,但我不明白为什么。我认为这可能与我将 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>
两个问题:
你不断地添加到 physicsX,所以它移动的距离量不断增加。只需保持 physicsX 不变即可移动相同的量。 (实际上不是,因为你设置的每个动画帧 PhysicsX = 0,但逻辑是错误的。当你修复真正的错误时,这会导致单位不能正确移动。)
将 '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;