一、效果图

二、编写步骤及原理

1.方法一:利用css三角形原理, 缺点:不能准确控制盒子大小 (建议使用 方法二)

代码如下(示例):

<template><view class="rocker"><view style="width: 390rpx;height: 390rpx;position: relative;"><view class="content_trangle"  v-if="dirtion === ''"></view><view class="content_trangle" style="border-top-color: #79F6BC;" v-if="dirtion === '上'"></view><view class="content_trangle" style="border-bottom-color: #79F6BC;" v-if="dirtion === '下'"></view><view class="content_trangle" style="border-left-color: #79F6BC;" v-if="dirtion === '左'" ></view><view class="content_trangle" style="border-right-color: #79F6BC;" v-if="dirtion === '右'"></view><view class="core"><view><image src="../../../static/img/image/rocker-left.png" mode=""></image></view><view><image src="../../../static/img/image/rocker-left.png" mode=""></image></view><view><image src="../../../static/img/image/rocker-left.png" mode=""></image></view><view><image src="../../../static/img/image/rocker-left.png" mode=""></image></view></view><view class="curise" @touchmove="move" @touchstart="start" @touchcancel="cancelAndEnd" @touchend="cancelAndEnd":style="{left:left+'rpx',top:top+'rpx'}"></view></view></view></view>
</template><script>export default {data() {return {left: 0,top: 0,startx: 0, //x坐标starty: 0, //y坐标dirtion: ''}},onLoad() {},methods: {//将方法暴露给父组件,并传值do(direct) {this.$emit('remote', direct);},// 移动时move(e) {// 向上移,Y轴的值减小,向下移,Y轴的值增大 | 向左移,X轴的值在减小,向右移X轴的值在增大// console.log('eX',e.touches[0].clientX,'eY',e.touches[0].clientY);const templeft = (e.touches[0].clientX - this.startx) * 1const temptop = (e.touches[0].clientY - this.starty) * 1if (Math.sqrt(Math.pow(templeft, 2) + Math.pow(temptop, 2)) >= 110) {let angle = Math.atan(Math.abs(templeft) / Math.abs(temptop))let rad = (180 * angle / Math.PI)let cx = 0let cy = 0let r = 140//第一象限(右上)if (this.startx < e.touches[0].clientX && this.starty > e.touches[0].clientY) {cx = Math.cos(angle) * -r;cy = Math.sin(angle) * r;}//第三象限(左下)if (this.startx > e.touches[0].clientX && this.starty < e.touches[0].clientY) {cx = Math.cos(angle) * r;cy = Math.sin(angle) * -r;}//第四象限(右下)if (this.startx < e.touches[0].clientX && this.starty < e.touches[0].clientY) {cx = Math.cos(angle) * r;cy = Math.sin(angle) * r;}//第二象限(左上)if (this.startx >= e.touches[0].clientX && this.starty >= e.touches[0].clientY) {cx = Math.cos(angle) * -r;cy = Math.sin(angle) * -r;}//上if (e.touches[0].clientY - this.starty < 0 && rad < 45) {// console.log("上")this.dirtion = '上'this.do('上');}//右if (e.touches[0].clientX - this.startx > 0 && rad >= 45) {// console.log("右")this.dirtion = '右'this.do('右');}//下if (e.touches[0].clientY - this.starty > 0 && rad < 45) {// console.log("下")this.dirtion = '下'this.do('下');}//左if (e.touches[0].clientX - this.startx < 0 && rad >= 45) {// console.log("左")this.dirtion = '左'this.do('左');}this.left = cy * 2this.top = cx * 2} else {this.left = templeft * 2this.top = temptop * 2}},// 开始时start(e) {this.startx = e.touches[0].clientXthis.starty = e.touches[0].clientY// console.log('X轴', this.startx, 'Y轴', this.starty);},// 意外取消时与完成时cancelAndEnd(e) {this.left = 0this.top = 0this.dirtion = ''this.$emit('remoteCancelAndEnd')}}}
</script><style lang="scss" scoped>.rocker{width: 450rpx;height: 450rpx;border-radius: 50%;background-color: #F4F4F4;display: flex;justify-content: center;align-items: center;}.content_trangle {width:  110rpx;height:  110rpx;border: 150rpx solid #000;// border-top-color: red;// border-bottom-color: yellow;// border-left-color: skyblue;// border-right-color: green;border-color: #fff;border-radius: 50%;margin-top: -10rpx;margin-left: -10rpx;}.curise {position: absolute;top: 0rpx;left: 0rpx;bottom: 0rpx;right: 0rpx;margin: auto;width: 105rpx;height: 105rpx;background-color: #5ABF78;// background-color: #fff;border-radius: 50%;}.core {width: 400rpx;height: 400rpx;position: absolute;top: 0;left: 0;display: flex;flex-wrap: wrap;transform: rotate(45deg);>view:nth-child(-n+4) {width: 200rpx;height: 200rpx;display: flex;justify-content: center;align-items: center;image {width: 30rpx;height: 50rpx;}}>view:nth-child(1)>image {transform: rotate(45deg);margin-right: 20rpx;}>view:nth-child(2)>image {transform: rotate(135deg);margin-right: 20rpx;}>view:nth-child(3)>image {transform: rotate(-45deg);margin-right: 20rpx;}>view:nth-child(4)>image {transform: rotate(-135deg);margin-right: 20rpx;}}
</style>

2.方法二:利用相对定位与绝对定位控制盒子,可拓展性强

代码如下(示例):

<template><view style="width: 100%;height: 800rpx;display: flex;justify-content: center;align-items: center;"><view class="container" :style="{width:containerWH+'rpx',height:containerWH+'rpx'}"><view class="core" :style="{width:controlWH+'rpx',height:controlWH+'rpx'}"><view class="core_fourview"><!-- <view><image src="../../static/img/image/nav-arrow-left.png" mode=""></image></view> --><view :style="dirtion === '上' ? viewActiveStyle:''"><image src="../../static/img/image/nav-arrow-left-fff.png" mode="" v-if="dirtion === '上'"></image><image src="../../static/img/image/nav-arrow-left.png" mode="" v-else></image></view><view :style="dirtion === '右' ? viewActiveStyle:''"><image src="../../static/img/image/nav-arrow-left-fff.png" mode="" v-if="dirtion === '右'"></image><image src="../../static/img/image/nav-arrow-left.png" mode="" v-else></image></view><view :style="dirtion === '左' ? viewActiveStyle:''"><image src="../../static/img/image/nav-arrow-left-fff.png" mode="" v-if="dirtion === '左'"></image><image src="../../static/img/image/nav-arrow-left.png" mode="" v-else></image></view><view :style="dirtion === '下' ? viewActiveStyle:''"><image src="../../static/img/image/nav-arrow-left-fff.png" mode="" v-if="dirtion === '下'"></image><image src="../../static/img/image/nav-arrow-left.png" mode="" v-else></image></view></view><!-- 控制的小球 --><view class="curise" @touchmove="move" @touchstart="start" @touchcancel="cancelAndEnd"@touchend="cancelAndEnd" :style="{left:left+'rpx',top:top+'rpx',width:circleWH+'rpx',height:circleWH+'rpx',backgroundColor:circleBgColor}"></view><!-- 白底小球 --><view class="curise_fff" :style="{width:colorcircleWH+'rpx',height:colorcircleWH+'rpx',backgroundColor:colorCircleStyle}"></view></view></view></view>
</template><script>export default {props:{// 主容器宽高,可以用来扩展阴影containerWH:{type:Number,default:450},// 整个控制容器的宽高controlWH:{type:Number,default:400},//判断小球移动多少大于值,开始计算方向与顶边comparenum: {type: Number,default: 100},//手指超出外圆的范围顶点是哪comparewidth: {type: Number,default: 140},// 可移动小球的宽高circleWH:{type:Number,default:100},//可移动小球的背景颜色circleBgColor:{type:String,default:'#5ABF78'},// 方向盒子确认方向后活动的样式viewActiveStyle:{type:String,default:`background-color:#79F6BC;`},// 小球移动后原先的小球占点,宽度与高度比移动小球小colorcircleWH:{type:Number,default:95},//小球移动后原先的小球占点背景颜色colorCircleStyle:{type:String,default:`#fff`},// 箭头图片宽高大小imgWH:{type:String,default:50},// 箭头图片margin-right值大小imgMarRight{type:Number,default:20}},data() {return {left: 0,top: 0,startx: 0, //x坐标starty: 0, //y坐标dirtion:'',}},onLoad() {},methods: {do(direct) {this.$emit('remote', direct);// this.dirtion = direct},// 移动时move(e) {// 向上移,Y轴的值减小,向下移,Y轴的值增大 | 向左移,X轴的值在减小,向右移X轴的值在增大// console.log('eX',e.touches[0].clientX,'eY',e.touches[0].clientY);const templeft = (e.touches[0].clientX - this.startx) * 1const temptop = (e.touches[0].clientY - this.starty) * 1if (Math.sqrt(Math.pow(templeft, 2) + Math.pow(temptop, 2)) >= this.comparenum) {let angle = Math.atan(Math.abs(templeft) / Math.abs(temptop))let rad = (180 * angle / Math.PI)let cx = 0let cy = 0let r = this.comparewidth//第一象限(右上)if (this.startx < e.touches[0].clientX && this.starty > e.touches[0].clientY) {cx = Math.cos(angle) * -r;cy = Math.sin(angle) * r;}//第三象限(左下)if (this.startx > e.touches[0].clientX && this.starty < e.touches[0].clientY) {cx = Math.cos(angle) * r;cy = Math.sin(angle) * -r;}//第四象限(右下)if (this.startx < e.touches[0].clientX && this.starty < e.touches[0].clientY) {cx = Math.cos(angle) * r;cy = Math.sin(angle) * r;}//第二象限(左上)if (this.startx >= e.touches[0].clientX && this.starty >= e.touches[0].clientY) {cx = Math.cos(angle) * -r;cy = Math.sin(angle) * -r;}//上if (e.touches[0].clientY - this.starty < 0 && rad < 45) {// console.log("上")this.dirtion = '上'this.do('上');}//右if (e.touches[0].clientX - this.startx > 0 && rad >= 45) {// console.log("右")this.dirtion = '右'this.do('右');}//下if (e.touches[0].clientY - this.starty > 0 && rad < 45) {// console.log("下")this.dirtion = '下'this.do('下');}//左if (e.touches[0].clientX - this.startx < 0 && rad >= 45) {// console.log("左")this.dirtion = '左'this.do('左');}this.left = cy*2this.top = cx*2} else {this.left = templeft*2this.top = temptop*2}},// 开始时start(e) {this.startx = e.touches[0].clientXthis.starty = e.touches[0].clientY// console.log('X轴', this.startx, 'Y轴', this.starty);},// 意外取消时与完成时cancelAndEnd(e) {this.left = 0this.top = 0this.dirtion = ''this.$emit('remoteCancelAndEnd')}}}
</script><style lang="scss" scoped>.container{// width: 450rpx;// height: 450rpx;border-radius: 50%;background-color: #F4F4F4;display: flex;justify-content: center;align-items: center;.core{width: 400rpx;height: 400rpx;border-radius: 50%;background-color: #FFF;overflow: hidden;position: relative;.core_fourview{width: 100%;height: 100%;display: flex;flex-wrap: wrap;transform: rotate(45deg);>view:nth-child(-n+4) {width: 200rpx;height: 200rpx;display: flex;justify-content: center;align-items: center;image{width: 50rpx;height: 50rpx;}}>view:nth-child(1)>image{transform: rotate(45deg);margin-right: 20rpx;}>view:nth-child(2)>image{transform: rotate(135deg);margin-right: 20rpx;}>view:nth-child(3)>image{transform: rotate(-45deg);margin-right: 20rpx;}>view:nth-child(4)>image{transform: rotate(-135deg);margin-right: 20rpx;}}}.curise {position: absolute;top: 0rpx;left: 0rpx;bottom: 0rpx;right: 0rpx;margin: auto;width: 100rpx;height: 100rpx;background-color: #808080;border-radius: 50%;z-index: 9;}.curise_fff{position: absolute;top: 0rpx;left: 0rpx;bottom: 0rpx;right: 0rpx;margin: auto;// width: 96rpx;// height: 96rpx;// background-color: #fff; border-radius: 50%;z-index: 8;}}</style>

3.使用组件 —import—

<remotesense @remote="thisremote" @remoteCancel="remoteClose" @remoteEnd="remoteClose"></remotesense>//引入注册组件
import remotesense from "组件文件名"export default {components: {remotesense},
data(){return{requestStatus: false, //摇杆防抖directtion: '', //方向,可加可不加timesset: null  //控制定时器有无}},methods:{// 遥控thisremote(e) {if (this.requestStatus) {// 利用 return 终止函数继续运行return false;}clearInterval(this.timesset)let timeCount = 0this.timesset = setInterval(() => {if (timeCount >= 2) {  //2是每1秒继续发送请求timeCount = 0this.thisremote(e)  //利用重复调用函数监测方向}timeCount += 1      //增长速度},500)// 执行逻辑console.log('发送请求','方向:',e);// 发送请求,1.5s发送一次请求this.requestStatus = truesetTimeout(() => {// 改变 requestStatusthis.requestStatus = false;}, 1000);  //1s捕抓一次方向},// 摇杆取消,手指离开,此方法由remotesense组件传递过来的remoteClose(){clearInterval(this.timesset)},}}

总结

提示:这里对文章进行总结:

送自己和大家一句话吧:乾坤未定,你我皆是黑马!!!加油

uni-app:游戏摇杆,遥控控制4方向 常用于移动端组件相关推荐

  1. 360°平滑游戏摇杆(触屏方向导航)

    Android游戏开发二十四]360°平滑游戏摇杆(触屏方向导航) 本站文章均为 李华明Himi 原创,转载务必在明显处注明:(作者新浪微博: @李华明Himi ) 转载自[黑米GameDev街区]原 ...

  2. Unity3D 游戏引擎之IOS自定义游戏摇杆与飞机平滑的移动(十一)

    Unity3D 游戏引擎之IOS自定义游戏摇杆与飞机平滑的移动 雨松MOMO原创文章如转载,请注明:转载至我的独立域名博客雨松MOMO程序研究院,原文地址:http://www.xuanyusong. ...

  3. vue插槽solt ,uni.app

    一.什么是插槽? 插槽就是子组件提供给父组件使用的一个占位符,用<slot></solt>表示父组件可以在这个占位符中填充任何模板代码. 二.插槽的用法 1.创建一个子组件,在 ...

  4. 手机游戏摇杆控制人物移动解决方案

    手机游戏摇杆控制人物移动解决方案 https://zhuanlan.zhihu.com/p/358614239 完成之后的演示 一.摇杆的UI搭建 Panel里主要是一个摇杆的背景(圆环)和摇杆头(红 ...

  5. STM32F103+NRF2401+游戏摇杆ADC双单片机通信遥控小车

    STM32F103+NRF2401+游戏摇杆ADC双单片机通信遥控小车 文章目录 STM32F103+NRF2401+游戏摇杆ADC双单片机通信遥控小车 前言 一.实现的功能? 二.主要代码及模块讲解 ...

  6. Unity UGUI通过摇杆joystick 控制角色移动 标准的第三人称视角手游-左侧控制移动,右侧控制视角和方向

    Unity UGUI通过摇杆joystick 控制角色移动 标准的第三人称视角手游-左侧控制移动,右侧控制视角和方向 效果图显示 附上demo下载地址 备注:资源是URP的,普通平台修改资源材质即可 ...

  7. android 游戏遥感,Android2.2+游戏摇杆 MOPS魅影T800评测

    为游戏而生:MOPS魅影T800 Android凭借着自身出色的设计以及丰富的第三方软件应用的支持,目前已经成为了最炙手可热的智能手机系统之一,很多朋友对Android感兴趣是因为其具有非常丰富的软件 ...

  8. 【Unity插件】游戏摇杆Joystick

    文章目录 前言 一.Joystick摇杆类型 二.摇杆基本属性 三.摇杆使用方法 四.其他功能及扩展 总结 前言 最近开发很多游戏Demo中都有用到游戏摇杆Joystick.个人还是挺喜欢用这个插件的 ...

  9. 自定义View之游戏摇杆键盘实现(二)

    前言 去年开发项目,需要实现一个遥感按钮,控制公司机器人行走,于是通过自定义SurfaceView实现了该功能,想了解的话,传送门在这自定义View之游戏摇杆键盘实现,但由于传输指令过程中对时间准确度 ...

最新文章

  1. spring boot 整合mybatis 无法输出sql的问题
  2. 2014年百度之星程序设计大赛 - 初赛(第二轮)Chess
  3. Django中提供的6种缓存方式
  4. 在Homebrew 发布程序
  5. 关于vue,angularjs1,react之间的对比
  6. keil MDK编译器警告和错误详解(不定期更新)
  7. APACHE OFBIZ XML-RPC 反序列化漏洞 (CVE-2020-9496) 的复现与分析
  8. 大数据分析系统包含哪些功能板块
  9. 10.RabbitMQ实战 --- 监控
  10. 读python学习手册
  11. python中文版-python有中文版吗
  12. Windows 7硬盘安装工具 NT6 HDD Installer v3.0(含图文教程)
  13. android时间轴折线图,echarts时间轴折线图
  14. 公众号原主体营业执照已注销 如何办理账号迁移和公证书?
  15. 五险一金真的那么重要吗?为什么很多人宁愿做小时工不要五险一金?
  16. 墨者学院—Webmin未经身份验证的远程代码执行(简单复习)
  17. 机智云受邀加入中国智能家居产业联盟智慧酒店小组
  18. HYBBS2.3轻论坛M-TOUCH模板源码
  19. JavaScript如何截取字符串的最后一位
  20. Spring Integration

热门文章

  1. android系统便签 备份,写在安卓系统手机里便笺(记事本)里的内容有什么方法能传到电脑上吗?...
  2. 大数据时代隐藏新商机 客厅激战开启平台之争
  3. linux java 查询cpu核数,linux java 查询cpu核数
  4. es 修改ik和同义词插件源码连接mysql实现字典值同义词热更新
  5. GoLang版的RPC简介
  6. Windows与Linux虚拟机间的简单文件互传
  7. elisp 漫画教程
  8. Python爬取煎蛋网的妹子图
  9. 使用python进行字频统计和词频统计
  10. 快速选择算法(Quick Select Algorithm)