我有一个球,它从光标位置掉落,并在光标移动到另一个位置时重新掉落。我试图每次单击鼠标时都放一个新球。我试过了:

canvas.addEventListener('click', function(event) {
  ball.draw();
});


但这似乎无能为力。有什么方法可以在点击时绘制一个新球,而不仅仅是一次又一次地重画相同的球吗?

这是其余的代码:

var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d");
var W = window.innerWidth,
    H = window.innerHeight;
var running = false;

canvas.height = H; canvas.width = W;

var ball = {},
    gravity = .5,
    bounceFactor = .7;

ball = {
  x: W,
  y: H,
  radius: 15,
  color: "BLUE",
  vx: 0,
  vy: 1,

  draw: function() {
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radius, 0, Math.PI*2, false);
    ctx.fillStyle = this.color;
    ctx.fill();
    ctx.closePath();
  }
};

function clearCanvas() {
  ctx.clearRect(0, 0, W, H);
}

function update() {
  clearCanvas();
  ball.draw();

  ball.y += ball.vy;

  ball.vy += gravity;
  if(ball.y + ball.radius > H) {
    ball.y = H - ball.radius;
    ball.vy *= -bounceFactor;
  }
}

canvas.addEventListener("mousemove", function(e){
  ball.x = e.clientX;
  ball.y = e.clientY;
  ball.draw();
});
setInterval(update, 1000/60);

ball.draw();

最佳答案

只需重写ball对象,它就可以实例化:

function Ball(W, H) {
  this.x = W;
  this.y = H;
  this.radius = 15;
  this.color = "blue";
  this.vx = 0;
  this.vy = 1;


}

将方法移至原型(这将使它们可在实例之间共享)。此外,添加更新方法,以便可以本地化更新:

Ball.prototype = {
  draw: function() {
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radius, 0, Math.PI*2, false);
    ctx.fillStyle = this.color;
    ctx.fill();
    ctx.closePath();
  },

  update: function() {
    this.y += this.vy;
    this.vy += gravity;
    if(this.y + this.radius > H) {
      this.y = H - this.radius;
      this.vy *= -bounceFactor;
    }
  }
};


在click事件中(考虑将数组重命名为复数形式-更加容易区分。在代码中,稍后将用单个球形对象覆盖“数组”(定义为对象)):

var balls = [];                // define an array to hold the balls


为了使click事件使用鼠标的x和y位置作为球的起点,我们首先需要对其进行调整,因为它是相对于客户端窗口而不是画布。为此,我们获取画布的绝对位置,并将其从客户端坐标中减去:

canvas.addEventListener('click', function(event) {
  var rect = this.getBoundingClientRect(),  // adjust mouse position
      x = event.clientX - rect.left,
      y = event.clientY - rect.top;

  balls.push(new Ball(x, y));               // add a new instance
});


现在,在主动画循环中,只需遍历数组即可。每当有一个新球时,都会对其进行考虑和更新-我们只是让循环运行直到满足某些条件(未显示):

function update() {
  clearCanvas();

  for(var i = 0, ball; ball = balls[i]; i++) {
    ball.draw();    // this will draw current ball
    ball.update();  // this will update its position
  }

  requestAnimationFrame();
}


现场例子

如果将它们放在一起,将得到:



var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d"),
    W = canvas.width, // simplified for demo
    H = canvas.height,
    gravity = .5,
    bounceFactor = .7;

function Ball(x, y) {
  this.x = x;
  this.y = y;
  this.radius = 15;
  this.color = "blue";
  this.vx = 0;
  this.vy = 1
}

Ball.prototype = {
  draw: function() {
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
    ctx.fillStyle = this.color;
    ctx.fill();
    ctx.closePath();
  },

  update: function() {
    this.y += this.vy;
    this.vy += gravity;  // todo: limit bounce at some point or this value will be added
    if (this.y + this.radius > H) {
      this.y = H - this.radius;
      this.vy *= -bounceFactor;
    }
  }
};

function clearCanvas() {
  ctx.clearRect(0, 0, W, H);
}

var balls = []; // define an array to hold the balls

canvas.addEventListener('click', function(event) {
  var rect = this.getBoundingClientRect(),  // adjust mouse position
      x = event.clientX - rect.left,
      y = event.clientY - rect.top;
  balls.push(new Ball(x, y));               // add a new instance
});


(function update() {
  clearCanvas();

  for (var i = 0, ball; ball = balls[i]; i++) {
    ball.draw(); // this will draw current ball
    ball.update(); // this will update its position
  }

  requestAnimationFrame(update);
})();

canvas {background:#aaa}

<canvas id="canvas" width=600 height=400></canvas>

09-25 17:25