桨和键盘控制

这是 Gamedev Canvas 教程 中 10 个步骤中的第 4 步。您可以从 Gamedev-Canvas-workshop/lesson4.html 中找到完成本课后代码的正确示例。

球在墙上自由弹跳,您可以无限期地观看它,但目前没有交互性。如果您无法控制它,那就不是游戏!因此,让我们添加一些用户交互:一个可控的桨。

定义一个用来击打球的桨

所以,我们需要一个桨来击打球。让我们为它定义一些变量。将以下变量添加到代码顶部,在其他变量旁边

js
const paddleHeight = 10;
const paddleWidth = 75;
let paddleX = (canvas.width - paddleWidth) / 2;

这里我们定义了桨的高度和宽度,以及它在 x 轴上的起始点,用于后面的代码计算。让我们创建一个函数,在屏幕上绘制桨。将以下代码添加到 drawBall() 函数下方

js
function drawPaddle() {
  ctx.beginPath();
  ctx.rect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
}

允许用户控制桨

我们可以将桨绘制在任何我们想要的地方,但它应该响应用户的操作。现在是实现一些键盘控制的时候了。我们需要以下内容

  • 两个变量用于存储关于是否按下了左右控制按钮的信息。
  • 两个用于 keydownkeyup 事件的事件监听器。当按钮被按下时,我们想要运行一些代码来处理桨的移动。
  • 两个处理 keydownkeyup 事件的函数,即按下按钮时将运行的代码。
  • 能够将桨向左和向右移动

可以使用布尔变量定义和初始化已按下的按钮,例如示例中的情况。将这些行添加到变量组附近

js
let rightPressed = false;
let leftPressed = false;

两者的默认值为 false,因为一开始没有按下控制按钮。为了监听按键,我们将设置两个事件监听器。将以下代码行添加到 JavaScript 底部的 setInterval() 行上方

js
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);

当键盘上的任何键触发 keydown 事件(当按下键时)时,keyDownHandler() 函数将被执行。第二个监听器也遵循相同的模式:keyup 事件将触发 keyUpHandler() 函数(当键停止被按下时)。现在将这些添加到您的代码中,位于 addEventListener() 行下方

js
function keyDownHandler(e) {
  if (e.key === "Right" || e.key === "ArrowRight") {
    rightPressed = true;
  } else if (e.key === "Left" || e.key === "ArrowLeft") {
    leftPressed = true;
  }
}

function keyUpHandler(e) {
  if (e.key === "Right" || e.key === "ArrowRight") {
    rightPressed = false;
  } else if (e.key === "Left" || e.key === "ArrowLeft") {
    leftPressed = false;
  }
}

当我们按下某个键时,此信息将存储在一个变量中。每种情况下的相关变量都被设置为 true。当释放键时,变量被重置为 false

这两个函数都将事件作为参数,由 e 变量表示。您可以从中获取有用的信息:key 包含有关被按下的键的信息。大多数浏览器使用 ArrowRightArrowLeft 表示左右方向键,但我们需要包含 RightLeft 检查来支持 IE/Edge 浏览器。如果按下了左方向键,则 leftPressed 变量将设置为 true,当释放左方向键时,leftPressed 变量将设置为 false。相同的模式适用于右方向键和 rightPressed 变量。

桨移动逻辑

我们现在已经设置了用于存储关于已按下键的信息的变量、事件监听器和相关函数。接下来,我们将进入代码,使用我们刚刚设置的所有东西,并在屏幕上移动桨。在 draw() 函数内,我们将在渲染每一帧时检查是否按下了左右方向键。我们的代码可能看起来像这样

js
if (rightPressed) {
  paddleX += 7;
} else if (leftPressed) {
  paddleX -= 7;
}

如果按下了左方向键,桨将向左移动 7 个像素,如果按下了右方向键,桨将向右移动 7 个像素。这目前有效,但是如果我们长时间按住任一方向键,桨会从画布边缘消失。我们可以通过更改代码来改进这一点,只在画布边界内移动桨,如下所示

js
if (rightPressed) {
  paddleX = Math.min(paddleX + 7, canvas.width - paddleWidth);
} else if (leftPressed) {
  paddleX = Math.max(paddleX - 7, 0);
}

我们使用的 paddleX 位置将在画布左侧的 0 和右侧的 canvas.width-paddleWidth 之间移动,这将完全按照我们的预期工作。

将上述代码块添加到 draw() 函数的底部,就在结束的大括号上方。

现在唯一剩下要做的就是从 draw() 函数中调用 drawPaddle() 函数,以便将它实际打印到屏幕上。将以下代码行添加到 draw() 函数中,就在调用 drawBall() 的代码行下方

js
drawPaddle();

比较您的代码

查看您的代码与下面的实时示例相比如何

注意:尝试让桨移动得更快或更慢,或者改变它的尺寸。

下一步

现在我们已经有了一些像游戏一样的东西。现在唯一的麻烦是你可以不断地用桨击打球,而没有实现获胜或失败。这将在第五章 游戏结束 中发生改变,我们将开始为我们的游戏添加游戏结束状态。