关键词:
作者:杨尚晓
前言
虚拟摇杆在移动端游戏中是最常见看的,用来实现游戏中的精灵移动。本案例中使用jspai中的div和image组件来实现的虚拟摇杆组件,然后监听touch事件获取滑动的方向和位置x,y。
开发环境说明
- 工具版本:OpenHarmony DevEco Studio 3.0 Release
- SDK版本:3.0.0.993(API Version 8 Beta3)
- 组要组件:组件名称yg-rocker
展示效果
属性
属性名 | 类型 | 默认值 | 作用 |
---|---|---|---|
rocker-data | Object | - | 配置摇杆的参数,参考下面rockerData |
rockerData
属性名 | 类型 | 默认值 | 作用 |
---|---|---|---|
ou_width | Number | 140 | 摇杆外圆宽度 |
ou_height | Number | 140 | 摇杆外圆高度 |
in_width | Number | 60 | 摇杆内圆宽度 |
in_height | Number | 60 | 摇杆内圆高度 |
ou_img | Image | - | 摇杆外圆图片 |
in_img | Image | - | 摇杆内圆图片 |
组件事件
属性名 | 类型 | 返回值 | 备注 |
---|---|---|---|
play | Function | x:Number, y:Number, angle:Number | x: 摇杆滑动的x, y: 摇杆滑动的y, angle: 对应x方向的角度 |
调用实现
hml部分
<element name="yg-rocker" src="../../common/component/ygRocker.hml"></element>
<div class="container" ref="box">
<yg-rocker
rocker-data="rockerData"
@play="play"
></yg-rocker>
</div>
js部分
import Log from ../../common/utils/log.js
const log = new Log(index.js页面)
export default
data:
rockerData:
ou_width: 140,
ou_height: 140,
in_width: 60,
in_height: 60,
ou_img: /common/images/rocker_bg.png,
in_img: /common/images/rocker.png,
,
d_x: 0,
d_y: 0,
window:
w: 720,
h: 332
,
angle: 0
,
onInit()
,
onShow()
let d = this.$refs.box.getBoundingClientRect();
this.window.w = d.width || 720;
this.window.h = d.height || 332;
,
play(e)
let opt = e.detail
let x, y, angle = opt;
this.angle = angle;
this.d_x = x;
this.d_y = y;
实现过程
1. 首先渲染虚拟摇杆的外圆和内圆
通过css调整
.yg-rocker
position: fixed;
bottom: 40px;
left: 40px;
.yg-rocker div image
opacity: .4;
.yg-rocker-bg .active-bg
box-shadow: 0fp 0 10px 5px rgba(0,170,255,.2);
opacity: .6;
.yg-rocker .yg-rocker-item
position: absolute;
最后得到
2. 给虚拟摇杆添加touch事件
<div
class="yg-rocker-bg"
ref="ygRockerBg"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
>
touchStart触摸开始事件
- 在开始触摸时,记录当前手势按压的位置x,y。
- 获取摇杆内圆的位置,
d = this.$refs.ygRockerItem.getBoundingClientRect()
。 - 记录当前内圆的圆心在屏幕的位置 this.x, this.y
- isTouch记录当前在触摸,后面需要做定时器逻辑判断。
- setSide(t)方法传入一个x,y坐标,计算当前内圆的位置,下面详细讲解。
- ani(time)传入一个毫秒级的时间,作为定时器刷新时间,下面详细讲解。
touchStart(e)
let t = e.touches[0];
let d = this.$refs.ygRockerItem.getBoundingClientRect();
this.x = d.left + d.width / 2;
this.y = d.top + d.height / 2;
this.isTouch = true;
this.setSide(t);
this.ani(10);
,
触摸滑动事件和触摸结束事件
// 触摸滑动事件也交给setSide方法处理
touchMove(e)
let t = 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));
-
让手指所在的位置和当前摇杆外圆的半径对比,如果超出外圆,就让内圆在外圆的边上滑动,不让内圆跟着手指超出外圆范围。
-
最后通过三角函数求得内圆在屏幕上的位置left,top。
-
speed记录滑动处理后的坐标速度。
-
getAngle获取当前手指和内圆圆心所在x轴方向的角度。后续用来判断物体的方向。
-
setFlag记录坐标所在的以内圆圆心位坐标原点的象限。
setSide(t)
let x = this.x - t.globalX;
let y = this.y - t.globalY;
// 获取到当前位置到圆心半径
let temp = Math.sqrt(Math.pow(x,2) + Math.pow(y,2));
let r = this.rockerData.ou_width / 2;
let r2 = temp <= r ? r : temp;
let top = Math.sin(y/r2) * (this.rockerData.ou_width / 2);
let 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)
return num > 0 ? 0 - num : Math.abs(num);
,
4. 获取角度
获取当前手指和内圆圆心所在x轴方向的角度。用来判断物体的方向。 因为通过css的rotate来判断实现物体方向,所以以x轴方向为起点,顺时针为递增从0到360° 圆的周长为2Πr,也就是说2Π为圆的360°,一个Π就是180°,使用三角函数的反正切可求得当前位置对应圆心的角度。 但是因为是正切,所以取值只有0到90°或者是-0到-90°。 所以需要根据在象限的位置来计算内圆圆心为坐标原点,x轴为起边的顺时针角度。
getAngle(obj)
let x, y = obj;
//返回角度,不是弧度
let res = 180 * Math.atan(y / x) / Math.PI;
if(x > 0 && y > 0)
res = 90 - Math.abs(res)
if(x > 0 && y < 0)
res = 90 + Math.abs(res)
if(x < 0 && y < 0)
res = 180 + (90-Math.abs(res))
if(x < 0 && y > 0)
res = 270 + Math.abs(res)
return 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)
// 下面的操作都是为了防止物体(坦克)离开屏幕画面。
if(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. 最后,画一个坦克来验证虚拟摇杆的数据。
<div class="tank" style="transform: rotate(angledeg); top: d_ypx; left: d_xpx;">
<div class="l1"></div>
<div class="l2"></div>
<div class="c"></div>
<div class="g"></div>
<div class="r"></div>
</div>
最后我们再次看一下效果
代码地址
https://gitee.com/yango520/yg-rocker
总结
整体的实现就是这样,逻辑也比较简单,当然也有些bug,比如滑动的速度没有限制超出摇杆外圆的时候而限制。坦克用div画的,如果需要做更复杂的操作,需要使用canvas来作为画布场景。
更多原创内容请关注:中软国际 HarmonyOS 技术团队
入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。
https://ost.51cto.com/#bkwz
#打卡不停更#harmonyos-基于arkui(ets)实现心电图组件(代码片段)
作者:杨尚晓前言随着大家生活水平的提升,越来越多的人注重自身身心健康,养生成了目前比较热门的活动。心电图是检测心脏活动状态的直观表现,可以通过心电图来观察人提的健康状况。响应鸿蒙万物互联的口号,肯定少... 查看详情
#打卡不停更#openharmony-arkui(ts)声明式开发之列表拖动排列(代码片段)
...基于TS扩展的声明式开发范式,因为OpenHarmony的API相对于HarmonyOS的API,功能上比较完善和成熟的,有些新的技术也早早接触到,所以本项目直接使用OpenHarmonySDK开发。工具版本:DevEcoStudio3.0ReleaseSDK版本: 查看详情
基于openharmony/harmonyos操作系统的arkui框架——harmony原生开发
一.基于OpenHarmony/HarmonyOS操作系统的ArkUI框架——Harmony原生开发开发需要的IDE:1.1什么是ArkUI框架?ArkUI是一套构建分布式应用界面的声明式UI开发框架。它使用极简的UI信息语法、丰富的UI组件、以及实时界面预览工具,帮助您提... 查看详情
harmonyos-基于arkui(js)实现图片旋转验证(代码片段)
...习其他人的slider滑块组件衍生出的小组件,本文主要结合HarmonyOS官网上的相关组件以及通用API,来实现一个图片的旋转验证--需拖动滑块将图片旋转还原为正确,方可验证通过。效果演示实现原理触发条件基于HarmonyOS通用事件touc... 查看详情
harmonyos-基于arkui(js)实现彩带飘动特效(代码片段)
...购物是经常看到一个彩带飘动的特效,又恰逢最近在学习HarmonyOS开发的知识,便想着自己能否用HarmonyOS相关的知识也做一个类似的东西,于是就自己动手尝试了一下。效果展示实现原理彩带飘动特效,主要是使用canvas来实现的,... 查看详情
harmonyos-基于arkui(ets)实现猫头鹰动画(代码片段)
作者:范颖前言因为工作原因,后面我可能会接触到基于TS扩展的声明是开发范式,因此我需要提前学习关于ets的内容。在学习了一段时间之后,我决定用ets来画一只猫头鹰,看看ets跟我之前掌握的知识有何不同,在什么地方需... 查看详情
#夏日挑战赛#harmonyos-基于arkui(js)实现打地鼠游戏(代码片段)
...:尹宝荣本文正在参加星光计划3.0–夏日挑战赛前言初学HarmonyOSArkUI(JS),对于FA的开发还是不太熟悉,单纯看文档,不使用起来的话,始终掌握不了,代码还是要多敲多思考才能进步。所以周末突发奇想利用HarmonyOS写了一个简单的... 查看详情
harmonyos-基于arkui(js)实现信件弹出效果(代码片段)
作者:罗晓纯前言自从大家使用QQ、微信、邮件等网络平台交流以后,大家对纸这种介质和书信这种通讯方式可能都比较陌生了。可别觉得书信是一个过时的东西,它可是80后的情怀,90后的回忆,00后的新宠,是经典的代名词。... 查看详情
harmonyos-基于arkui(js)实现黑白翻棋小游戏(代码片段)
作者:苏亚雯前言本人经过一段HarmonyOS的学习,运用所学的知识,制作了一个黑白翻棋的游戏,来检验自己的学习成果。本文详细讲述了黑白翻棋的编写思路,内含详细解释,有兴趣的小伙伴可以自己动手来制作一个属于自己的... 查看详情
#打卡不停更#ffh浅析ability框架中stage模型与fa模型的差异(代码片段)
...能力的抽象,也是应用程序的基本组成单元。OpenHarmony与HarmonyOS的应用程序APP由一个或多个Hap包组成,每个Hap可以包含一个或多个Ability。Ability框架模型具有两种形态,FA模型以及Stage模型:FA模型:OpenHarmonyAPI8 查看详情
基于stm32的串口收发讲解(hal库)#打卡不停更#(代码片段)
(基于STM32的串口收发程序(HAL库))介绍串口(UART通用异步收发器,TTL)通讯是一种设备间的串行全双工通讯方式。由于UART是异步传输,没有传输同步时钟,为了保证数据的正确性,UART采用16倍数据波特率的时钟进行采样。因为... 查看详情
openharmony/harmonyos的arkui的类web范式开发详解(代码片段)
一.OpenHarmony/HarmonyOS的ArkUI的类Web范式开发1.1类Web范式~三件套开发基于JS扩展的类****Web开发范****式的方舟开发框架包括应用层(Application)、前端框架层(Framework)、引擎层(Engine)、平台适配层(PortingLayer)JSUI框架采用类HTML和... 查看详情
arkui新能力,助力应用开发更便捷
...xff0c;并能在多种设备上实现生动而流畅的用户体验。随着HarmonyOS3.1版本的发布,ArkUI也新增许多能力,助力应用开发更便携。ArkUI框架新增能力概览ArkUI 查看详情
openharmony-基于arkui(ts)开发颜色选择器(代码片段)
...基于TS扩展的声明式开发范式,因为OpenHarmony的API相对于HarmonyOS的API,功能上比较完善和成熟的,有些新的技术也早早接触到,所以本项目直接使用OpenHarmonySDK开发。工具版本:DevEcoStudio3.0Beta4SDK版本:3. 查看详情
#打卡不停更#ffhopenharmony学生挑战赛分享-少儿语言教育app(代码片段)
Openharmony学生挑战赛经验分享前言本次参赛的项目是基于openHarmony开发的北向应用-少儿语言文化教育APP。从项目成立到初版成型再到参加比赛,这一路上遇到了不少困难,我也从团队协作、产品迭代、技术等方面学到了很多宝贵... 查看详情
#打卡不停更#智能喂食器(代码片段)
一、介绍随着人们生活方式的不断改变,宠物猫在许多家庭中占有重要的地位,其凭借独立的个性和易于打理的饲养方式,成为当下上班族喜欢的宠物之一,人们更是把宠物猫和狗作为家庭的重要成员。有铲屎官表示,每月在... 查看详情
#打卡不停更#-openharmony/docs开发入门(代码片段)
作者:朱子道杨成前言不管是作为软件开发的爱好者还是已经从事软件开发这个行业的从业者,对于接触一种全新的系统OpenHarmony。学习OpenHarmony,需要清楚OpenHarmony这个系统是什么,能干什么,今日分享从设备开发和应用开发两... 查看详情
#打卡不停更#三方库移植之napi开发[2]c/c++与js的数据类型转换(代码片段)
在《三方库移植之NAPI开发[1]—HelloOpenHarmonyNAPI》通过一个HelloOpenHarmonyNAPI样例讲述了NPAI接口开发基础知识。本文在其基础上修改hellonapi.cpp文件,介绍JS类型和C/C++数据类型之间的转换。开发基于最新的OpenHarmony3.2Beta3版本及其对应... 查看详情