触屏虚拟摇杆控制
概述
本教程分享触屏虚拟摇杆库,可以安装到任何需要触屏控制的项目中并进行定制。
如果此前未使用过 PlayCanvas 界面系统,建议先阅读相关文档,因为此库使用它渲染和定位控件。

安装方法
打开示例项目,右键点击 touch-joypad 文件夹,选择 Copy(复制)。

打开自己的项目,在资源面板中右键,选择 Paste(粘贴)。

添加摇杆
在刚粘贴的文件夹中打开 templates,可看到四种预配置的摇杆模板,覆盖最常见的使用场景。
- Left/Right Fixed Touch Joystick:锚定在屏幕左下角或右下角的固定摇杆,适合需要即时响应的快节奏游戏,例如复古平台跳跃游戏。
- Left/Right Half Touch Joystick:输入区域为左半屏或右半屏,摇杆先移动到触点,再通过拖动控制运动,适合在应用中推拉对象。
本例使用 Left Half Touch Joystick 模板。
创建二维屏幕实体,并将模板添加为其子级。

摇杆由三个实体组成:
- 输入区域,红色轮廓。
- 底座,蓝色轮廓。
- 摇杆帽,蓝色轮廓。

输入区域监听触摸事件和用于调试的鼠标事件,同时阻止事件传播。
因此,如果先与此区域交互,其下方的界面元素以及 pc.Mouse 和 pc.Touch 都不会收到相应事件。
输入区域本身是界面元素,可通过界面系统布局按需求设置位置、尺寸和锚点。
它还挂载 touchJoystick 脚本,包含摇杆的全部逻辑与属性。每个属性都有用途提示,下文将进一步说明。

底座和摇杆帽也是界面元素,由脚本控制。如果希望摇杆位于模板之外的位置,请移动并锚定底座实体,而非输入区域。
行为类型
摇杆支持触屏游戏与应用中常见的三种行为类型。

Fixed in place:底座固定在原位置,不移动。

Move to first touch and fixed:底座移动到用户首次触碰输入区域的位置,然后保持固定。

Move to first touch and drags:底座移动到首次触点,当用户拖动超过摇杆范围时随之移动。

该类型可以在运行时修改,因此可将其作为应用内设置供用户选择。
读取摇杆数值

红色圆圈为死区。如果摇杆帽位于其中,两个轴的返回值均为 0。蓝色圆圈为活动范围,摇杆帽不能超出该区域。
根据摇杆帽在死区和活动范围之间的位置,两个轴的数值始终归一化到 -1 至 1。
圆圈尺寸可以在编辑器中通过脚本属性设置。
在代码中,通过全局 JavaScript 对象 window.touchJoypad.sticks 和标识符访问摇杆值。默认标识符为 joystick0,可在编辑器的脚本属性中改为更明确的名称。
示例代码:
// Get the joystick by the identifier from the global object
var joystick = window.touchJoypad.sticks['joystick0'];
// Get the normalized values of both joystick axes and print to console
console.log('X: ' + joystick.x + ', Y: ' + joystick.y);
添加按钮
按钮是屏幕上固定位置的界面元素。templates 文件夹中提供按钮模板,应将其添加为屏幕实体的子级。

由于按钮是界面元素,可通过界面系统布局根据需求设置位置、尺寸和锚点。
与摇杆相同,按钮也有标识符,可通过全局 JavaScript 对象 window.touchJoypad.buttons 及以下 API 访问。
| 函数名称 | 说明 |
|---|---|
| isPressed | 接收按钮标识符;按钮当前正被按住时返回 true。 |
| wasPressed | 接收按钮标识符;按钮自上一帧以来被按下时返回 true。 |
| wasReleased | 接收按钮标识符;按钮自上一帧以来被松开时返回 true。 |
| wasTapped | 接收按钮标识符;按钮在 200 毫秒内按下并松开,即快速轻触时返回 true。 |
摇杆本身也是按钮,因此用法更灵活。例如,将摇杆标识符传给 wasTapped,可以实现类似 PlayStation 控制器 L3/R3 的输入。
示例代码:
// Get the button global object
var buttons = window.touchJoypad.buttons
// Check if the button was pressed since the last frame
console.log('Was pressed: ' + buttons.wasPressed('button0'));