让球动起来

本篇是 Gamedev Canvas tutorial (en-US) 10 节教程中的第二节。如果你完成了本篇教程之后,你可以从 Gamedev-Canvas-workshop/lesson2.html 看到源码。

从上一节中你已经知道如何去绘制一个球。现在让我们使它动起来。从技术上讲,我们将在画布上绘制一个球,之后让它消失,然后在一个稍微不用的位置上再绘制一个一样的球。就想电影里的每一帧动起来的感觉。

我们需要定义一个绘图函数,每次使用一组不同的变量改变球体的位置;循环调用以保持画布上每一帧不断更新。你可以使用 JavaScript 时间函数 setInterval() (en-US) 或者 window.requestAnimationFrame()

在你的 HTML 文件只保留前两行,删除其他所有的 JavaScript 代码并在 draw() 函数中添加以下内容保证每 10 毫秒执行一次 draw() 函数:

js
function draw() {
  // drawing code
}
setInterval(draw, 10);

得益于 setInterval 的无限性,使得 draw() 函数将每 10 毫秒就会被调用,除非我们停止它。现在,我们来绘制小球吧,在 draw() 函数中添加以下内容:

js
ctx.beginPath();
ctx.arc(50, 50, 10, 0, Math.PI * 2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();

现在,尝试更新你的代码,球会在每一帧画面被绘制

让球动起来

你不会注意到球正在不停地被重新刷,因为它没有移动。让我们改变这种情况。首先,我们不再使用固定位置 (50,50),而是用 x 和 y 的变量来定义画布底部的起始点,然后使用这些变量来定义圆被绘制的位置。

首先,在draw()函数上方添加以下两行,以定义xy

js
var x = canvas.width / 2;
var y = canvas.height - 30;

接下来更新 draw() 函数,在 arc() 方法中使用 xy 变量,如下面高亮行所示:

js
function draw() {
  ctx.beginPath();
  ctx.arc(x, y, 10, 0, Math.PI * 2);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
}

现在到了最重要的部分:我们想要在每一帧都被绘制出来之后,给 xy 添加一个较小的值,让它看起来像是在移动。让我们将这些值定义为 dxdy,并将它们的值分别设为 2-2。在你的 x 和 y 变量声明下方添加以下内容:

js
var dx = 2;
var dy = -2;

最后要做的是在每一帧上更新 xy,在每一次更新中,把球画在新的位置上。将下面的两条新线添加到你的 draw() 函数:

js
function draw() {
  ctx.beginPath();
  ctx.arc(x, y, 10, 0, Math.PI * 2);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
  x += dx;
  y += dy;
}

再次保存代码,并在浏览器中尝试。很好,尽管看起来球在后面留下了痕迹:

在每一帧更新之前清空画布

球移动时留下了轨迹,因为我们在每一帧上都画了一个新的圆,而没有去掉之前的一个圆。不要担心,因为有一个方法来清空画布的内容:clearRect()。该方法有四个参数:矩形左上角的 xy 坐标,以及矩形的右下角的 xy 坐标。这个矩形覆盖的整个区域里,之前所画的任何内容将被清除。

将下列高亮显示行添加到 draw() 函数:

js
function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.beginPath();
  ctx.arc(x, y, 10, 0, Math.PI * 2);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
  x += dx;
  y += dy;
}

保存你的代码并再次尝试,这次你将看到球移动后没有留下轨迹。每隔 10 毫秒,画布就会被清除,蓝色的圆圈 (我们的球) 将被绘制在一个给定的位置上,而 xy 的值将在下一个帧被更新。

保持代码整洁

在接下来的几篇文章中,我们将在 draw() 函数中添加越来越多的命令,因此尽可能保持简单和整洁是很好的。让我们从把绘制球的代码移至一个单独的函数。

用以下两个函数替换现有的 draw() 函数:

js
function drawBall() {
  ctx.beginPath();
  ctx.arc(x, y, 10, 0, Math.PI * 2);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
}

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawBall();
  x += dx;
  y += dy;
}

比较你的代码

你可以在下面的实时演示中查看本文的代码,并使用它来更好地了解其工作原理:

练习:尝试改变移动球的速度,或者移动球的方向。

下一步

我们已经画了我们的球,并将其移动,但它仍然消失在画布的边缘。在第三章中,我们将探讨如何使其 从墙壁上反弹 (en-US).