我最近做了一个JS Pong游戏。它运作良好,但球很少卡在底部或顶部。看起来好像是穿过墙壁的一半,并且不断弹跳。 Video of the issue happening.您可以尝试游戏here。我不知道为什么会发生此问题,因为逻辑似乎正确,并且90%的时间正确运行。这是我程序的主要两个功能:

function moveAll() {
  if (showingWinScreen) {
    return;
  }
  computerMovement();
  ballX += ballSpeedX;
  ballY += ballSpeedY;
  if (ballY <= 10) {
    ballSpeedY = -ballSpeedY;
  } else if (ballY >= HEIGHT - 10) {
    ballSpeedY = -ballSpeedY;
  }
  if (ballX >= WIDTH - 10) {
    if ((ballY > paddleY) && (ballY < paddleY + 100)) {
      ballSpeedX = -ballSpeedX;
      var deltaY = ballY - paddleY - 50;
      ballSpeedY = deltaY / 5;
    } else {
      player1Score++;
      ballReset();
    }
  } else if (ballX <= 10) {
    if ((ballY > mouseY - 50) && (ballY < mouseY + 50)) {
      ballSpeedX = -ballSpeedX;
      deltaY = ballY - mouseY;
      ballSpeedY = deltaY / 6;
    } else {
      player2Score++;
      ballReset();
    }
  }
}

function drawAll() {
  if (showingWinScreen) {
    colorRect(0, 0, WIDTH, HEIGHT, "black");
    canvas.fillStyle = "yellow";
    canvas.fillText("Click to continue!", 300, 300);
    if (player1Score == WINNING_SCORE) {
      canvas.fillText("You won!", 360, 500);
    } else if (player2Score == WINNING_SCORE) {
      canvas.fillText("The computer beat you!", 280, 500);
    }
    return;
  }
  colorRect(0, 0, WIDTH, HEIGHT, "black");
  drawNet();
  makeCircle(ballX, ballY, 10, 0, Math.PI * 2, "red");
  colorRect(790, paddleY, 10, 100, "cyan");
  colorRect(0, mouseY - 50, 10, 100, "yellow");
  canvas.fillStyle = "white";
  canvas.fillText(player1Score + "    " + player2Score, 360, 100);
}


谢谢您的帮助!

最佳答案

我认为只有一种情况可能发生:当您在碰撞的帧中降低速度时。

当速度保持不变时,无论如何,您的球将始终弹回到先前的帧位置:



var cvs = document.querySelector("canvas");
var ctx = cvs.getContext("2d");
var balls = [
  Ball(50, 50, 0, 5, 5, "red"),
  Ball(100, 50, 0, 5, 10, "blue"),
  Ball(150, 50, 0, 5, 15, "green"),
  Ball(200, 50, 0, 5, 20, "yellow")
];

var next = () => {
  updateFrame(balls);
  drawFrame(balls);
}

var loop = () => {
  requestAnimationFrame(() => {
    next();
    loop();
  });
}

next();

function Ball(x, y, vx, vy, r, color) {
  return {
    x: x,
    y: y,
    vx: vx,
    vy: vy,
    r: r,
    color: color
  }
};

function updateBall(b) {
  b.x += b.vx;
  b.y += b.vy;

  if (b.y <= b.r ||
      b.y >= cvs.height - b.r) {
     b.vy *= -1;
  }
};

function drawBall(b) {
  ctx.beginPath();
  ctx.fillStyle = b.color;
  ctx.arc(b.x, b.y, b.r, 0, 2 * Math.PI, false);
  ctx.fill();
}

function updateFrame(balls) {
   balls.forEach(updateBall);
}

function drawFrame(balls) {
  ctx.clearRect(0, 0, cvs.width, cvs.height);
  balls.forEach(drawBall);
};

<canvas width="300" height="150" style="background: #454545"></canvas>
<button onclick="next()">next</button>
<button onclick="loop()">run</button>





但是,当速度改变时,事情就卡住了:



var cvs = document.querySelector("canvas");
var ctx = cvs.getContext("2d");
var balls = [
  Ball(50, 50, 0, 10, 5, "red"),
  Ball(100, 50, 0, 10, 10, "blue"),
  Ball(150, 50, 0, 10, 15, "green"),
  Ball(200, 50, 0, 10, 20, "yellow")
];

var next = () => {
  updateFrame(balls);
  drawFrame(balls);
}

var loop = () => {
  requestAnimationFrame(() => {
    next();
    loop();
  });
}

next();

function Ball(x, y, vx, vy, r, color) {
  return {
    x: x,
    y: y,
    vx: vx,
    vy: vy,
    r: r,
    color: color
  }
};

function updateBall(b) {
  b.x += b.vx;
  b.y += b.vy;

  if (b.y <= b.r ||
      b.y >= cvs.height - b.r) {
     b.vy *= -0.5;
  }
};

function drawBall(b) {
  ctx.beginPath();
  ctx.fillStyle = b.color;
  ctx.arc(b.x, b.y, b.r, 0, 2 * Math.PI, false);
  ctx.fill();
}

function updateFrame(balls) {
   balls.forEach(updateBall);
}

function drawFrame(balls) {
  ctx.clearRect(0, 0, cvs.width, cvs.height);
  balls.forEach(drawBall);
};

<canvas width="300" height="150" style="background: #454545"></canvas>
<button onclick="next()">next</button>
<button onclick="loop()">run</button>





就您而言,我认为只有在同时发生桨叶碰撞和墙壁碰撞时才能发生这种情况。

一种快速实施的解决方案是在平移球位置之前检查新位置是否有效。如果您不希望精确的位置,可以将球放在碰撞点。请注意,这会产生稍微偏离的框架。

例如。:

var newY = ballY + ballSpeedY;

// Top wall
if(newY <= 10) {
  ballY = 10;
  ballSpeedY = -ballSpeedY;
}
// Bottom wall
else if(newY >= HEIGHT-10){
  ballY = HEIGHT - 10;
  ballSpeedY = -ballSpeedY;
}
// No collision
else {
  ballY = newY;
}


更新:可能发生的情况的更详细描述

假设您的球与画布的顶部边框以及同一帧中的球拍相撞。

首先,将球移动到碰撞位置:ballY += ballSpeedY;假设您的ballY为4,而您的ballSpeedY为-5,则将球定位在墙内的-1

如果这是唯一的冲突,则应该没事。翻转速度(ballSpeedY = -ballSpeedY),因此在下一帧中,您的球应回到-1 + 5 = 4,因此ballY将再次为4,并且您的球将在下一帧中向4 + 5 = 9移动。

现在出现一个问题,当在-1定位的框架中时,您也会与拨片碰撞!当桨击中球时,您将修改球速:ballSpeedY = deltaY / 5;。如果结果是< 1,则您的球将无法在下一帧离开墙壁。例如,您的球将代替-1 + 5 = 4移至:-1 + 0.5 = -0.5

现在,您的球将无法重新进入比赛,因为下一帧将再次计算碰撞并翻转速度。当球卡住时,您会看到有弹性的颤抖效果。

一个天真但相当不错的解决方案是仅将球的位置更新为有效位置。即:永不碰撞。

07-25 20:55