前言
最早实现这个效果,是2011年用Objective-C在iOS里实现的。原仓库地址:https://code.google.com/archive/p/ccjoystick/downloads
在Vue里实现这个东西没啥用处,毕竟Vue也不是一个游戏框架,但是谁叫Vue这个话题的热度最高呢,写文章还是希望被更多人看到嘛...
印象里我在不同时期曾经用三种语言分别实现过这个案例。所以无论用什么框架、语言,只要你了解背后的原理,都很容易实现。
三层UI
全部UI分为三层
- 第一层是杆头,尺寸不会变化,拖拽的视觉效果区。
- 第二层是杆体,高度可拉伸,用于拟物流模仿真实感。
- 第三层是底,只是放在画面中,为了让视觉感受更完整。
当然没有第二层和第三层是不影响摇杆功能的,但谁叫我是一个拟物流的前端偏执狂呢?
把这三个层通过绝对定位+z-index叠起来,通过设置touch事件让杆头可以拖动。为了让大家看得清楚层级,我们先把杆头变透明。
圆形的拖拽区
摇杆嘛,圆形的洞里有根杆(不要污呀),所以我们必须把拖拽限制在一个圆形区域里
onTouchMove(e){ var curTouch=e.touches[0]; var tleft=curTouch.clientX-startLeft; var ttop=curTouch.clientY-startTop; //获取点击位置和起点的直线距离,也就是半径 var distance = getDistance(tleft,ttop,0,0); //如果这个距离是否大于圆形可移动区域的半径,则强行变更 if(distance>=this.ballMoveRadius)distance = this.ballMoveRadius; //最后通过夹角,正弦,余弦,半径还原x,y坐标 var angle = Math.atan2((ttop-0), (tleft-0)); this.left=Math.cos(angle)*distance; this.top=Math.sin(angle)*distance;}
代码中比较核心的部分是:我们先通过所在点和原点位置求出半径distance,以及之间的夹角角度angle。然后通过限定半径和夹角角度还原出x,y的坐标。就可以达到控制拖动在圆形区域内的效果了。
//获取两点间直线距离的算法var getDistance=function(x1, y1, x2, y2) { var _x = Math.abs(x1 - x2); var _y = Math.abs(y1 - y2); return Math.sqrt(_x * _x + _y * _y);}
羞涩的杆体
杆体是这里面最麻烦的一块,需要通过摇杆的拖拽的距离变化长度,同时根据摇杆的位置旋转角度。
这里我用了两层dom来完成这个杆体,一层用height进行高度变化,一层用transfrom设置旋转角度和旋转中心点。大家有更好的实现方法吗,在评论区告诉我吧。
夹角转为旋转角度算法angle/(3.14159/180),减去90是为了让度数起点在12点钟的位置。
onTouchMove(e){ var curTouch=e.touches[0]; var tleft=curTouch.clientX-startLeft; var ttop=curTouch.clientY-startTop; var distance = getDistance(tleft,ttop,0,0); if(distance>=this.ballMoveRadius)distance = this.ballMoveRadius; var angle = Math.atan2((ttop-0), (tleft-0)); this.left=Math.cos(angle)*distance; this.top=Math.sin(angle)*distance; //同步杆体的高度,旋转角度 this.stickHeight = distance; this.angle = angle;}
现在摇杆UE基本就完成了,接下来我们要输出一些数值,毕竟摇杆不能光自己摇,得用来控制其他的元素进行运动。
摇杆数值方向我们在杆体运动的时候,已经写完了,就是那个角度angle。
power = 当前半径/最大半径;
摇杆力度这件事在拳皇里是不存在的,但是在很多游戏中分轻推和重推(其实就是摇杆当前距离和最大距离的比),比如轻推是走,重推是跑。
gif有点掉帧,大家能看出来运动的快慢吗?
组件化
现在把上面的成果封装成一个vue组件,方便复用。
- 三个属性
- touchRadius 触摸检测的实际半径
- ballMoveRadius 杆头的最大移动范围半径
- transition 是否开启缓动回位
三个slot三个slot都是非必须的,不填的话,该部分就是空dom。具体可参考源码。
ball 杆头
stick 杆体
bottom 底两个事件
onJoystickUpdate 有数值变化就会触发
onJoystickCancel 停止触摸时触发
实现经典UI组件封装好了,接下来用咱们这个组件实现几个经典的界面吧
模拟十字键,核心是把角度转成4个方向,这里我随手写了一下,应该有更优雅的实现。
onCrossJoyStickUpdate(obj){ this.crossupPressed&#61;false; this.crossrightPressed&#61;false; this.crossdownPressed&#61;false; this.crossleftPressed&#61;false; if(obj.angle>-2.35&&obj.angle-0.75&&obj.angle<0.75){ this.crossrightPressed&#61;true; }else if(obj.angle>0.75&&obj.angle<2.35){ this.crossdownPressed&#61;true; }else{ this.crossleftPressed&#61;true; }}
在外层关联旋转一个箭头而已...
源码仓库
https://github.com/ezshine/ezjoystick
clone源码后使用HBuilerX打开可以快速看到实例&#xff0c;或将components复制到vuecli项目中导入使用
后话&#xff0c;怎么实现搓招
什么是搓招&#xff1f;就是在一定时间内按顺序完成几个方向&#43;按键即可触发招式。比如此图里不知火舞的这招需要我们按顺序完成 ←↙↓↘→&#43;轻或重脚。
今日话题&#xff1a;说一说&#xff0c;你做过最自豪的一件事。
你的点赞与关注是小编坚持的动力。