我目前正在尝试制作大学版Breakout。感谢您帮助我画桨。现在,我发现自己无法使球在画布边缘反弹(中间除外)。我已经尝试过在ball.x和ball.y中添加和减去分数(大于或等于canvas.width和canvas.height都起作用),但是对于小于或等于0的情况,似乎没有成功。这是JavaScript代码:

    var canvas = document.getElementById("breakout");
var ctx = canvas.getContext("2d");
var PADDLE_WIDTH_PX = canvas.width / 5;
var PADDLE_HEIGHT_PX = 10;
var PADDLE_SPEED = 450;

var ball = {
  x: canvas.width / 2,   //pixels
  y: canvas.height / 2,  //pixels
  xSpeed: 500,           //pixels per second
  ySpeed: 500,           //pixels per second
  radius: 100  //the ball is exceptionally large so that I can see what part of the ball is surpassing the canvas edge before the motion is reversed
}

var paddle = {
//radius: 5,
/*speed: 500,
TopRight: ctx.moveTo(canvas.width / 1.35, canvas.height - (canvas.height / 12.5)),
TopSide: ctx.lineTo(canvas.width / 2, canvas.height - (canvas.height / 12.5)),
RightSide: ctx.lineTo(canvas.width / 1.35, canvas.height - (canvas.height / 27.5)),
BottomLeft: ctx.moveTo(canvas.width / 2, canvas.height - (canvas.height / 27.5)),
LeftSide: ctx.lineTo(canvas.width / 2, canvas.height - (canvas.height / 12.5)),
BottomSide: ctx.lineTo(canvas.width / 1.35, canvas.height - (canvas.height / 27.5))*/
xSpeed: 450,
x: (canvas.width - PADDLE_WIDTH_PX) / 2,
y: canvas.height - PADDLE_HEIGHT_PX
}

var keysDown = {};
window.addEventListener("keydown",function(e) {
keysDown[e.keyCode] = true;
});
window.addEventListener("keyup",function(e) {
delete keysDown[e.keyCode];
});


function render() {
  //clear the canvas
  ctx.clearRect(0, 0, canvas.width, canvas.height)
  // draw the ball
  ctx.fillStyle = "white";
  ctx.beginPath();
  ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
  ctx.closePath();
  ctx.fill();
  ctx.beginPath();
  //ctx.fillStyle = "red";
  /*ctx.moveTo(canvas.width - (2*paddle.x), canvas.height - (2*paddle.y));
  /*ctx.lineTo(canvas.width / 2, canvas.height - (canvas.height / 12.5));
  ctx.lineTo(canvas.width / 1.35, canvas.height - (canvas.height / 27.5));
  ctx.moveTo(canvas.width / 2, canvas.height - (canvas.height / 27.5));
  ctx.lineTo(canvas.width / 2, canvas.height - (canvas.height / 12.5));
  ctx.lineTo(canvas.width / 1.35, canvas.height - (canvas.height / 27.5));
  ctx.fill();
  ctx.closePath();*/
  /*ctx.lineTo(canvas.width - (2*paddle.x), canvas.height - paddle.y);
  ctx.moveTo(canvas.width - paddle.x, canvas.height - paddle.y);
  ctx.lineTo(canvas.width - paddle.x, canvas.height - (2*paddle.y));
  ctx.lineTo(canvas.width - (2*paddle.x), (canvas.height -paddle.y));*/
  ctx.fillRect(paddle.x, paddle.y, PADDLE_WIDTH_PX, PADDLE_HEIGHT_PX);
  /*ctx.closePath();
  ctx.fill();*/
}

function update(elapsed) {
  //update the ball position according to the elapsed time
  ball.y += ball.ySpeed * elapsed;
  ball.x += ball.xSpeed * elapsed;
  /*paddle.TopRight += paddle.speed * elapsed;
  paddle.BottomLeft += paddle.speed * elapsed;
  paddle.RightSide += paddle.speed * elapsed;
  paddle.LeftSide += paddle.speed * elapsed;
  paddle.TopSide += paddle.speed * elapsed;
  paddle.BottomSide += paddle.speed * elapsed;*/
  /*paddle.x += paddle.xSpeed * elapsed;
  paddle.y += paddle.xSpeed * elapsed;*/

  //bounce the ball of all edges
if (37 in keysDown && paddle.x > 0)
  paddle.x -= PADDLE_SPEED * elapsed;
if (39 in keysDown && paddle.x + PADDLE_WIDTH_PX < canvas.width)
  paddle.x += PADDLE_SPEED * elapsed;

  if (ball.x+(ball.x/7) >= canvas.width) {
    ball.x -= 5;
    ball.xSpeed *= -1;
  }
  if (ball.x-(ball.x/7) <= 0) {
      ball.x += 5;
      ball.xSpeed *= -1;
  }
  if (ball.y+(ball.y/100) <= 0) {
    ball.y += 5;
    ball.ySpeed *= -1;
  }
  if (ball.y+(ball.y/3) >= canvas.height) {
    ball.y -= 5;
    ball.ySpeed *= -1;
    }

  /*
  The problem here is that sometimes the ball gets 'stuck' to an edge.

  This can occur when the ball passes beyond an edge in a frame when the
  elapsed time is relatively large. In some cases, when the elapsed time in the
  next frame is relatively short, the ball doesn't reach the edge to get back
  into play. This results in another flip of the velocity and the ball becomes
  'trapped' on the edge.

  e.g.
  xSpeed = -500, x = 10, elapsed = 0.2 => xSpeed = 500, x = -90 (xMovement = -100)
  xSpeed = 500, x = -90, elapsed = 0.1 => xSpeed = -500, x = -40 (xMovement = +50)
  xSpeed = -500, x = -40, elapsed = 0.1 => xSpeed = 500, x = -40 (xMovement = -50)
  and so on ...until a larger elapsed time occurs in the right direction

  The fix for this is to move the ball to the edge when the velocity is flipped.
  */
}

var previous;
function run(timestamp) {
  if (!previous) previous = timestamp;          //start with no elapsed time
  var elapsed = (timestamp - previous) / 1000;  //work out the elapsed time
  update(elapsed);                              //update the game with the elapsed time
  render();                                     //render the scene
  previous = timestamp;                         //set the (globally defined) previous timestamp ready for next time
  window.requestAnimationFrame(run);            //ask browser to call this function again, when it's ready
}

//trigger the game loop
window.requestAnimationFrame(run);


感谢您抽时间阅读
-困惑的学生

最佳答案

桨板存在许多问题。

首先,您可能希望它具有固定的大小,所以让我们定义
它在文件开头的尺寸(将其放在代码的前两行之后,因为它使用canvas来将桨叶宽度设置为其宽度的1/5-我认为这就是您尝试做的事情):

var PADDLE_WIDTH_PX = canvas.width / 5;
var PADDLE_HEIGHT_PX = 10;


使用此方法,您可以将桨叶初始化为位于画布的底部和中间:

var paddle = {
  x: (canvas.width - PADDLE_WIDTH_PX) / 2,
  y: canvas.height - PADDLE_HEIGHT_PX
}


xy是拨片的左上角,因此右侧位于x + PADDLE_WIDTH_PX,底部位于y + PADDLE_HEIGHT_PX
知道了这一点,您可以像这样通过所有四个角绘制一条路径:

ctx.beginPath();
ctx.moveTo(paddle.x, paddle.y);
ctx.lineTo(paddle.x + PADDLE_WIDTH_PX, paddle.y);
ctx.lineTo(paddle.x + PADDLE_WIDTH_PX, paddle.y + PADDLE_HEIGHT_PX);
ctx.lineTo(paddle.x, paddle.y + PADDLE_HEIGHT_PX);
ctx.lineTo(paddle.x, paddle.y);
ctx.closePath();


但是由于桨只是一个矩形,所以使用一种绘制矩形的方法-fillRect更容易,如下所示:

ctx.fillRect(paddle.x, paddle.y, PADDLE_WIDTH_PX, PADDLE_HEIGHT_PX);


无论哪种方式,桨的所有四个角都一起移动,因此不会增长或收缩。

因此,如果将它放在您的render函数中,它看起来像这样:

function render() {
  //clear the canvas
  ctx.clearRect(0, 0, canvas.width, canvas.height)
  // draw the ball
  ctx.fillStyle = "white";
  ctx.beginPath();
  ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
  ctx.closePath();
  ctx.fill();

  // draw the paddle
  ctx.fillStyle = "red";
  ctx.fillRect(paddle.x, paddle.y, PADDLE_WIDTH_PX, PADDLE_HEIGHT_PX);
}


最后一件事是在按向左和向右箭头键时使桨移动。

仅当按下向左箭头或向右箭头时,桨叶才会移动。否则,其速度为0,并且位于其位置。因此,paddle对象不需要xSpeed成员变量。
此外,拨片仅水平移动,因此其x变量仅发生变化,y始终相同。

首先让我们在文件开头定义桨的速度:

var PADDLE_SPEED = 300;


然后将移动逻辑放在update函数中:

if (37 in keysDown && paddle.x > 0)
  paddle.x -= PADDLE_SPEED * elapsed;
else if (39 in keysDown && paddle.x + PADDLE_WIDTH_PX < canvas.width)
  paddle.x += PADDLE_SPEED * elapsed;


您会注意到,仅当按下箭头键并且桨叶不在边缘时,桨叶位置才会更改。

paddle有关的所有其他代码都应从update函数中删除,使其看起来像这样(我删除了大多数注释):

function update(elapsed) {
  //update the ball position according to the elapsed time
  ball.y += ball.ySpeed * elapsed;
  ball.x += ball.xSpeed * elapsed;

  if (37 in keysDown && paddle.x > 0)
    paddle.x -= PADDLE_SPEED * elapsed;
  else if (39 in keysDown && paddle.x + PADDLE_WIDTH_PX < canvas.width)
    paddle.x += PADDLE_SPEED * elapsed;

  //bounce the ball of all edges
  if/*(*/(ball.x /*- (ball.x / 2))*/<= 0) {
    ball.x = 1;
    ball.xSpeed *= -1;
  }
  if /*(*/(ball.x /*+ (ball.x / 2))*/>= canvas.width) {
    ball.x = ball.x -1;
    ball.xSpeed *= -1;
  }
  if/*(*/(ball.y /*- (ball.y / 2))*/<= 0) {
    ball.y = 1;
    ball.ySpeed *= -1;
  }
  if /*(*/(ball.y /*+ (ball.y / 2))*/>= canvas.height) {
    ball.y = ball.y -1;
    ball.ySpeed *= -1;
  }
}

09-30 16:13