虚拟摇杆(Joystick)的实现原理
三个组成对象
在移动端,用虚拟摇杆来控制物体的移动是一种体验非常棒的交互方式。这个笔记中,注重分享摇杆的实现原理,与语言和平台无关,后面会有一个用 JS 实现的在线演示 Demo。
摇杆通常由三个部分组成:摇杆按钮、摇杆滑块、滑块运动范围。
滑块运动范围决定了滑块最大偏移摇杆按钮的长度,也决定了第一次触摸事件的响应范围。
如下图所示,左边是没有事件输入时的样子,通常虚线框的响应范围是透明的,大小根据业务交互来定,而滑块在没有事件输入时是不显示的。右边是触发 Touch 事件后,滑块显示在手指滑动的位置与方向。
输出值的计算方式
从上图的右边可以看出,在摇杆的运动中,我们能得到两个值,一个是原点(第一次点击屏幕的坐标点,这里我们假设是摇杆按钮的中心点)与滑块中心点的距离。以这个距离为半径,摇杆按钮中心为圆心,画一个圆,能得到滑块在这个圆上的角度。
这个距离值可以反映到要控制的物体的运动速度,角度可以反映到我们要控制的物体的运动方向。
距离
距离的求出比较简单,计算两个点的坐标之间的距离即可,此时滑块运动范围是这个距离的最大值,我们可以根据这个最大值与距离的比例来决定我们的运动速度。以 JS 为例:1
2
3
4Math.sqrt(
(y2 - y1) * (y2 - y1) +
(x2 - x1) * (x2 - x1)
)
角度
根据三角函数可以得到 α 的角度,这个角度就是我们要输出的值,计算步骤:
- 求出 Delta Y,也就是绿色线条的长度,
deltaY = y2 - y1
- 求出 Delta X,也就是黄色线条的长度,
deltaX = x2 - x1
- 用反三角函数公式计算 α 的弧度 radian,以 JS 为例:
Math.atan(deltaY, deltaX)
- 再转角度
degree = radian * 180 / PI
这里得到的角度值是以 X 轴为零点,如果我们这里是以 12 点钟方向为零点,这里计算的角度还需要再加 90 度再模 360。具体可以根据业务的需要做修改。
摇杆的交互实现
摇杆按钮
大部分的按钮,只是一个静态的 UI,告诉用户这里有一个虚拟摇杆,不需要在交互中做出修改。如果原点是动态的,那摇杆按钮需要移动到原点坐标。
摇杆滑块
方向
滑块的方向总是等于我们手指相对原点(摇杆按钮中心点)运动的方向。所以可以用上面获取的角度值来修改滑块的旋转角度。
回弹
当抬起手指后,滑块需要回弹到摇杆按钮的中心点,这里的可以使用各个平台下的 tween 类库来实现缓动回弹。上面提到的角度旋转为了更好的感官体验,也可以使用 tween 类库来做。
事件的响应
虚拟摇杆的实现涉及到这三个事件,可能各个平台略有不同,下面简单的列出每个事件要处理的逻辑。
TouchBegin
- 获取第一个手指点击的位置
- 记录坐标点,定为原点
- 显示滑块
- 把滑块的坐标设置成原点坐标
- 如果移动摇杆按钮,记录摇杆按钮当前位置为中心点,将摇杆按钮移动到原点
TouchMove
- 获取新的手指位置
- 获取上一次手指位置
- 计算差值,得出新的滑块位置
- 计算新位置与原点的角度
- 计算新位置与原点的距离
- 设置滑块旋转角度
- 防止超出滑块的最大距离,修正新的滑块位置
- 将滑块移动到新的位置
- 保存当前手指位置
TouchEnd
- 回弹滑块
- 滑块回弹结束后消失
- 如果移动滑块按钮,将摇杆按钮重置回中心点
DEMO 演示(JS 实现)
获取输入值之后
根据具体业务,可以自行封装几个事件,用于值的输出。
计算运动速度
根据滑块离原点的距离与最大运动范围的比例,我们可以对速度进行线性的关联,也可以分段离散来实现速度状态机。
计算运动方向
根据速度,再结合方向角度,利用三角函数可以计算 x, y 的运动分量。用分量计算新的物体位置。
PS
后续会使用 Rx.js 来实现这个组件,并对其进行封装。