HarmonyOS-基于ArkUI(JS)实现虚拟摇杆组件
时间:2023-03-13 18:11:01
科技观察
了解更多开源信息,请访问:开源基础软件社区https://ost.51cto.com。前言虚拟摇杆是手游中最常见的,用来实现游戏中精灵的移动。本例利用jspai中的div和image组件实现虚拟摇杆组件,然后监听touch事件获取滑动方向和位置x,y。开发环境说明工具版本:OpenHarmonyDevEcoStudio3.0ReleaseSDK版本:3.0.0.993(APIVersion8Beta3)主要组件:组件名称yg-rocker显示效果属性属性名称类型默认值角色rocker-dataObject-配置摇杆的参数,参考如下rockerDatarockerData属性名类型默认值函数ou_widthNumber140摇杆外圆宽度ou_heightNumber140摇杆外圆高度in_widthNumber60摇杆内圆宽度in_heightNumber60摇杆内圆高度ou_imgImage-摇杆外圆图片in_imgImage-摇杆内圆图片组件事件属性名类型返回valueremarkplayFunction{x:Number,y:Number,angle:Number}x:摇杆滑动的x,y:摇杆滑动的y,angle:对应x方向的角度调用实现hmlSection:
js部分:importLogfrom'../../common/utils/log.js'constlog=newLog('index.jspage')exportdefault{data:{rockerData:{ou_width:140,ou_height:140,in_width:60,in_height:60,ou_img:'/common/图片/rocker_bg.png',in_img:'/common/images/rocker.png',},d_x:0,d_y:0,window:{w:720,h:332},angle:0},onInit(){},onShow(){让d=this.$refs.box.getBoundingClientRect();这个.window.w=d.width||720;this.window.h=d.height||332;},play(e){让opt=e。细节让{x,y,角度}=选择;this.angle=角度;这个.d_x=x;这个.d_y=y;}}实现过程1.先渲染虚拟摇杆的外圈和内圈,通过css调整:.yg-rocker{position:fixed;底部:40px;左:40px;}.yg-rocker{不透明度:.4;}.yg-rocker-bg.active-bg{box-shadow:0fp010px5pxrgba(0,170,255,.2);opacity:.6;}.yg-rocker.yg-rocker-item{position:absolute;}最后得到:2.给虚拟摇杆添加一个触摸事件
touchStart触摸开始事件:触摸开始时,记录当前手势按下的位置x,y获取摇杆内圆的位置,d=this.$refs.ygRockerItem.getBoundingClientRect()。记录当前内圈圆心在屏幕上的位置this.x,this.y。isTouch记录了当前的触摸,后面还需要定时器逻辑判断。setSide(t)方法传入一个x,y坐标来计算当前内圆的位置,下面会详细说明。ani(time)传入一个毫秒级的时间作为定时器刷新时间,下面会详细说明。touchStart(e){让t=e.touches[0];让d=this.$refs.ygRockerItem.getBoundingClientRect();this.x=d.left+d.width/2;this.y=d.top+d.height/2;this.isTouch=true;这个.setSide(t);这个.ani(10);}、触摸滑动事件和触摸结束事件。//触摸滑动事件也交给setSide方法处理touchMove(e){lett=e.touches[0];this.setSide(t);},//触摸结束后,摇杆内圈回到初始位置touchEnd(){this.isTouch=false;//回到中心位置this.top=0;this.left=0;},3.处理滑动位置。setSide(t)方法传入一个对象{x,y},表示当前手势触摸在屏幕上的位置。计算触摸手指当前位置到摇杆内圆初始圆心的半径为temp,如下图所示。通过勾股定理,我们得到temp=Math.sqrt(Math.pow(x,2)+Math.pow(y,2))。将手指的位置与当前摇杆的外圆半径进行比较。如果超出外圈,让内圈在外圈边缘滑动,防止内圈跟随手指超出外圈范围。最后通过三角函数得到内圆在屏幕上的左侧和顶部位置。speed记录滑动处理后的坐标速度。getAngle获取当前手指与内圈圆心在x轴方向的夹角。随后用于确定对象的方向。SetFlag记录内圆圆心所在的象限坐标原点。setSide(t){让x=this.x-t.globalX;让y=this.y-t.globalY;//获取当前位置到圆心的半径lettemp=Math.sqrt(Math.pow(x,2)+Math.pow(y,2));让r=this.rockerData.ou_width/2;让r2=temp<=r?r:温度;让top=Math.sin(y/r2)*(this.rockerData.ou_width/2);让left=Math.sin(x/r2)*(this.rockerData.ou_width/2);this.top=this.setFlag(top);this.left=this.setFlag(left);this.xx=-1*x*this.speed;this.yy=-1*y*this.speed;this.angle=this.getAngle({x:(-1*x),y});},setFlag(num){返回num>0?0-num:Math.abs(num);},4.获取角度获取当前手指与内圈圆心在x轴方向的夹角。用于确定物体的方向。因为css的旋转是用来判断物体的方向的,所以以x轴方向为起点,顺时针从0递增到360°。圆的周长是2Πr,也就是说2Π是圆的360°,一个Π是180°,用三角函数的反正切可以得到圆心对应的角.但因为是切线,所以取值只有0到90°或者-0到-90°。因此需要根据象限中的位置计算出内圆的圆心作为坐标原点,x轴为起始边的顺时针角度。getAngle(obj){让{x,y}=obj;//返回角度,而不是弧度letres=180*Math.atan(y/x)/Math.PI;如果(x>0&&y>0){res=90-Math.abs(res)}如果(x>0&&y<0){res=90+Math.abs(res)}如果(x<0&&y<0){res=180+(90-Math.abs(res))}if(x<0&&y>0){res=270+Math.abs(res)}返回res===res?res.toFixed(2):0;}5.处理ani的动画帧传入一个定时器的时间,也就是说这个时间段内动画刷新一次。因为我们在触摸的时候,如果触摸是向一个方向停止的,但是被操作的物体不应该停止。而是按照这个方向继续以现在的速度前进。所以需要使用定时器操作来刷新这个动画帧。ani(t){clearInterval(this.timer);this.timer=setInterval(()=>{if(!this.isTouch){clearInterval(this.timer)}else{this.d_x=this.d_x+this.xx;this.d_y=this.d_y+this.yy;this.$emit('play',{x:this.d_x,y:this.d_y,angle:this.angle})//下面的操作都是为了防止物体(坦克)离开屏幕框。如果(this.d_x<=0){this.d_x=0;}if(this.d_x>=680){this.d_x=680;}if(this.d_y<=0){this.d_y=0;}if(this.d_y>=292){this.d_y=292;}}},t)},最后的效果就出来了。6、最后画一个坦克来验证虚拟摇杆的数据。