移动触摸控制
移动游戏的未来绝对是 Web,许多开发人员在其游戏开发过程中选择移动优先方法——在现代世界中,这通常也包括实现触摸控制。在本教程中,我们将了解在 HTML 游戏中实现移动控制是多么容易,并在支持触摸的移动设备上享受游戏乐趣。
注意:游戏Captain Rogers: Battle at Andromeda是使用 Phaser 构建的,控制管理是基于 Phaser 的,但也可以用纯 JavaScript 完成。使用 Phaser 的好处是它提供了辅助变量和函数,可以简化和加快开发速度,但完全取决于您选择哪种方法。
纯 JavaScript 方法
我们可以自己实现触摸事件——设置事件监听器并为其分配相关函数将非常简单
const el = document.querySelector("canvas");
el.addEventListener("touchstart", handleStart);
el.addEventListener("touchmove", handleMove);
el.addEventListener("touchend", handleEnd);
el.addEventListener("touchcancel", handleCancel);
这样,在移动屏幕上触摸游戏的<canvas>
就会发出事件,因此我们可以以任何我们想要的方式操作游戏(例如,移动宇宙飞船)。事件如下
- touchstart 当用户将手指放在屏幕上时触发。
- touchmove 当他们在触摸屏幕时移动手指时触发
- touchend 当用户停止触摸屏幕时触发
- touchcancel 当触摸被取消时触发,例如当用户将手指移出屏幕时。
注意:触摸事件参考文章提供了更多示例和信息。
纯 JavaScript 演示
让我们在 GitHub 上提供的一个小演示中实现移动支持,以便我们通过在移动设备上触摸屏幕来移动玩家的飞船。
我们将使用两个事件:touchstart
和 touchmove
,这两个事件都由一个函数处理。为什么?函数 touchHandler
将为飞船的位置分配适当的变量,以便我们可以将其用于这两种情况:当玩家触摸屏幕但没有移动它(touchstart
)时,以及当手指在屏幕上移动时(touchmove
)
document.addEventListener("touchstart", touchHandler);
document.addEventListener("touchmove", touchHandler);
touchHandler
函数如下所示
function touchHandler(e) {
if (e.touches) {
playerX = e.touches[0].pageX - canvas.offsetLeft - playerWidth / 2;
playerY = e.touches[0].pageY - canvas.offsetTop - playerHeight / 2;
output.textContent = `Touch:\nx: ${playerX}, y: ${playerY}`;
e.preventDefault();
}
}
如果发生触摸(touches
对象不为空),那么我们将在该对象中获得所有我们需要的信息。我们可以获取第一个触摸(e.touches[0]
,我们的示例不支持多点触摸),提取 pageX
和 pageY
变量,并通过减去画布偏移量(画布与屏幕边缘之间的距离)和玩家宽度和高度的一半来设置玩家飞船在屏幕上的位置。
要查看它是否正常工作,我们可以使用 output
元素输出 x
和 y
位置。preventDefault()
函数需要防止浏览器移动——如果没有它,您将获得默认行为,并且画布将在页面上四处拖动,这将显示浏览器滚动条并显得杂乱无章。
Phaser 中的触摸事件
我们不必自己做这些;像 Phaser 这样的框架为我们提供了管理触摸事件的系统——请参阅管理触摸事件。
指针理论
一个指针表示触摸屏上的一个手指。Phaser 默认启动两个指针,因此两个手指可以同时执行操作。Captain Rogers 是一个简单的游戏——它可以通过两个手指控制,左手指移动飞船,右手指控制飞船的枪。没有多点触摸或手势——一切都由单个指针输入处理。
您可以使用 this.game.input.addPointer
向游戏添加更多指针,最多可以同时管理十个指针。最近使用的指针可在 this.game.input.activePointer
对象中获得——屏幕上最近激活的手指。
如果您需要访问特定指针,它们都可以在 this.game.input.pointer1
、this.game.input.pointer2
等中获得。它们是动态分配的,因此如果您在屏幕上放置三个手指,则 pointer1
、pointer2
和 pointer3
将处于活动状态。例如,移除第二个手指不会影响其他两个手指,将其放回原位将使用第一个可用属性,因此 pointer2
将再次被使用。
您可以通过 this.game.input.x
和 this.game.input.y
变量快速获取最近激活指针的坐标。
输入事件
除了直接使用指针之外,还可以监听 this.game.input
事件,例如 onDown
、onUp
、onTap
和 onHold
this.game.input.onDown.add(itemTouched, this);
function itemTouched(pointer) {
// Do something
}
当 onDown
事件通过触摸屏幕调度时,将执行 itemTouched()
函数。pointer
变量将包含有关激活该事件的指针的信息。
此方法使用普遍可用的 this.game.input
对象,但您也可以通过使用 onInputOver
、onInputOut
、onInputDown
、onInputUp
、onDragStart
或 onDragStop
检测任何游戏对象(如精灵或按钮)上的操作
this.button.events.onInputOver.add(itemTouched, this);
function itemTouched(button, pointer) {
// Do something
}
这样,您就可以将事件附加到游戏中的任何对象(例如玩家的飞船),并对用户执行的操作做出反应。
使用 Phaser 的另一个优点是,您创建的按钮将接收任何类型的输入,无论是移动设备上的触摸还是桌面上的点击——框架会在后台为您解决这个问题。
实施
添加一个交互式对象来监听用户输入的最简单方法是创建一个按钮
const buttonEnclave = this.add.button(
10,
10,
"logo-enclave",
this.clickEnclave,
this,
);
此按钮在 MainMenu
状态中形成——它将放置在屏幕左上角的十个像素处,使用 logo-enclave
图像,并在触摸时执行 clickEnclave()
函数。这将在移动设备和桌面上开箱即用。主菜单中有一些按钮,包括启动游戏的按钮。
对于实际的游戏玩法,与其创建更多按钮并用它们覆盖小的移动屏幕,我们可以使用一些不同的东西:我们将创建对给定操作做出响应的不可见区域。从设计的角度来看,最好扩大活动区域,而不用按钮图像覆盖屏幕的一半。例如,点击屏幕右侧将发射武器
this.buttonShoot = this.add.button(
this.world.width * 0.5,
0,
"button-alpha",
null,
this,
);
this.buttonShoot.onInputDown.add(this.goShootPressed, this);
this.buttonShoot.onInputUp.add(this.goShootReleased, this);
上面的代码将使用透明图像创建一个新的按钮,该图像覆盖屏幕的右侧一半。如果您想执行更复杂的操作,可以分别为输入按下和输入抬起分配函数,但在本游戏中,触摸屏幕右侧将向右发射子弹——在本例中,这正是我们需要的。
移动玩家可以通过创建四个方向按钮来管理,但我们可以利用触摸屏并四处拖动玩家的飞船
const player = this.game.add.sprite(30, 30, "ship");
player.inputEnabled = true;
player.input.enableDrag();
player.events.onDragStart.add(onDragStart, this);
player.events.onDragStop.add(onDragStop, this);
function onDragStart(sprite, pointer) {
// Do something when dragging
}
我们可以四处拖动飞船并同时执行某些操作,并在拖动停止时做出反应。如果启用,Phaser 中的拖动将开箱即用——您不必手动设置精灵的位置,因此您可以将 onDragStart()
函数留空,或放置一些调试输出以查看它是否正常工作。pointer
元素包含存储拖动元素当前位置的 x
和 y
变量。
专用插件
您可以使用专用插件以不同的方式处理触摸事件、渲染 UI 控件等等。以下是一些使用虚拟游戏手柄和操纵杆的插件示例
- phaser-plugin-virtual-gamepad (Phaser 2)
- 虚拟操纵杆 (Phaser 3)
对于像虚拟游戏手柄这样的基本插件,您可以下载脚本并使其在您的页面中可用
<script src="js/phaser.min.js"></script>
<!-- https://github.com/ShawnHymel/phaser-plugin-virtual-gamepad -->
<script src="js/phaser-plugin-virtual-gamepad.js"></script>
然后将它们包含在你的脚本中,并像以下代码片段一样使用它们。
// Add the VirtualGamepad plugin to a Phaser 2 game
this.gamepad = this.game.plugins.add(Phaser.Plugin.VirtualGamepad);
// Add a joystick to the game
this.joystick = this.gamepad.addJoystick(100, 420, 1.2, "gamepad");
// Add a button to the game
this.button = this.gamepad.addButton(400, 420, 1.0, "gamepad");
有关更多信息,请查看Phaser 插件的非官方目录,看看是否有适合你需求的插件。