前言
最早实现这个效果,是2011年用Objective-C在iOS里实现的。原仓库地址:code.google.com/archive/p/c…
在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);
}
羞涩的杆体
杆体是这里面最麻烦的一块,需要通过摇杆的拖拽的距离变化长度
,同时根据摇杆的位置旋转角度。
<view class='stick' :class="{animation:inDraging===false&&transition}" :style="{height: stickHeight+'px',transform:'translateX(-50%)'}">
<view :style="{transform:'rotate('+(angle/(3.14159/180)-90)+'deg)'}" style="transform-origin: 50% 0%;width: 100%;height: 100%;">
<slot name="stick">
</slot>
</view>
</view>
这里我用了两层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基本就完成了,接下来我们要输出一些数值,毕竟摇杆不能光自己摇
,得用来控制其他的元素进行运动。
摇杆数值
- 方向
- 力度
power = 当前半径/最大半径;
gif有点掉帧,大家能看出来运动的快慢吗?
组件化
现在把上面的成果封装成一个vue组件,方便复用。
<ezjoystick
:touchRadius="100"
:ballMoveRadius="50"
:transition="true"
@onJoyStickUpdate="onBeetleJoystickUpdate"
>
<view slot="ball">
</view>
<view slot="stick">
</view>
<view slot="bottom">
</view>
</ezjoystick>
- 三个属性
- touchRadius 触摸检测的实际半径
- ballMoveRadius 杆头的最大移动范围半径
- transition 是否开启缓动回位
- 三个slot
- ball 杆头
- stick 杆体
- bottom 底
- 两个事件
- onJoystickUpdate 有数值变化就会触发
- onJoystickCancel 停止触摸时触发
实现经典UI
- 街机摇杆
- 十字键
模拟十字键,核心是把角度转成4个方向,这里我随手写了一下,应该有更优雅的实现。
onCrossJoyStickUpdate(obj){
this.crossupPressed=false;
this.crossrightPressed=false;
this.crossdownPressed=false;
this.crossleftPressed=false;
if(obj.angle>-2.35&&obj.angle<-0.75){
this.crossupPressed=true;
}else if(obj.angle>-0.75&&obj.angle<0.75){
this.crossrightPressed=true;
}else if(obj.angle>0.75&&obj.angle<2.35){
this.crossdownPressed=true;
}else{
this.crossleftPressed=true;
}
}
- 王者荣耀的摇杆
在外层关联旋转一个箭头而已...
源码仓库
github.com/ezshine/ezj…
clone源码后使用HBuilerX打开可以快速看到实例,或将components复制到vuecli项目中导入使用
后话,怎么实现搓招
什么是搓招?就是在一定时间内按顺序完成几个方向+按键即可触发招式。比如此图里不知火舞的这招需要我们按顺序完成 ←↙↓↘→
+轻
或重
脚。
看到此刻的你想到如何实现了吗?
期待看到你们的文章
写完请AT我来帮你点赞哟
如果没有人写这个话题的话,那我再来专门写一篇搓招
的实现吧
关注大帅搞全栈
近期文章(感谢掘友的鼓励与支持???)
- ?做了一夜动画,就为让大家更好的理解Vue3的Composition Api 854赞
- ?2020更新,Vue仿探探拖拽卡片的效果 866赞
- ?2020,疫情重创了我的第三次创业 | 掘金年度征文 136赞
- ?如何用JS做一个老虎机抽奖,由服务端控制得奖几率 48赞
欢迎拍砖,一起探讨更优雅的实现
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!