桌面鼠标和键盘控件
现在,当我们的移动端控件已就位,并且游戏可以在触摸屏设备上玩时,最好添加鼠标和键盘支持,以便游戏也可以在桌面上玩。这样我们就可以扩大支持的平台列表。我们将在下面进行介绍。
此外,如果您在桌面上开发独立于控件的游戏玩法等功能,那么进行测试会更容易,这样您就不必在每次更改源代码时都将文件推送到移动设备上。
注意: Captain Rogers: Battle at Andromeda 是使用 Phaser 构建的,控件管理也是基于 Phaser 的,但也可以用纯 JavaScript 完成。使用 Phaser 的好处是它提供了辅助变量和函数,使开发更轻松、更快,但选择哪种方法完全取决于您。
纯 JavaScript 方法
让我们先来考虑在游戏中实现纯 JavaScript 键盘/鼠标控件,看看它是如何工作的。首先,我们需要一个事件监听器来监听按下的按键。
document.addEventListener("keydown", keyDownHandler);
document.addEventListener("keyup", keyUpHandler);
每当按下任何按键时,我们就会执行 keyDownHandler 函数,当按键释放时,我们就会执行 keyUpHandler 函数,这样我们就知道何时按键不再按下。为此,我们将保存有关我们感兴趣的按键是否被按下的信息。
let rightPressed = false;
let leftPressed = false;
let upPressed = false;
let downPressed = false;
然后,我们将监听 keydown 和 keyup 事件,并在两个处理函数中进行相应操作。在其中,我们可以从事件对象的 code 属性中获取被按下按键的代码,查看是哪个按键,然后设置相应的变量。代码都是可读的字符串名称,但您可以 查找它们 以确保;"ArrowLeft" 是左箭头。
function keyDownHandler(event) {
if (event.code === "ArrowRight") {
rightPressed = true;
} else if (event.code === "ArrowLeft") {
leftPressed = true;
}
if (event.code === "ArrowDown") {
downPressed = true;
} else if (event.code === "ArrowUp") {
upPressed = true;
}
}
keyUpHandler 的写法几乎与上面的 keyDownHandler 完全相同,但不同的是,我们将按下变量设置为 true,而这里我们将它们设置为 false。如果按下左箭头(⬅︎;"ArrowLeft"),我们可以将 leftPressed 变量设置为 true,并在 draw 函数中执行分配给它的操作——将飞船向左移动。
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (rightPressed) {
playerX += 5;
} else if (leftPressed) {
playerX -= 5;
}
if (downPressed) {
playerY += 5;
} else if (upPressed) {
playerY -= 5;
}
ctx.drawImage(img, playerX, playerY);
requestAnimationFrame(draw);
}
draw 函数首先清除整个 Canvas——我们每一帧都从头开始绘制所有内容。然后检查按键变量,并调整 playerX 和 playerY 变量(我们在 leftPressed 和其他变量之后立即定义了它们)来保存飞船的位置,调整量为给定值,例如 5 像素。然后,玩家的飞船绘制在屏幕上,并在 requestAnimationFrame 中调用下一个绘制。

您可以在线查看此示例的运行情况:end3r.github.io/JavaScript-Game-Controls,完整的源代码可以在 github.com/end3r/JavaScript-Game-Controls 找到。
Phaser 方法
正如我之前提到的,您可以自己编写所有内容,但也可以利用 Phaser 等框架中的内置函数。这些将使您的生活更轻松,开发速度更快。所有边缘情况——浏览器实现之间的差异等——都由框架处理,因此您可以专注于您想要做的实际任务。
鼠标
游戏中的鼠标交互主要集中在点击按钮。在 Phaser 中,您创建的按钮可以接受任何类型的输入,无论是移动设备上的触摸还是桌面上的点击。这样,如果您已经按照《移动端触摸控件》一文中的说明实现了按钮,那么它在桌面上也可以开箱即用。
const buttonEnclave = this.add.button(
10,
10,
"logo-enclave",
this.clickEnclave,
this,
);
按钮将放置在屏幕左上角十像素处,使用 logo-enclave 图片,并在点击时执行 clickEnclave() 函数。我们可以直接为按钮分配操作。
this.buttonShoot = this.add.button(
this.world.width * 0.5,
0,
"button-alpha",
null,
this,
);
this.buttonShoot.onInputDown.add(this.shootingPressed, this);
this.buttonShoot.onInputUp.add(this.shootingReleased, this);
用于射击的按钮在移动和桌面方法下都能完美运行。
如果您想在屏幕上使用鼠标光标位置,可以使用 this.game.input.mousePointer。假设您想在鼠标点击屏幕右侧时射击子弹,可以这样做:
if (this.game.input.mousePointer.isDown) {
if (this.game.input.mousePointer.x > this.world.width * 0.5) {
// shoot
}
}
如果您想区分按下的鼠标按钮,有三个默认选项可供选择:
this.game.input.mousePointer.leftButton.isDown;
this.game.input.mousePointer.middleButton.isDown;
this.game.input.mousePointer.rightButton.isDown;
请记住,为了实现平台无关的输入,如果您想保留对移动端触摸交互的支持,最好使用 activePointer 而不是 mousePointer。
键盘
整个游戏都可以仅用键盘控制,而无需其他任何设备。内置的 this.game.input.keyboard 对象管理键盘输入,并具有 一些有用的方法,如 addKey() 和 isDown()。还有一个 Phaser.KeyCode 对象,其中包含所有可用的键盘按键。

在游戏的主菜单中,我们可以添加一种额外的开始游戏方式。可以点击“开始”按钮来实现这一点,但我们也可以使用 Enter 键来实现相同的功能。
const keyEnter = this.game.input.keyboard.addKey(Phaser.KeyCode.ENTER);
keyEnter.onDown.add(this.clickStart, this);
您可以使用 addKey() 来添加 Phaser.KeyCode 对象提供的任何按键。每当按下 Enter 键时,就会执行 onDown() 函数。它将调用 clickStart() 方法,该方法会启动一个新游戏。
提供一个选项让玩家在桌面上不使用鼠标玩游戏非常有用,这样他们就不必将手从键盘上移开。
控制游戏
通过在 create() 函数中使用 createCursorKeys() 函数,我们可以通过启用基本的方向键来支持使用 Phaser 构建的游戏中的键盘输入。
this.cursors = this.input.keyboard.createCursorKeys();
这会为我们创建四个方向箭头键。
this.cursors.left;
this.cursors.right;
this.cursors.up;
this.cursors.down;
您也可以自己定义按键,并提供一个替代的 W A S D 控件机制。例如:
this.keyLeft = this.input.keyboard.addKey(Phaser.KeyCode.A);
this.keyRight = this.input.keyboard.addKey(Phaser.KeyCode.D);
this.keyUp = this.input.keyboard.addKey(Phaser.KeyCode.W);
this.keyDown = this.input.keyboard.addKey(Phaser.KeyCode.S);
为了同时支持方向键和 W A S D 键,我们需要这样做:
if (this.cursors.left.isDown || this.keyLeft.isDown) {
// move left
} else if (this.cursors.right.isDown || this.keyRight.isDown) {
// move right
}
if (this.cursors.up.isDown || this.keyUp.isDown) {
// move up
} else if (this.cursors.down.isDown || this.keyDown.isDown) {
// move down
}
在 update() 函数中,我们现在可以使用两种移动按键选项之一来向任何方向移动玩家的飞船。
我们还可以提供射击控件的替代方案。对于方向键,自然的射击按钮会在键盘的另一侧,这样玩家就可以使用另一只手——例如 X 键。对于 W A S D 键,可以是空格键。
this.keyFire1 = this.input.keyboard.addKey(Phaser.KeyCode.X);
this.keyFire2 = this.input.keyboard.addKey(Phaser.KeyCode.SPACEBAR);
在 update() 函数中,我们可以轻松地检查每一帧是否按下了这两个按键中的任何一个。
if (this.keyFire1.isDown || this.keyFire2.isDown) {
// fire the weapon
}
如果按下,那么就该射击一些子弹了!
我们甚至可以定义一个秘密的作弊按钮。
this.keyCheat = this.input.keyboard.addKey(Phaser.KeyCode.C);
然后在 update() 函数中,每当按下 C 键时,我们就会这样做:
if (this.keyCheat.isDown) {
this.player.health = this.player.maxHealth;
}
我们可以将玩家的生命值设置为最大。请记住:这是秘密,所以不要告诉任何人!
如何玩
我们已经实现了控件,现在我们应该告知玩家他们的游戏控制选项。否则他们不会知道!在显示“如何玩”屏幕,其中展示了游戏中控制飞船的各种方法时,我们不必向所有人展示所有内容,而是可以检测游戏是在桌面还是移动设备上启动,然后仅显示适合该设备的控件。
if (this.game.device.desktop) {
moveText = "Arrow keys or WASD to move";
shootText = "X or Space to shoot";
} else {
moveText = "Tap and hold to move";
shootText = "Tap to shoot";
}
如果游戏在桌面上运行,将显示方向键和 W A S D 键的消息。否则,将显示移动端触摸控件的消息。

要跳过“如何玩”屏幕,我们可以监听任何按键按下并继续。
this.input.keyboard.onDownCallback = function () {
if (this.stateStatus === "intro") {
this.hideIntro();
}
};
这会隐藏介绍并开始实际游戏,而无需我们为这个目的设置新的按键控件。
暂停和游戏结束屏幕
为了使游戏完全可以用键盘玩,应该可以从暂停和游戏结束屏幕返回主菜单、继续游戏或重新开始游戏。这可以通过捕获按键代码并执行操作来完成,方法与之前完全相同。例如,通过指定 Phaser.KeyCode.Backspace 或 Phaser.KeyCode.Delete,您可以将一个操作绑定到按下 Delete/Backspace 键时触发。
总结
好的,我们已经处理了触摸、键盘和鼠标控件。现在让我们继续研究如何使用 Gamepad API 设置游戏以通过控制台游戏手柄进行控制。