虚拟摇杆实现

摇杆布局实现

摇杆功能实现

用摇杆控制主角


该功能已收录在Many Widgets插件中,使用Cocos Creator 3.x版本的小伙伴可以用该插件快速生成摇杆。

插件地址:https://store.cocos.com/app/detail/3147

2D摇杆演示地址:https://www.bilibili.com/video/BV1LP4y1W73z/

3D摇杆演示地址:https://www.bilibili.com/video/BV1w64y1Y7Xm/

在本教程中我们实现一个控制主角转向并移动的虚拟摇杆。

运行效果如下:

Cocos Creator版本:2.2.0

公众号后台回复"虚拟摇杆",获取该教程完整代码下载地址:

摇杆布局实现

项目文件的初始内容截图如下:

新建一个名为joystick的场景,textures文件夹中有两张图片分为作为摇杆背景和摇杆按钮,JoyStick.js中存放摇杆功能代码。

首先我们把joystick_panel图片拖到层级管理器中作为Canvas的子节点:

然后再将joystick_btn图片拖到层级管理器中,让它作为joystick_panel的子节点(这样按钮就会自动位于背景的正中央):

接着在属性检查器中设置joystick_btn宽高为60:

现在场景编辑器显示如下:

通常摇杆位于屏幕左下方,所以我们给joystick_panel节点添加一个Widget组件来固定其位置:

我们设置该节点离屏幕左边和底部的距离值都为5%:

游戏运行截图如下:

我们看到左下角的FPS信息遮挡了一些,我们在JoyStick.js中用这行代码可以把它去掉:

onLoad () {// hide FPS infocc.debug.setDisplayStats(false);
},

将JoyStick.js挂到joystick_panel节点上后再次运行游戏:

发现已经没有FPS信息了。

摇杆功能实现

这里肯定要用到触摸事件,我们先把这部分相关代码编写完整:

onLoad () {// hide FPS infocc.debug.setDisplayStats(false);// get joyStickBtnthis.joyStickBtn = this.node.children[0]; // touch eventthis.node.on('touchstart', this.onTouchStart, this);this.node.on('touchmove', this.onTouchMove, this);this.node.on('touchend', this.onTouchEnd, this);this.node.on('touchcancel', this.onTouchCancel, this);
},onDestroy() {// touch eventthis.node.off('touchstart', this.onTouchStart, this);this.node.off('touchmove', this.onTouchMove, this);this.node.off('touchend', this.onTouchEnd, this);this.node.off('touchcancel', this.onTouchCancel, this);
},

在onLoad方法中我们也获取了joystick_btn这个节点并存储在joyStickBtn变量中。

下面分别是onTouchStart,onTouchMove,onTouchEnd和onTouchCancel方法实现:

onTouchStart(event) {// when touch starts, set joyStickBtn's position let pos = this.node.convertToNodeSpaceAR(event.getLocation());this.joyStickBtn.setPosition(pos);
},onTouchMove(event) {// constantly change joyStickBtn's positionlet posDelta = event.getDelta();this.joyStickBtn.setPosition(this.joyStickBtn.position.add(posDelta));
},onTouchEnd(event) {// resetthis.joyStickBtn.setPosition(cc.v2(0, 0));
},onTouchCancel(event) {// resetthis.joyStickBtn.setPosition(cc.v2(0, 0));
},
  • 在onTouchStart中我们通过event.getLocation()获取触摸坐标,由于这里获取到的是世界坐标,我们需要通过convertToNodeSpaceAR方法将其转换成joystick_panel节点上的坐标。转换好后,将其设置成摇杆按钮的坐标。
  • 在onTouchMove中,我们通过event.getDelta()获取手指位移距离(向量),然后加上当前摇杆按钮的坐标就得到了按钮在移动之后的坐标。
  • 在onTouchEnd和onTouchCancel中,我们还原按钮位置。

此时运行游戏,我们发现一个待完善的地方,就是按钮它可以移动到摇杆背景外:

为解决这个问题我们在update方法中添加如下代码:

update (dt) {// get ratiolet len = this.joyStickBtn.position.mag();let maxLen = this.node.width / 2;let ratio = len / maxLen;// restrict joyStickBtn inside the joyStickPanelif (ratio > 1) {this.joyStickBtn.setPosition(this.joyStickBtn.position.div(ratio));}
},

为方便理解以上代码,请看下面这张图:

首先获取摇杆按钮当前所在位置坐标(x1, y1),因为这是一个向量,所以我们可以调用mag()求出该向量的长度len。也就是按钮中心到原点(摇杆背景中心)的直线长度。如果该直线长度大于摇杆背景的半径maxLen(按钮在背景外),那我们就获取超出的比例值ratio,然后让按钮当前的坐标除以它,即x1/ratio和y1/ratio,这样我们其实就得到了按钮在摇杆背景边界上时的x和y坐标。

现在运行游戏你会发现摇杆按钮被限制在了背景中:

用摇杆控制主角

这里的主角我们直接用粒子来代替。在层级管理器中创建一个粒子节点并重命名为player:

接着我们在properties中添加两个属性,一个是用于挂载节点,另一个用于设置主角最大移动速度:

properties: {player: {default: null,type: cc.Node},maxSpeed: 0,
},

将player节点拖入,并设置maxSpeed属性值为10:

现在来解决主角的移动问题。首先是移动方向,我们在onLoad方法中新建一个dir变量用于存储主角移动方向:

onLoad () {...// Player's move directionthis.dir = cc.v2(0, 0);...
},

读者如果玩过带摇杆功能的游戏的话,应该都知道摇杆按钮的移动方向就是主角的移动方向。而我们在onTouchMove方法中是知道主角移动后的坐标(向量)的,所以获取方向非常简单:

onTouchMove(event) {// constantly change joyStickBtn's positionlet posDelta = event.getDelta();this.joyStickBtn.setPosition(this.joyStickBtn.position.add(posDelta));// get directionthis.dir = this.joyStickBtn.position.normalize();
},

我们这里调用了normalize()让向量归一化(方向不变但长度为1)。

接着在update方法中设置玩家位置:

update (dt) {...// move Playerlet dis = this.dir.mul(this.maxSpeed * ratio);this.player.setPosition(this.player.position.add(dis));
},

this.maxSpeed *ratio表示主角移动的速度会根据摇杆按钮所移动的距离来变换。如果摇杆按钮只移动一点,那么主角移动速度就慢;如果摇杆按钮处于摇杆背景的边界处,那么移动速度就达到最大值。

然后我们再将得到的值与this.dir这个方向向量相乘,这样就可以得到朝特定方向的位移大小,最后加上主角当前位置即可。

当然我们还得限制主角移动范围,不能移动到屏幕外边:

update (dt) {...// move Playerlet dis = this.dir.mul(this.maxSpeed * ratio);this.player.setPosition(this.player.position.add(dis));// restrict Player inside the Canvasif (this.player.x > this.player.parent.width / 2)this.player.x = this.player.parent.width / 2;else if (this.player.x < -this.player.parent.width / 2)this.player.x = -this.player.parent.width /2;if (this.player.y > this.player.parent.height / 2)this.player.y = this.player.parent.height / 2;else if (this.player.y < -this.player.parent.height / 2)this.player.y = -this.player.parent.height / 2;
},

这里的this.player.parent就是Canvas节点。

运行截图如下:

好,那到这里虚拟摇杆的功能就全部都实现了,希望大家有所收获!

欢迎关注我的微信公众号,发现更多有趣内容:

《Cocos Creator游戏实战》虚拟摇杆实现相关推荐

  1. 《Cocos Creator游戏实战》贪吃蛇平滑移动

    贪吃蛇平滑移动 贪吃蛇平滑移动 初始化蛇头和蛇身 调整蛇头方向 贪吃蛇移动 蛇头和蛇身的节点顺序 添加食物 添加碰撞逻辑代码 从pointsArray中剔除无用的坐标点(更新) 在本教程中我们重点来学 ...

  2. 《Cocos Creator游戏实战》棋类游戏中的棋子摆放逻辑

    棋类游戏中的棋子摆放逻辑 创建节点 代码编写 其实要点就一句话:我们看到的不应是棋盘,而是坐标. 现在通过下面的五子棋(或围棋)实例来看下如何理解这句话. 运行效果如下: Cocos Creator版 ...

  3. 《Cocos Creator游戏实战》游戏转场时如何保留节点信息

    游戏转场时如何保留节点信息 使用常驻节点 使用全局变量 使用本地存储 引擎同时只会运行一个场景,当切换场景时,默认会将场景内所有节点和其他实例销毁(本句来自Cocos Creator文档). 在这一节 ...

  4. 《Cocos Creator游戏实战》摘星星进阶版

    摘星星进阶版 添加开始按钮 实现按钮功能 显示"Game Over" 限制主角移动范围 让跳跃动作更加细腻 加入星星收集动画 编写动画脚本 加入触屏控制 添加游戏提示 Cocos ...

  5. 《Cocos Creator游戏实战》新手引导实现

    新手引导实现 新建节点 完成代码 该功能已收录在Many Widgets插件中,使用Cocos Creator 3.x版本的小伙伴可以用该插件快速生成新手引导. 插件地址:https://store. ...

  6. 《Cocos Creator游戏实战》关卡功能实现

    关卡功能实现 创建节点 设置关卡信息 实现关卡界面 为预制添加脚本 完善Game.js逻辑 在上一节教程中我们讲解了打砖块的主要功能与逻辑实现,在这一篇教程中,笔者会在它的基础上增加关卡功能(建议先阅 ...

  7. 《Cocos Creator游戏实战》老虎机抽奖效果实现思路

    在线体验地址 Cocos Creator | SlotMachine Cocos Store 购买地址(如果没有显示,那就是还在审核): https://store.cocos.com/app/det ...

  8. cocoscreator editbox 只允许数字_《Cocos Creator游戏实战》做一个数字调节框

    当玩家购买道具的时候,一个个买可能会比较麻烦,用数字调节框的话玩家一次性就可以买好几十个了(钱够的话). 运行效果如下: Cocos Creator版本:2.2.0 公号"All Codes ...

  9. 《Cocos Creator游戏实战》你画我猜中的画板功能

    你画我猜中的画板功能 创建节点 完成脚本 本节我们来做一个画板,该画板一共有三个小功能: 调节笔刷大小 改变笔刷颜色 橡皮擦 运行效果如下: Cocos Creator版本:2.2.0 后台回复&qu ...

最新文章

  1. 【前端2】js:原始类型,运算符,调试,页面加载,轮播图,Bom(对象,时钟),Dom(全选全不选,省市级联,隔行/触摸换色,表单校验)
  2. 【F3简介】一张图看懂FPGA-F3实例
  3. 目前最厉害的象棋软件_qq什么引流方式最厉害,QQ引流目前最有效的方法
  4. ros安装过后怎么找不到安装文件_ros配置乐视奥比中光相机
  5. 275. H-Index II 递增排序后的论文引用量
  6. 【玩转Golang】 自定义json序列化对象时,非法字符错误原因
  7. C#异步方法调用(四大方法详解)
  8. 网络流(最大流) CQOI 2015 BZOJ 3931 网络吞吐量
  9. SQL进阶教程(一)——CASE表达式
  10. (首个填坑)联想拯救者Y7000(自带win10 home) 安装Ubuntu16.04.6 + NVIDIA GTX1650驱动
  11. 计算机网络原理 谢希仁(第8版)第二章习题答案
  12. Python — — turtle 常用代码
  13. ubuntu linux 郑码,如何输入间隔号 - dengyz的个人页面 - OSCHINA - 中文开源技术交流社区...
  14. 在北京租房 舒舍的租客素质怎么样?
  15. 程序员的奋斗史(七)——沟通交流、表达能力的重要性
  16. 5.2.1_3 普通心理学(彭冉玲第四版) - 第2章 心理的神经生理机制
  17. HBuilder打开发生了错误。请参阅日志文件
  18. 浅谈一下汽车行业中的OTA/FOTA/SOTA
  19. 爸爸给4岁女儿的遗书 10年后女儿回了信(感人)
  20. 基于微信小程序的校园跑腿系统

热门文章

  1. 行人检测——Caltech Pedestrian Dataset 数据集的使用
  2. 4.设备像素、css像素、设备独立像素、dpr、ppi 之间的区别?
  3. .NET Framework和.NET Core/.NET5/.NET6
  4. Git与Git可视化工具TortoiseGit-小乌龟安装和配置
  5. PRE_LOAD+putenv
  6. HTML5期末大作业:生鲜超市网站设计——生鲜超市网站设计(5页)HTML+CSS+JavaScript 学生DW网页设计作业成品 美食站
  7. 计算机应用基础18在线作业容,东师《计算机应用基础》18秋在线作业2.doc
  8. Cesium 卫星轨迹、卫星通信、卫星过境,模拟数据传输。
  9. 笨方法学Python 练习16
  10. 本固枝荣 —— Java关键字之分类